Tuesday, April 7, 2015

Implement BroadcastReceiver to monitor change of Charging State and Battery Level

This example show how to implement our BroadcastReceiver to monitor change of Charging State and Battery Level.

reference: http://developer.android.com/training/monitoring-device-state/battery-monitoring.html#MonitorChargeState

In the Android guide, it advise to get status of battery, such as BATTERY_STATUS_CHARGING, BATTERY_STATUS_FULL
  int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);

But in my test on Nexus 7 WiFi (2012) running Android 5.1, status always return -1.

In my example, I change it as:
  IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
  Intent batteryStatus = context.registerReceiver(null, ifilter);
  status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);


MyBatteryReceiver.java, our BroadcastReceiver to monitor change of Charging State and Battery Level.
package com.example.androidbattery;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.widget.Toast;

public class MyBatteryReceiver extends BroadcastReceiver {

 @Override
 public void onReceive(Context context, Intent intent) {
  String action = intent.getAction();

  String strAction;
  if(action == Intent.ACTION_BATTERY_LOW){
   strAction = "ACTION_BATTERY_LOW";
  }else if(action == Intent.ACTION_BATTERY_OKAY){
   strAction = "ACTION_BATTERY_OKAY";
  }else if(action == Intent.ACTION_POWER_CONNECTED){
   strAction = "ACTION_POWER_CONNECTED";
  }else if(action == Intent.ACTION_POWER_DISCONNECTED){
   strAction = "ACTION_POWER_DISCONNECTED";
  }else{
   strAction = "unknown!";
  }
  
  /* === for status detection in BroadcastReceiver === */
  int status;
  /* 
   * advised in Android doc: http://goo.gl/xYemvi
   * but in my test on Nexus 7 WiFi (2012) Android 5.1
   * status always return -1
  */
  //status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
  
  /* I change it like this */
  IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
  Intent batteryStatus = context.registerReceiver(null, ifilter);
  status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
  /* ===== */

  String msg;
  switch(status){
  case BatteryManager.BATTERY_STATUS_CHARGING:
   msg = "status = BATTERY_STATUS_CHARGING\n";
   break;
  case BatteryManager.BATTERY_STATUS_DISCHARGING:
   msg = "status = BATTERY_STATUS_DISCHARGING\n";
   break;
  case BatteryManager.BATTERY_STATUS_FULL:
   msg = "status = BATTERY_STATUS_FULL\n";
   break;
  case BatteryManager.BATTERY_STATUS_NOT_CHARGING:
   msg = "status = BATTERY_STATUS_NOT_CHARGING\n";
   break;
  case BatteryManager.BATTERY_STATUS_UNKNOWN:
   msg = "status = BATTERY_STATUS_UNKNOWN\n";
   break;
  default:
   msg = "status = ...unknown!\n";
  }

  int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
  if(chargePlug == BatteryManager.BATTERY_PLUGGED_USB){
   msg += "Plaugged USB\n";
  }
  if(chargePlug == BatteryManager.BATTERY_PLUGGED_AC){
   msg += "Plaugged AC\n";
  }
  
  Toast.makeText(
    context,
    "MyBatteryReceiver: " + action + "\n"
     + intent.toString()
     + strAction + "\n"
     + "\n"
     + status + " : " + msg, 
    Toast.LENGTH_LONG).show();
 }

}

Modify AndroidManifest.xml, to add <receiver>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.androidbattery"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="22" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <receiver android:name=".MyBatteryReceiver" >
            <intent-filter>
                <action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
                <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
                <action android:name="android.intent.action.ACTION_BATTERY_LOW" />
                <action android:name="android.intent.action.ACTION_BATTERY_OKAY"/>
            </intent-filter>
        </receiver>
    </application>

</manifest>

package com.example.androidbattery;

import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Bundle;

/*
 * reference:
 * http://developer.android.com/training/monitoring-device-state/battery-monitoring.html
 */

public class MainActivity extends ActionBarActivity {

 Button btnReadBattery;
 ImageView imageIcon;
 TextView textBatteryStatus;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        btnReadBattery = (Button)findViewById(R.id.readbattery);
        imageIcon = (ImageView)findViewById(R.id.icon);
        textBatteryStatus = (TextView)findViewById(R.id.batterystatus);
        
        btnReadBattery.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View v) {
    textBatteryStatus.setText(readBattery());
   }});
        
    }

    private String readBattery(){
     StringBuilder sb = new StringBuilder();
     IntentFilter batteryIntentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
     Intent batteryIntent = registerReceiver(null, batteryIntentFilter);

     boolean  present= batteryIntent.getExtras().getBoolean(BatteryManager.EXTRA_PRESENT);
     sb.append("PRESENT: " + present + "\n");
     
     int status = batteryIntent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
     if(status == BatteryManager.BATTERY_STATUS_CHARGING){
      sb.append("BATTERY_STATUS_CHARGING\n");
     }
     if(status == BatteryManager.BATTERY_STATUS_FULL){
      sb.append("BATTERY_STATUS_FULL\n");
     }

     int plugged = batteryIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
     if(plugged == BatteryManager.BATTERY_PLUGGED_USB){
      sb.append("BATTERY_PLUGGED_USB\n");
     }
     if(plugged == BatteryManager.BATTERY_PLUGGED_AC){
      sb.append("BATTERY_PLUGGED_AC\n");
     }

     int level = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
     sb.append("LEVEL: " + level + "\n");
     
        int scale = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
        sb.append("SCALE: " + scale + "\n");
        
        int  health = batteryIntent.getIntExtra(BatteryManager.EXTRA_HEALTH,0);
        sb.append("health: " + convHealth(health) + "\n");
        
        String  technology = batteryIntent.getExtras().getString(BatteryManager.EXTRA_TECHNOLOGY);
        sb.append("TECHNOLOGY: " + technology + "\n");
        
        int  temperature = batteryIntent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE,0);
        sb.append("TEMPERATURE: " + temperature + "\n");
        
        int  voltage = batteryIntent.getIntExtra(BatteryManager.EXTRA_VOLTAGE,0);
        sb.append("VOLTAGE: " + voltage + "\n");
        
        //I have no idea how to load the small icon from system resources!
        int  icon_small_resourceId = batteryIntent.getIntExtra(BatteryManager.EXTRA_ICON_SMALL,0);
        sb.append("ICON_SMALL: " + icon_small_resourceId + "\n");
        
        return sb.toString();
    }
    
    private String convHealth(int health){
     String result;
     switch(health){
     case BatteryManager.BATTERY_HEALTH_COLD:
      result = "BATTERY_HEALTH_COLD";
      break;
     case BatteryManager.BATTERY_HEALTH_DEAD:
      result = "BATTERY_HEALTH_DEAD";
      break;
     case BatteryManager.BATTERY_HEALTH_GOOD:
      result = "BATTERY_HEALTH_GOOD";
      break;
     case BatteryManager.BATTERY_HEALTH_OVERHEAT:
      result = "BATTERY_HEALTH_OVERHEAT";
      break;
     case BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE:
      result = "BATTERY_HEALTH_OVER_VOLTAGE";
      break;
     case BatteryManager.BATTERY_HEALTH_UNKNOWN:
      result = "BATTERY_HEALTH_UNKNOWN";
      break;
     case BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE:
      result = "BATTERY_HEALTH_UNSPECIFIED_FAILURE";
      break;
     default:
      result = "unkknown";
     }

     return result;
    }

}

activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.androidbattery.MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <Button
        android:id="@+id/readbattery"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Read Battery" />

    <TextView
        android:id="@+id/batterystatus"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

download filesDownload the files.

No comments: