I have written an application, and I want to know how much of the battery it consumes.
I'm testing it on smartphone (ACER Liquid Mt), but I can only read the battery level with an accuracy of 1% via the battery manager.
It will take a lot of runs to make the percentage decrease with 1%. So my question is this: Is it possible to get a more accurate battery level and is the battery level trustable?
I read some things that the battery level in software wouldn't be very accurate.
It will take a lot of runs to make the percentage decrease with 1% doesn't mean it is inaccurate, It could be that the battery is very durable. And because it is in percentage, 1 percent of battery power could be a lot of energy.
For getting battery level, I use a BroadcastReceiver, you may try it and see if it is accurate enough:
class BatteryLifeBroadcastReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
int level = intent.getIntExtra("level", 0);
int scale = intent.getIntExtra("scale", 100);
int batteryLevel = (float) level / scale;
// use batteryLevel...
}
}
}
// register the receiver in Activity.onResume()
registerReceiver(mBatteryLifeBroadcastReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
// unregister it in Activity.onPause()
unregisterReceiver(mBatteryLifeBroadcastReceiver);
Related
I'm writing an Android app using old Android phones dedicated to temperature monitoring. Now I'm having problem with an HTC Hero running Android 2.1 update-1. It doesn't receive updates of the battery temperature sensor. It only gets an initial value. It does however receive updates of external power plugged in status. If the external power source is changed a new temperature is received.
Is this behaviour set by the hardware or is it anything I can do about it?
I'm using a BroadcastReceiver:
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
registerReceiver(batteryReceiver, filter);
BroadcastReceiver batteryReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d(LOG_TAG, "onReceive, action = " + intent.getAction());
float temperature = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 999) / 10f;
boolean externalPower = (intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0);
// ...
}
};
This works fine on a Galaxy S4 / Android 4.3.
Like I said, if the external power source is changed (charger is plugged in or unplugged) the receiver is always called, and a new temperature is received.
Re-regestering the receiver doesn't help.
I've tried manually getting the Intent like this in intervals, but the temperature is constant (even if it definitely changed).
handleBatteryIntent(registerReceiver(null, filter));
Seems the temperature is only updated when the external power source status (EXTRA_PLUGGED) has changed.
I've tried two other battery apps, and they have the same problem.
Is it possible to get the battery level of connected smartwatches as part of the Wear API? (Preferably without having to deploy an actual wear-component onto the smartwatch and then communicating back-and-forth between the watch and the device). I've seen some wear-apps that show the battery level of the watch on the watch itself, but I'd simply like to find out the current battery level of the watch using the phone.
You're more than likely going to need a wear app, but it should be very easy.
On the wearable, make a WearableListenerService. Have the phone app send a message (using the Message APi). This will start the WearableListenerService on the watch. Have the watch get it's battery information and send it back to the phone using another message.
Start by determining the current charge status. The BatteryManager broadcasts all battery and charging details in a sticky Intent that includes the charging status.
IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent batteryStatus = context.registerReceiver(null, ifilter);
You can extract the current charging status this way
// Are we charging / charged?
int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
status == BatteryManager.BATTERY_STATUS_FULL;
you can use this one
public static final String EXTRA_LEVEL
Added in API level 5
Extra for ACTION_BATTERY_CHANGED: integer field containing the current battery level, from 0 to EXTRA_SCALE.
Constant Value: "level"
You can find the current battery charge by extracting the current
battery level and scale from the battery status intent as shown here:
int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
float batteryPct = level / (float)scale; // your %
so batteryPct is your Battery % Percentage
//you can show your Percentage then
For more info about BatteryManager from here
My goal is : when I call some function, I want to get the exact current battery status(level,voltage and etc..).
First I tried to do it in my application as shown on the website. Then I have found actually the ACTION_BATTERY_CHANGED broadcast is sticky which means what I got is from last broadcast, not the exact current value.
Actually, I have looked into the android source code. For the battery interface, the driver has functions to read the registers inside the battery which contain the current soc(state of charge), voltage and etc..
So I am just wondering how and when the system sends the sticky broadcast ACTION_BATTERY_CHANGED? Does it send it periodically(e.g.,every 10 seconds it will read the registers in battery and send the broadcast)? Or does it send based on other criteria(e.g, change of soc, voltage? But voltage will change so frequently in terms of mV)?
To realize my goal, one troublesome way is to implement a system call to call the driver functions and then recompile the NDK to make it usable in my application code. But I just want to know whether I can do this directly through the ACTION_BATTERY_CHANGED broadcast considering what I have mentioned above? Does registering the broadcast again have any effect?
Simply register the Broadcast receiver for the battery level. You will get the result of battery level in onReceive.
private void batteryLevel() {
BroadcastReceiver batteryLevelReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
context.unregisterReceiver(this);
int rawlevel = intent.getIntExtra("level", -1);
int scale = intent.getIntExtra("scale", -1);
int level = -1;
if (rawlevel >= 0 && scale > 0) {
level = (rawlevel * 100) / scale;
}
batterLevel.setText("Battery Level Remaining: " + level + "%");
}
};
IntentFilter batteryLevelFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
registerReceiver(batteryLevelReceiver, batteryLevelFilter);
}
Hope this will help you.
To elaborate on the answer from Arpit, ACTION_BATTERY_CHANGED is a "sticky" event - which means it doesn't need a receiver to be able to read its values. That way you may call registerReceiver() with receiver equal to null, and read all the battery stats synchronously right away, and there's no need to unregister.
Here's the code:
private void batteryLevel() {
IntentFilter batteryLevelFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent intent = registerReceiver(null, batteryLevelFilter);
if (intent != null) {
int rawlevel = intent.getIntExtra("level", -1);
int scale = intent.getIntExtra("scale", -1);
int level = -1;
if (rawlevel >= 0 && scale > 0) {
level = (rawlevel * 100) / scale;
}
batteryLevel.setText("Battery Level Remaining: " + level + "%");
}
}
Also, in some rare cases, registerReceiver() may throw an IllegalArgumentException: regist too many Broadcast Receivers exception, so you may want to catch it to avoid crashing.
In response to the of the question:
Does it send it periodically(e.g.,every 10 seconds it will read the
registers in battery and send the broadcast)? Or does it send based on
other criteria(e.g, change of soc, voltage? But voltage will change so
frequently in terms of mV)?
There is no single correct answer, Android makes no guarantees and it varies by device.
Based on my experience working with different board bring-ups it is highly dependant on the linux kernel drivers managing power. I've seen it firing uevents off once per second or once every 30 seconds. Even the same device will fire it differently based on whether it is attached to a power source or not. I tend to see that usually there is some fixed timer that triggers it and additionally major events such as attaching/detaching a charger will trigger it as well.
Also see: ACTION_BATTERY_CHANGED firing like crazy
In my application, I want to do something when the battery is low. When battery is low android fires ACTION_BATTERY_LOW and when the battery again reaches to its good health it fires intent ACTION_BATTERY_OKAY. So, I have three questions regarding this:
1.At what battery percentage android actually fires ACTION_BATTERY_LOW?
2.Does it fire that same event repeatedly if the battery gets even lower?
3.Can we configure the battery percentage at which android will fire ACTION_BATTERY_LOW intent?
I am more concerned about the third point.
No, you cannot set when the ACTION_BATTERY_LOW threshold will be sent. That is a system level intent that is specified by the Android ROM. Here is the code where it sets the value in the Battery Service:
mLowBatteryWarningLevel = mContext.getResources().getInteger(
com.android.internal.R.integer.config_lowBatteryWarningLevel);
See the code below which is cut from the Android system code in the update method of the Battery Service:
/* The ACTION_BATTERY_LOW broadcast is sent in these situations:
* - is just un-plugged (previously was plugged) and battery level is
* less than or equal to WARNING, or
* - is not plugged and battery level falls to WARNING boundary
* (becomes <= mLowBatteryWarningLevel).
*/
final boolean sendBatteryLow = !plugged
&& mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
&& mBatteryLevel <= mLowBatteryWarningLevel
&& (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel);
sendIntent();
// Separate broadcast is sent for power connected / not connected
// since the standard intent will not wake any applications and some
// applications may want to have smart behavior based on this.
Intent statusIntent = new Intent();
statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
if (mPlugType != 0 && mLastPlugType == 0) {
statusIntent.setAction(Intent.ACTION_POWER_CONNECTED);
mContext.sendBroadcast(statusIntent);
}
else if (mPlugType == 0 && mLastPlugType != 0) {
statusIntent.setAction(Intent.ACTION_POWER_DISCONNECTED);
mContext.sendBroadcast(statusIntent);
}
if (sendBatteryLow) {
mSentLowBatteryBroadcast = true;
statusIntent.setAction(Intent.ACTION_BATTERY_LOW);
mContext.sendBroadcast(statusIntent);
That intent is fired from the BatteryService. You'll have to analyze the code a bit, but I'm pretty sure it does not fire repeatedly:
http://gitorious.org/android-eeepc/base/blobs/fda6fae156e31a287e3cfbf66e51ea1405cdf479/services/java/com/android/server/BatteryService.java
The actual values that it fires at are setup in the android resources, so it's configurable only during a system build. This is what we have for our hardware, but this will likely be different for each hardware platform that Android runs on:
<!-- Display low battery warning when battery level dips to this value -->
<integer name="config_lowBatteryWarningLevel">15</integer>
<!-- Close low battery warning when battery level reaches this value -->
<integer name="config_lowBatteryCloseWarningLevel">20</integer>
Unless you're developing a custom hardware platform, I wouldn't make any assumptions about what these values are set to.
There is another way that detect "config_lowBatteryWarningLevel" from "com.android.internal.R.integer" field.
enter code here
try {
Class clazz = Class.forName("com.android.internal.R$integer");
Field field = clazz.getDeclaredField("config_lowBatteryWarningLevel");
field.setAccessible(true);
int LowBatteryLevel = _context.getResources().getInteger(field.getInt(null));
Log.d("LowBattery","warninglevel " + LowBatteryLevel);
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
Is there a way to get battery level only when the level changes?
I know how to get the battery info using Intent.ACTION_BATTERY_CHANGED and then I compare the battery level of it with the last battery level (that I saved before) in case it equals I don't do anything else I do my stuff.
I also know that ACTION_BATTERY_CHANGED happens when there is battery info change (not only the level) so cause of that I need to check the level. I don't know why but sometimes it doesn't work well.
Is there a better way to do it?
There is no other (documented) way to get the battery level. Just ignore the broadcast when the level did not change. As you already do.
You can get the latest status immediately with the following:
IntentFilter batIntentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent battery = this.registerReceiver(null, batIntentFilter);
int level = battery.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
Log.d("TAG", "Current Level: " + level);