Monday, February 8, 2010

Android XML Parsing

If you ever considered which parser to use in Android, on developer.com you can find an article that does a comparison of DOM, SAX, and XMLPullParser. Since I started working with Java ME in 2003, SAX was the XML parser of choice, since DOM consumed to much memory and was slower. Nothing changed in Android, although the pull parser is much closer in performance to SAX.

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!