2011年9月17日土曜日

Android アプリの終了処理:Low BatteryとShutdown(1)



アプリを作る際、Low Batteryによる端末終了と、Shutdownによる終了の処理が必要になりますので、調べてみました。

Low Batteryの処理
バッテリーステータスは、Broadcast Intentで、アプリに飛んできます。簡単に図にまとめます。(FULL/NORMAL/LOWは、便宜的につけたステータスです)



今回のようなシチュエーションでは、Low Batteryによる処理をしますので、ACTION_BATTERY_LOWのBroadcast Intentを捕まえれば・・・ではないです

このACTION_BATTERY_LOWは、機種にもよりますが、バッテリー残量が15%になると発行されるようです。

そうです、ぜんぜんLow Batteryとは言えません。このIntentが発行されるタイミングは、まさに、端末が「バッテリー残量が少ないです」って割り込みのポップアップを出してくるタイミングです。

これはただのユーザへの警告ですので、アプリとしてここでLow Batteryの終了を始めるのは、気が早い。
さらに、アプリ起動時に、このBroad cast Intentが発行済みの場合、(つまり残量15%以下)、アプリには通知されません。

アプリが知りたいのは、バッテリー残量が0%になった、もう端末終了するよ〜の状態です。
Emulatorと、Xperiaで、Low Batteryにしてみたところ、ACTION_BATTERY_CHANGEDで、EXTRA_LEVELが0で通知され、その直後にACTION_SHUTDOWNが飛んでくる動作になっていました。
ということで、EXTRA_LEVEL=0を検出するか、ACTION_SHUTDOWNを受ける動作をすればよい、ということになります。

ただ、そのACTION_SHUTDOWNも、何も考えずに使えるわけでもなさそうなので、別エントリで調査結果を書きます。

Android アプリの終了処理:Low BatteryとShutdown(2)に続きます

Battery周りの動作を確認したコードを晒しておきます。
ちなみにBroadcastReceiverの作り方など、こちらを参考にさせてもらっています。

package test.sample.battery;

import android.app.Activity;
import android.os.Bundle;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Handler;
import android.os.Message;
import android.util.Log;


public class BatteryTestActivity extends Activity {
 private static final String TAG = "BatteryTest";
 
 private final static int msgBatteryLow = 1;
 private final static int msgShutdown = 2;
 private final static int msgBatteryChanged = 3;
 private final static int msgBatteryOK = 4;
 
 @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        startSystemMonitor();
    }

 @Override
 protected void onDestroy() {
  Log.d(TAG, "onDestroy()");
  super.onDestroy();
  stopSystemMonitor();
 }

 @Override
 protected void onPause() {
  Log.d(TAG, "onPause()");
  super.onPause();
 }

 @Override
 protected void onRestart() {
  Log.d(TAG, "onRestart()");
  super.onRestart();
 }

 @Override
 protected void onResume() {
  Log.d(TAG, "onResume()");
  super.onResume();
 }

 @Override
 protected void onStart() {
  Log.d(TAG, "onStart()");
  super.onStart();
 }



 @Override
 protected void onStop() {
  Log.d(TAG, "onStop()");
  super.onStop();
 }


 public void onBatteryOk()
 {
  Log.d(TAG, "onBatteryOk");
 }
 public void onBatteryLow()
 {
  Log.d(TAG, "onBatteryLow()");
 }
 
 public void onBatteryChanged()
 {
  Log.d(TAG, "onBatteryChanged");
 }

 public void onShutdown()
 {
  Log.d(TAG, "onShutdown");
 }

 private Handler mHandler = new Handler()
 {

  @Override
  public void handleMessage(Message msg) {
   switch (msg.what)
   {
   case msgBatteryLow:
    onBatteryLow();
    break;
   case msgBatteryChanged:
    onBatteryChanged();
    break;
   case msgShutdown:
    onShutdown();
    break;
   case msgBatteryOK:
    onBatteryOk();
    break;
    
   default:
    super.handleMessage(msg);
    break;
   }
   super.handleMessage(msg);
  }
  
 };
 
 
 public void startSystemMonitor()
 {
  registerReceiver(lowBatteryReceiver, lowBatteryFilter);
  registerReceiver(batteryChangedReceiver, batteryChangedFilter);
  registerReceiver(shutdownReceiver, shutdownFilter);
 }
 
 public void stopSystemMonitor()
 {
  unregisterReceiver(lowBatteryReceiver);
  unregisterReceiver(batteryChangedReceiver);
  unregisterReceiver(shutdownReceiver);
 }
 
 private final BroadcastReceiver lowBatteryReceiver = new BroadcastReceiver()
 {

  @Override
  public void onReceive(Context context, Intent intent) {
   Log.d(TAG, "lowBatteryReceiver:onReceive()" + ", action:" + intent.getAction());

   if (intent.getAction().equals(Intent.ACTION_BATTERY_LOW))
   {
    mHandler.sendEmptyMessage(msgBatteryLow);
   } else if (intent.getAction().equals(Intent.ACTION_BATTERY_OKAY)){
    mHandler.sendEmptyMessage(msgBatteryOK);
   } else {
    assert true;
   }
   
  }
  
 };

 private static final IntentFilter lowBatteryFilter = new IntentFilter();
    static {
     lowBatteryFilter.addAction(Intent.ACTION_BATTERY_LOW);
     lowBatteryFilter.addAction(Intent.ACTION_BATTERY_OKAY);
    }
 
 private final BroadcastReceiver batteryChangedReceiver = new BroadcastReceiver()
 {

  @Override
  public void onReceive(Context context, Intent intent) {
   if (intent.getAction().equals(Intent.ACTION_BATTERY_CHANGED))
   {
    int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);

    Log.d(TAG, "ACTION_BATTERY_CHANGED: " + level + ", Extra:" + BatteryManager.EXTRA_SCALE);

    Message msg = new Message();
    msg.what = msgBatteryChanged;
    msg.arg1 = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
    msg.arg2 = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
    
    mHandler.sendMessage(msg);

   } else {
    assert true;
   }
   
  }
  
 };

 private static final IntentFilter batteryChangedFilter = new IntentFilter();
    static {
     batteryChangedFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
    }

 private final BroadcastReceiver shutdownReceiver = new BroadcastReceiver()
 {

  @Override
  public void onReceive(Context context, Intent intent) {
   if (intent.getAction().equals(Intent.ACTION_SHUTDOWN))
   {
    Log.d(TAG, "ACTION_SHUTDOWN");
    mHandler.sendEmptyMessage(msgShutdown);
   } else {
    assert true;
   }
   
  }
  
 };
 private static final IntentFilter shutdownFilter = new IntentFilter();
    static {
     shutdownFilter.addAction(Intent.ACTION_SHUTDOWN);
    }

}

0 件のコメント:

コメントを投稿