2

I want to start an IntentService if the battery level reaches a certain value while charging.

However, I dont want to register a BroadcastReceiver for android.intent.action.BATTERY_CHANGED in the AndroidManifest.xml because i need the service only started at a certain level (e.g. 40%) and only while charging.

Another idea would be starting a service that runs as long as the phone is charged and register a receiver programmatically. A third idea would be to periodically start a service with AlarmManager and check battery level.

What is the best way?

Solution:
I have implemented the fourth idea from answer below.

final int PI_REQUEST_CODE = 123456;
int pref_BatteryUpdatePeriod = 120000;  // 2 minutes

// set repeating alarm manager
Intent monitorIntent = new Intent(this, CheckBatteryReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this.getApplicationContext(), PI_REQUEST_CODE, monitorIntent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, Calendar.getInstance().get(Calendar.MILLISECOND), pref_BatteryUpdatePeriod, pendingIntent);

and the broadcast receiver for the alarm:

public class CheckBatteryReceiver extends BroadcastReceiver {

private int targetBatterylevel = 40;

@Override
public void onReceive(Context context, Intent intent) {

    // get sticky intent
    Intent batteryStatusIntent = context.getApplicationContext()
            .registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
    int batteryLevel = batteryStatusIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, 50);

    // evaluate battery level
    if(batteryLevel >= targetBatterylevel){
        // start service to stop charging
    } else {
        // continue charging
    }       
}
}

Note: I had to use context.getApplicationContext() instead of context otherwise the app would crash with an exception that I can't register a receiver within a broadcastreceiver

emareg
  • 23
  • 5

3 Answers3

2

I dont want to register a BroadcastReceiver for android.intent.action.BATTERY_CHANGED in the AndroidManifest.xml because i need the service only started at a certain level (e.g. 40%) and only while charging.

That does not work anyway, as you cannot register for that broadcast in the manifest.

Another idea would be starting a service that runs as long as the phone is charged and register a receiver programmatically.

Yuck.

A third idea would be to periodically start a service with AlarmManager and check battery level.

A fourth idea is to use AlarmManager, as you suggest, but bypass the service at the outset. Just have AlarmManager invoke a BroadcastReceiver. It can check the battery level by calling context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)) (on the context passed into onReceive()). The Intent returned by registerReceiver() will be the last broadcast of ACTION_BATTERY_CHANGED. If the battery level is at or below your desired threshold, then start your IntentService. You may need to adopt the WakefulBroadcastReceiver or WakefulIntentService pattern if your alarm will wake up the device. Also allow the user to choose the polling period, so they can trade off precision for better device performance.

I would go with the fourth idea.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
0

It doesn't sound too bad to have a service running, reacting to android.intent.action.BATTERY_CHANGED as long as it doesn't do anything when you don't need it to. That is, have a check for the interesting battery level and charging state early and just exit if you have nothing to do.

If you want to complicate things, register a mini service which only has the task of starting your main service when conditions are right. However, I don't see what benefit that would have.

Mattias Backman
  • 927
  • 12
  • 25
  • Yeah, good idea too but I think alarm based checking is the better way ;) Additionally I can't be sure that the service wont be killed... – emareg Jun 18 '14 at 13:39
0
public class Main extends Activity {
  private TextView batteryTxt;
  private BroadcastReceiver mBatInfoReceiver = new BroadcastReceiver(){
    @Override
    public void onReceive(Context ctxt, Intent intent) {
      int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
      batteryTxt.setText(String.valueOf(level) + "%");


    }
  };

  @Override
  public void onCreate(Bundle b) {
    super.onCreate(b);
    setContentView(R.layout.main);
    contentTxt = (TextView) this.findViewById(R.id.batteryTxt);
    this.registerReceiver(this.mBatInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
  }
}
Jogendra Gouda
  • 405
  • 4
  • 17