2

Like many others, I am trying to create a simple app that logs an entry every time the phone is connected or disconnected from the charger. I plan to use this data to calculate average charge and discharge rate over several weeks/months to get an idea of how well the battery is performing over time.

I have got Intent filters declared in the manifest for ACTION_POWER_CONNECTED and ACTION_POWER_DISCONNECTED, and they seem to be firing fine.

Now when they are fired, I am registering to receive ACTION_BATTERY_CHANGED to get the battery EXTRA_LEVEL, EXTRA_STATUS and EXTRA_PLUGGED. (Reference - Obtaining usb cable plugged IN/OUT event using EXTRA_PLUGGED does not work)

public class PowerConnectionReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intentPowerConn) {
        Intent intentBatChange = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
        int chargeStatus    = intentBatChange.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
        int chargeType      = intentBatChange.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
        int chargeLevel     = intentBatChange.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);

        Toast.makeText(context, chargeStatus + " " + chargeType + " " + chargeLevel, Toast.LENGTH_SHORT).show();
    }
}

However, the EXTRA_STATUS that is returned by this sticky broadcast still shows as Discharging when fired immediately after the phone is connected. Other extras like EXTRA_PLUGGED and EXTRA_LEVEL return correct values though.

A manual refresh to get the ACTION_BATTERY_CHANGED action after connecting returns the STATUS as Charging just fine.

It can't be that the intent received immediately after connecting is stale, since the EXTRA_PLUGGED returns the correct type (AC or USB).

I have a workaround where I use the ACTION_POWER_CONNECTED/ACTION_POWER_DISCONNECTED intent action to determine the charge state (as described here - How to detect power connected state?).

public class PowerConnectionReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context , Intent intentPowerConn) {
        Intent intentBatChange = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
        int chargeStatus    = intentBatChange.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
        int chargeType      = intentBatChange.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
        int chargeLevel     = intentBatChange.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);

        String action = intentPowerConn.getAction();
        boolean chargeFlag = false;

        if(action.equals(Intent.ACTION_POWER_CONNECTED)) {
            chargeFlag = true;
        }
        else if(action.equals(Intent.ACTION_POWER_DISCONNECTED)) {
            chargeFlag = false;
        }

        Toast.makeText(context, chargeStatus + " " + chargeType + " " + chargeLevel + " " + chargeFlag, Toast.LENGTH_SHORT).show();
    }
}

I might need to make use of STATUS for other scenarios like BATTERY_STATUS_FULL, BATTERY_STATUS_NOT_CHARGING and BATTERY_STATUS_UNKNOWN.

So I don't want to rely on the Intent.ACTION_POWER_CONNECTED action.

Given this, what is a reliable way to detect the current charge state?

I was considering adding a 2 sec delay before I register the ACTION_BATTERY_CHANGED intent; though I haven't tested this out yet, I figure it might work.

Community
  • 1
  • 1

0 Answers0