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.