8

I'm using the code from the below example page in my app to monitor when the device is connected / disconnected to a power adapter:

http://developer.android.com/training/monitoring-device-state/battery-monitoring.html

So I have in my manifest:

    <receiver android:name=".StatusChangeReceiver">
        <intent-filter>
            <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
            <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
        </intent-filter>
    </receiver>

And my class looks like this:

public class StatusChangeReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
    boolean isActive = prefs.getBoolean("isActive", false);
    if (isActive){
        int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
        boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || status == BatteryManager.BATTERY_STATUS_FULL;
        // Do somthing with isCharging here
    }

}

But isCharging is always false, regardless of whether the power was connected or disconnected. I'm obviously having problems debugging this as I have to keep (dis)connecting the USB cable to get the event to fire.

I presume when the power is connected the event is fired and the status isn't updated before my code runs, but I'm not sure of the best way to resolve it. Any ideas?

user1341608
  • 91
  • 1
  • 2
  • 3
  • 1
    OK so using the emulator and telnetting in to turn the power on/off I note that I always get status = -1, therefore it looks like the data isn't getting passed into the intent. No idea why. – user1341608 Apr 18 '12 at 15:18

5 Answers5

11

As suggested by @gnichola, referencing this post is the correct answer:

public class PowerReceiver extends BroadcastReceiver {

    @Override public void onReceive(Context context, Intent intent) {
        if(intent.getAction() == Intent.ACTION_POWER_CONNECTED) {
            //Handle power connected
        } else if(intent.getAction() == Intent.ACTION_POWER_DISCONNECTED){
            //Handle power disconnected
        }
    }
}

Below is an alternate (albeit incorrect) approach:

I had the same problem as noted by others. My solution is to call the ACTION_BATTERY_CHANGED blocking intent within the ACTION_POWER_CONNECTED and ACTION_POWER_DISCONNECTED Broadcast Receivers:

In onCreate() or some other appropriate initializer:

// register our power status receivers
IntentFilter powerConnectedFilter = new IntentFilter(Intent.ACTION_POWER_CONNECTED);
registerReceiver(PowerStatusReceiver, powerConnectedFilter);

IntentFilter powerDisconnectedFilter = new IntentFilter(Intent.ACTION_POWER_DISCONNECTED);
registerReceiver(PowerStatusReceiver, powerDisconnectedFilter);

Define our BroadcastReceiver and embed the BATTERY_STATUS request within it:

BroadcastReceiver PowerStatusReceiver = new BroadcastReceiver() {
    public void onReceive(Context context, Intent intent) {
        IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
        Intent batteryStatus = context.registerReceiver(null, ifilter);

        // Are we charging / charged?
        int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
        isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
                     status == BatteryManager.BATTERY_STATUS_FULL;
    }
};  

Additionally, using this approach you do not have to define a receiver in your manifest... however that is ultimately entirely up to you depending on the needs of your use case.

ShellDude
  • 579
  • 6
  • 12
  • I found the answer [here](https://stackoverflow.com/a/20392715/1337916) was the correct one, it seems the intent doesn't carry with it the information the documentation suggests it does. Just switching on the intent's action worked for me. – gnichola Jul 01 '17 at 20:32
  • I agree with the method suggested in your link. I'll update my answer to reference it. – ShellDude Dec 16 '19 at 01:27
  • Not sure why you include the incorrect approach here. I was doing it same as you and it seems the ACTION_BATTERY_CHANGED intent is occasionally not yet updated when CONNECTED/DISCONNECTED broadcasts are sent. – kodu Apr 08 '21 at 10:55
1

You can also check it by BatteryManager.EXTRA_PLUGGED

public boolean isChargingmy(Context context)
    {
        IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
        Intent batteryStatus = context.getApplicationContext().registerReceiver(null, ifilter);
        boolean bCharging=false;
        if(batteryStatus != null){

            int plugged = batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
            Log.e("plugged","plugged:"+plugged);
            bCharging= plugged == BatteryManager.BATTERY_PLUGGED_AC || plugged == BatteryManager.BATTERY_PLUGGED_USB;
            Log.e("bCharging","bCharging:"+bCharging);
        }
        else{
            Log.e("batteryStatus","batteryStatus:"+null);
        }

        return bCharging;
    }

I have register the receiver inside the BroadcastReceiver so i have used context.getApplicationContext().registerReceiver() . You have to use context.registerReceiver() only if you are not register it on BroadcastReceiver

Asha
  • 750
  • 1
  • 6
  • 22
1

I have the same problem, but looking at what the intent action was using intent.getAction(), the broadcast receive the expected information:

I/POWER: android.intent.action.ACTION_POWER_DISCONNECTED   
I/POWER: android.intent.action.ACTION_POWER_CONNECTED

So in my case it is all I need in my code since I know when the cable is connected/disconnected. Remember that using this means you just received only these events and not other one related to battery as if using ACTION_BATTERY_CHANGED.

rollstuhlfahrer
  • 3,988
  • 9
  • 25
  • 38
0

Also explained here: battery status on ACTION_POWER_CONNECTED

I had the same problem and was calling or checking the battery status too quick. ACTION_POWER_CONNECTED is invoked before ACTION_BATTERY_CHANGED gets updated, so perhaps use AlarmManager to schedule yourself to wake up again in a few seconds, and check again then. Two seconds, isn't long enough in my tests fyi...

Community
  • 1
  • 1
gauglerb
  • 258
  • 1
  • 12
0

Need to use API 26 registerReceiver documentation

onCreate

private val myBroadcastReceiver = MyBroadcastReceiver()

registerReceiver(
    myBroadcastReceiver,
    IntentFilter().apply {
        addAction(Intent.ACTION_POWER_CONNECTED)
        addAction(Intent.ACTION_POWER_DISCONNECTED)
    }
)

onDestroy

unregisterReceiver(myBroadcastReceiver)
Arman
  • 25
  • 7