Sunday, February 7, 2010

Getting the Battery Level in Android using the SDK

Finding out the battery level using the Android SDK is not quite an easy task because this functionality is not documented, which means it can change at any point in time. Well, after reading a little more about the ACTION_BATTERY_CHANGED Intent and about the BatteryManager class, starting with API Level 5, you have all the information needed to get the status on your phone's battery. The BatteryManager class contains some String values that will give you information about the current battery level and the scale, constants such as EXTRA_LEVEL and EXTRA_SCALE. If you were to work with an API version older than 2.0 (< 5), then it becomes a little more difficult to find the right information as it is not documented in the APIs as far as I could tell.

For now, here is how you can find out:
  • Create an IntentFilter that matches the Intent.ACTION_BATTERY_CHANGED action.
  • Create a BroadcastReceiver that will be called with a broadcast intent.
  • Inside onReceive, retrieve data based on the "level" item (battery level) for version < 5, or use BatteryManager.EXTRA_LEVEL for versions >= 5.
  • Register the receiver that will be called with the broadcast intent that signals a battery change 
Here is the BatteryLevelActivity:
package edu.fau.csi.battery;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.widget.TextView;

/**
 * Used for finding the battery level of an Android-based phone.
 * 
 * @author Mihai Fonoage
 *
 */
public class BatteryLevelActivity extends Activity {
    /** Called when the activity is first created. */
    private TextView batterLevel;

    @Override
    /**
     * Called when the current activity is first created.
     */
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.main);
        batterLevel = (TextView) this.findViewById(R.id.batteryLevel);
        batteryLevel();
    }

    /**
     * Computes the battery level by registering a receiver to the intent triggered 
     * by a battery status/level change.
     */
    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);
    }
    
}
The battery.xml layout file is next:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout 
  xmlns:android="http://schemas.android.com/apk/res/android" 
  android:orientation="vertical" 
  android:layout_width="fill_parent" 
  android:layout_height="fill_parent"> 
  
    <TextView         
        android:id="@+id/batteryLevel"
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent" 
        android:gravity="center_vertical|center_horizontal"
        android:textSize="50dip"> 
    </TextView>
    
</LinearLayout>


As I mentioned in the beginning, if you are using Android 2.0 or higher, you can make the following changes to the batteryLevel method of the BatterLevelActivity class:
    /**
     * Computes the battery level by registering a receiver to the intent triggered 
     * by a battery status/level change.
     */
    private void batteryLevel() {
        BroadcastReceiver batteryLevelReceiver = new BroadcastReceiver() {
            public void onReceive(Context context, Intent intent) {
                context.unregisterReceiver(this);
                int rawlevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
                int scale = intent.getIntExtra(BatteryManager.EXTRA_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);
    }
The code for getting the battery level was inspired from the Twisty project.

Enjoy!

23 comments:

Unknown said...

The info u gave was very helpful,I am working on a formula to calculate the battery life,I dont have a real device and unable to change the battery lvl of the emulator.Is there any means to change the battery lvl of an emulator or I have to buy a device for rnd ,TY

Mihai Fonoage said...

Hi Nishant,

I have never tried it (had a G1 to test the code), but you might be able. Look at http://developer.android.com/guide/developing/tools/emulator.html#power.

Chintan said...

Thanks for the info.
I have two questions to ask,

1. Android SDK does not export the current "battery current" parameter right? I am able to view the value of current through /sys/class/power_supply/..
but looking at the code of JNI interface, I don't think we would be able to get 'current' values. Any workaround?

2. I am trying to build an app which logs the battery data over period of few hours, in that case I would have to put this app into sleep and then wakeup at defined interval.

Is there any other better alternative for it?

Thanks,

Mihai Fonoage said...

Hi Chintan,

1. There is no value in BatterManager that would tell you the battery current. However, you could approximate by using Ohm's law (Current = Voltage/Resistance), knowing that typically, the internal resistance for a 1000 mA Lithium mobile phone battery is between 100 and 200 mOhm. Of course, you would want to make sure of this.

2. An Alarm could be used: http://developer.android.com/guide/appendix/faq/commontasks.html#alarms.

Chintan said...

Hi Mihai,

Thanks for your quick reply.

For the current measurements, we have to read the specific value from the sysfs, as the dividing Battery Voltage by the constant resistor won't give us the correct value of current. pls correct me if I am wrong.

The sysfs interface from kernel gives me correct value of current when I am connected via USB, but if I disconnect it gives me the value of current as zero. it should be greater than zero.

Thanks,

Arun R Murthy said...

Hi Mihai,
I am writting a batttery driver and integrating it to android.
I am able to see the battery parameters getting updated only on plug/unplug of AC/USB charger.
The issue that I am facing is battery capacity if not getting updated in the mean time.

When I do a cat from the sysfs I am able to see the change in the battery capacity.

Please let me know where an I missing with?

Thanks,
Arun

Adriano Tornatore said...

Nishant i'm developing an application to control also the battery status properties of android Emulator. You can find it here http://atornatore.wordpress.com

Unknown said...

thanks Adriano for the emulator controller

simon said...

thank you very much for that code.
i implented it into my test application but i dont really know how to recieve the information from "level" with another method/class.
i have done this:

BatteryLevelActivity bla = new BatteryLevelActivity();

bla.batteryLevel();



if ( level == 0 )
{
c.drawColor(0xfffc0000);
}
else
{ c.drawColor(0xfffc00fc);
}


but everytime i run i get
The application has stopped unexpectedly. Please try again."

can you help me? please?

Unknown said...

Nice tutorial.

Is it possible to get battery level for each running application on phone? If it is possible then how? Have you any idea or suggestions?

Thanks.
Pranav

Arun R Murthy said...

Pranav,
Battery level will be available from the sys class. You need to register an UEventObserver from you application. This will ensure that you are being notified with the updated battery level from time to time.


Correspondingly the battery driver in kernel has to send uevent on observing a change in battery level.

himanshu said...

Hi - I wanted to know a way to support additional battery on android device. Does that need writing of a new library?
Thanks,
Himanshu

Felipe said...

nevermind..I found this other solution which worked for me: http://android-er.blogspot.com/2010/09/detect-battery-info.html. thanks

Lucas Sun said...

Thank your for the excellent tutorial.

I have one question to ask.
Can I get battery level anytime I want to query instead of receiving battery info while the value changes?

ahmadpi said...

thanks for sharing! this is works very well for me on Android 2.3.3.

Ashok said...

I have not more idea about Android coding. I want to calculate % of battery discharge by how many times I encrypted or decrypted my message in Android API 4.0.3 emulator. Kindly write step by step procedure or coding. Thanking you.

Ashok said...
This comment has been removed by the author.
theju said...

Can any one suggest me how to calculate % of battery used by each application in device. I got some private API's which are not possible to implement. So please suggest me how i should do it. Thanks

Unknown said...

Very usefull!!
Thank You!

JorgeRO said...

Thanks a lot this was very useful information. Is there any way to retrieve the battery consumption from a particular application?

Meghna said...

Nice post Mihai.. Thanks for sharing this. Even this http://www.compiletimeerror.com/2013/05/android-battery-percentage-example.html might help.. have a look...

Braydenblake said...

Hybrid batteries are completely re-manufactured.All of Hybrid Batteries carry a minimum 90 day warranty with some models going up to 48 MONTHS.
re-involt

Unknown said...

It is working when app is open. I want to show notification when battery is low and app is closed.