0

I'm currently working on an application that needs to change certain settings on the phone such as volume when a certain event is triggered, such as a time event (between 9am and 5pm) or a battery event (battery below 30%).

The first way I thought to do this was to set up a background service which checks system time and battery level (for example) every so many seconds or minutes, then changes the phones settings when the appropriate time or battery level is met. I'm not entirely certain how to do this and I have seen some other methods which seem possible.

What would be the best method to use to perform these background checks and change settings based on the findings without requiring interaction from the user?

Thanks in advance.

[EDIT]

After being told by Jakar and gobernador to use AlarmManager, BroadcastReceiver and IntentService I came across this answer:

android: running a background task using AlarmManager

Which explained with examples how to accomplish this, thanks for the helps guys!

[EDIT]

I managed to set it up and get the service working, it doesn't do anything yet but the rest should be easy. I did it with the following components:

  • Boot BroadcastReceiver which sets a repeating alarm to run my alarm BroadcastReceiver. This will start the service after the phone is rebooted.
  • Similar code in my main application activity that cancels any other pending intents to start the service. This starts the service when the application is run, good for starting after installation.
  • Alarm BroadcastReceiver class which has code to startService().
  • Finally my IntentService class which has the stuff I want to do in the onHandleIntent() method. (I also want to add I had a problem with this class, it was because the constructor wasn't allowed any parameters).

Thanks again.

Community
  • 1
  • 1
William Stewart
  • 841
  • 1
  • 14
  • 27
  • You should use a combination of `AlarmManager`, and `BroadcastReceiver` to check for things that it's able to, and a `Service` to check anything that the `BroadcastReceiver` can't handle. If you must use a `Service`, you may need to use a `WakeLock` in order to keep the service running, but this will use extra battery. – Reed Mar 07 '12 at 17:40
  • Will I also be able to perform actions based on these checks using AlarmManager and BroadcastReceiver? For example If I'm checking to see if the battery level is lower than 30%, I will then need to perform a series of actions such as lower the screen brightness, turn off bluetooth and wifi, etc. – William Stewart Mar 07 '12 at 17:43
  • I've seen others suggest any `BroadcastReceiver` should be able to execute all it's code within about 50ms (you can test this by logging at beginning and at end of code, then watch the logcat). Getting battery level in `BroadcastReceiver` may not be possible, because you first have to register a receiver (I believe there is no direct API to get battery level). But, if there is a direct API to get/set something (such as wifi on or off), then you can likely execute that in broadcast receiver. If your code will take more than 50 ms to run, then you will likely want to start a service. – Reed Mar 07 '12 at 18:04
  • Right okay, the problem is that the user will determine how many events to check for and how many settings to change, therefore the time isn't necessarily going to be the same. Would you recommend using a Service in this case? Yes the method I used previously to get battery level was by registering a receiver. Would that be possible to do within a service? – William Stewart Mar 07 '12 at 18:08

2 Answers2

1

It would be difficult to do this with a Service. What you want is a BroadcastReciever. The way that the Android OS works is when certain events occur (such as ACTION_BOOT_COMPLETED OR ACTION_POWER_CONNECTED, see the section on Standard Broadcast Actions in the Intent documentation), Android broadcasts an Intent telling all applications that this event has occurred. What you need to do is set up a BroadcastReciever to catch the broadcasts that you want.

public class MyReciever extends BroadcastReciever {
    @Overwrite
    public void onRecieve(Context context, Intent intent) {
        //parse intent
        //carry out actions
    }
}

Note that the only method you need to overwrite is onRecieve(). Also, it seems like you will be looking for multiple different broadcasts. If this is the case, you can choose to create multiple extensions of BroadcastReciever: e.g. BatteryLowReciever, AtWorkTimeReciever, etc. You could also choose to simply have one and parse multiple intents...

private final String[] broadcasts = {android.intent.action.BATTERY_LOW, ...};
int i = 0;
for(i ; i < broadcasts.length, i++) {
    if (intent.getAction().equals(broadcasts[i]))
        break;
}
switch (i) {
    case 1:
        //perform battery low actions
        break;
    case 2:
        //different actions

    //More cases and actions
}

EDIT: Based on what you've told me, here's a list of things to look into:

gobernador
  • 5,659
  • 3
  • 32
  • 51
  • "a Service first requires an activity" - This is incorrect. You can start a service from a `BroadcastReceiver` if you do `intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);` You can also start a `Service` using `AlarmManager` with `getService` – Reed Mar 07 '12 at 18:00
  • Thanks for the info. I haven't had much experience using this other than to get the current battery level, however that was called within a WallpaperService class to print the level onto a live wallpaper. How exactly is this BroadcastReceiver class run? The way my app works is that the user launches the activity to add profiles, including events they want to check for (such as POWER_CONNECTED) and the settings they want to change based on the event. They can then enable or disable each profile. How and when will the BroadcastReceiver be called to begin running in background? – William Stewart Mar 07 '12 at 18:00
  • @Jakar, Yes, you're right, that's my mistake, a `Service` can be called from pretty much anywhere using `Intent.startService(Intent)`. – gobernador Mar 07 '12 at 19:37
  • 1
    @William, the way you describe it to me is that you want an `Activity` to build a profile and the events that trigger it, and then you want a `Service` whose *sole purpose* is to receive a profile and enact it.... (continued) You can use `BroadcastReciever` and `AlarmManager` (each has its own capabilities) to trigger the `Service`. By the way, I suggest using an `IntentService` and creating your own `Intent`s to send to it. `IntentService` is a streamlined subclass of `Service` that seems like exactly what you would need. – gobernador Mar 07 '12 at 19:44
  • See the [IntentService documentation](http://developer.android.com/reference/android/app/IntentService.html). It's a surprisingly useful tool. In any case, you will need plenty of experience with `Intent`s – gobernador Mar 07 '12 at 19:45
  • Yes that is correct, the application is essentially two parts, one being the activities which allow the user to add, edit and delete the profiles. The second part being a `Service` (seems to be what I need to use) which runs checks in background to see if the events the user specified in their enabled profile have been triggered, and then to change the phones settings based on the outcome of the checks. The activity to add, edit and delete is already done, all I need to do now is implement the background `Service`, I'll definitely check out `IntentService`. – William Stewart Mar 07 '12 at 21:12
  • Do you know roughly what the new classes I will need to implement are, It would be a great help If I had a simple breakdown of what I need, then I'm sure I'd be able to figure out the rest using the docs. – William Stewart Mar 07 '12 at 21:13
  • Thanks, I have seen some similar things to this where the service runs once, at the end it sets another alarm, so it effectively keeps running forever. Is this the best thing to do in this case? Also where exactly do I set-up the `AlarmManager` and `BroadcastReceiver`? – William Stewart Mar 08 '12 at 12:47
1

You can check battery level in a service. I guess I would recommend enabling everything (except the battery), then see how long it takes to check/set all of what your app is suppose to. If it is under 50ms, then use a BroadcastReceiver in any case where battery level is not a concern (for example, time triggers).

Then if user enables battery level check, then always use the service.

If running all the checking/setting system settings takes over 50ms, then always use a Service.

I would recommend registering a BroadcastReceiver with the BOOT_COMPLETED action, so your app will be able to run after a reboot. Also, I do not recommend running a service constantly. I would recommend using AlarmManager to run the service every 10 minutes or so. Reason being, if your service takes 15 seconds to do what it needs, then it will waste battery for it to keep running all the time.

Also, if you are going to use a mix of Service/BroadcastReceiver, I would recommend creating a class (call it M for methods). Then in M you will have a method (say doSomething()) to do whatever you need. Then in the Service or Receiver, you would just need to call M.doSomething() so you don't have to change the code twice for every one time you change it.

Let me know if I was unclear/confusing or I need to add anything, and I'll do my best to elaborate.

EDIT:
You would need to use AlarmManager to set the alarms, Calendar to get and set specific times/dates. https://stackoverflow.com/a/7342724/802469 will help you with this process. To keep the device's CPU awake and keep it from stopping your service, you would need to use PowerManager. For other things that you haven't specified, you should be able to find by Googling or by looking in the docs. WifiManager for changing wifi setting.

Community
  • 1
  • 1
Reed
  • 14,703
  • 8
  • 66
  • 110
  • At the moment the only checks that can be made are time and battery level, this is because I'm only creating a prototype as part of my dissertation for my degree. I do however plan on releasing this app at some point and I expect to add more events for the user to choose from, therefore I would rather write the app so that its future proof. By that I mean I don't want to use BroadcastReceiver now where it wont take long to do the maximum 2 checks, if in the future I will have to rewrite the code completely to cater for more time consuming checks. – William Stewart Mar 07 '12 at 18:30
  • Apologies for the double post, I didn't have enough room in the a single comment. Also if the checks are scheduled every 10 minutes, this means that if a time event needs to check if the system time is between 9am and 5pm (work), there is a potential 10 minute delay before the check is performed and the changes are made. I suppose I could just make it check for whatever time they enter minus 10 minutes, either way it seems quite inaccurate. – William Stewart Mar 07 '12 at 18:32
  • 1
    Well - the 10 minutes would be more for like... checking battery (or location or something else if you ever add that) Being 1% or 2% late on the battery level wouldn't be a big deal. There would be no reason to do a "time check" because you can use `AlarmManager` to make the code launch at a specified time anyway. http://stackoverflow.com/a/7342724/802469 is an answer I gave about setting an alarm, which may help with the time triggers – Reed Mar 07 '12 at 19:08
  • And for the time triggers - say you'd be turning a user specified "profile" on at 9:00 am, then you'd set another alarm for 5:00pm (or whenever) to turn the normal "profile" back on. – Reed Mar 07 '12 at 19:10
  • Okay that makes sense, the only problem with using `AlarmManager` for time is that if the user first creates the profile whilst already in the time-frame (eg. they create their 9 - 5 profile at 1pm), then it won't become enabled until the next day. I suppose I could have a check for time when the profile is first enabled aswell. Do you know roughly what the new classes I will need to implement are, as I said to gobernador It would be a great help If I had a simple breakdown of what I need, then I'm sure I'd be able to figure out the rest using the docs. – William Stewart Mar 07 '12 at 21:17