Search code examples
androidbroadcastreceiverbatterylevel

Android: Start Service at certain Battery Level


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


Solution

  • 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.