Android

Androidでどんな時でもセンサ値を収集し続けられるようにする方法

概要

加速度や角速度などのセンサ値を収集し続けるAndroidアプリ、要はロガーを開発する際に、Dozeやスリープ(電源ボタンを押して画面が消えている状態)になった時の対応についてまとめる

要件

  • Dozeに耐える
  • 画面をスリープしてもセンサ値を収集し続ける(SensorManagerで取れる加速度や角速度、気圧などを対象としているが、Wi-FiやGPSでも同じ対策方法で取れそうな気はする)

結論

結論から言うとタイトルのベストプラクティスは、対象アプリをDozeのホワイトリストに入れて、WakeLockをacquireすると、センサ値を収集し続けることができる。

センサ値が取得できない時とは

SensorManagerにregisterListenerしてなかったからとかそういうレベルではなく、Dozeやスリープモードによってセンサ値が取得できない状況が多々ある。

Dozeに関しては、Android M/NのDozeによる制限とバックグラウンドタスク実行に関するまとめが非常によくまとまってるので読むべき。
合わせてDoze と App Standby 用に最適化するも読もう。

スリープモードは、Android PowerManager を使うなどにあるが、要は画面がスリープした時に処理が止まってしまうため、センサ値が取得できなくなる。

対策

Doze

Doze対策はホワイトリストに入れるのが最も簡単。

manifestに

<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />

を追加。

ホワイトリストに入れるようにユーザに促す。onCreateとかで呼ぼう
電池の最適化云々のダイアログが出るのではいをタップすればホワイトリストに入る。
ホワイトリスト入ってるかどうかは、isIgnoringBatteryOptimizationsでも分かるが、設定->電池->右上から電池の最適化 からでも確認できる

PowerManager powerManager = getSystemService(PowerManager.class);
if (!powerManager.isIgnoringBatteryOptimizations(getPackageName())) {
    Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
    intent.setData(Uri.parse("package:" + getPackageName()));
    startActivity(intent);
}

スリープ

Doze対策をしていると、WakeLockが使えるのでこうする。

//private PowerManager.WakeLock wakeLock;

PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getPackageName());
wakeLock.acquire();
//wakeLock.release(); //使い終わった時とかonDestroyとかで呼ぼう

まとめ

当然ながら、バッテリー消費は増加する。
こういうアプリがストアから配信できるのかは不明。