Android Marshmallow の Doze テストの正しい手順

# 前提

Android 6.0 Marshmallow (MPA44I) Developer Preview 3
Nexus 5, Nexus 6

# Google 様の言う Doze のテスト方法がよく分からない件

いわゆる Android M の Doze をテストする方法として、Google の公式文書では adb を使った方法が示されています。
追記：以下はプレビュー時代の解説文書の内容になります。現在は [こちら](http://developer.android.com/intl/ja/training/monitoring-device-state/doze-standby.html) がそれに相当します。

[Doze と App Standby をテストする](http://developer.android.com/intl/ja/preview/testing/guide.html)
> アプリで Doze をテストするには:
> 
> 1. M Preview のシステム イメージを使用して、ハードウェア端末または仮想端末を構成します。
> 1. 端末を開発マシンに接続し、アプリをインストールします。
> 1. アプリを実行し、アクティブ状態のままにします。
> 1. 以下のコマンドを実行して、端末の Doze モードへの移行をシミュレートします。
> 1. 端末がアクティブ状態に戻ったときのアプリの動作を観察します。端末が Doze モードから抜けるときに、アプリがスムーズに復帰することを確認します。

> ```
$ adb shell dumpsys battery unplug
$ adb shell dumpsys deviceidle step
$ adb shell dumpsys deviceidle -h
> ```

実際この通りにやっても、unplug されて、ACTIVE かを確認して、ヘルプが表示されるだけです。しかも戻し方は記載されていないので、鵜呑みにした我々は unplug 状態のまま放置されることになります。本来なら `unplug reset` で元に戻すわけですが、`-h` でヘルプを表示する方法を教えたからあとは各自で頑張ってくれということでしょうか。不親切ですね。

しかも残念なことに、**このやり方では Doze のテストになりません。**だめじゃん。

同じ疑問を抱いた方はいたらしく、本件が Issue として上がっているのを見つけました。その表題でも「**Doze テストガイドが不明瞭である**」と言ってくれています。
[Issue 2930: Testing guide for Doze is unclear](
https://code.google.com/p/android-developer-preview/issues/detail?id=2930&thanks=2930&ts=1439405162)

そしてここに記載がある方法で Doze のテストができそうです。コマンドには "Doze" という言葉が一切出てこないので不安ですが、"Doze" = "Idle" という解釈で良いのでしょうか。

# Doze のテスト方法

内部電源状態かつ Idle 状態が Doze になるようです。おそらくこの方法でなら Doze をテストすることができます。

## 1. 内部電源状態をシミュレートする

USB ケーブルをつないでいる状態で内部電源状態をシミュレートします。

```:unplug
$ adb shell dumpsys battery unplug
```
powered が `false` になっていればシミュレートできています。

```:確認
$ adb shell dumpsys battery
Current Battery Service state:
  AC powered: false
  USB powered: false
  Wireless powered: false
  ...
```

## 2. Idle を有効にする

上記の方法で内部電源状態にしたら、次に Idle を有効化します。

```:Idleを有効化
$ adb shell dumpsys deviceidle enable
```

## 3. Idle に移行する

二種類の方法があります。一つ目は、電源ボタンを押して画面をスリープさせてからコマンドを実行します。順番に状態が切り替わっていくので、出力が `IDLE` になるまで何度か繰り返します。unplug を実行していないとこれが切り替わらないので注意してください。

```:画面をスリープさせた上で状態を移行
$ adb shell dumpsys deviceidle step
```

```:出力
Stepped to: IDLE_PENDING
Stepped to: SENSING
Stepped to: IDLE
Stepped to: IDLE_MAINTENANCE
Stepped to: IDLE
...
```

二つ目の方法では強制的に Idle に移行するコマンドを使用します。これを使うと画面をスリープさせる必要がありません。

```:画面をスリープさせずに強制的にIdleに移行
$ adb shell dumpsys deviceidle force-idle
```

`dumpsys deviceidle` の出力にある mState を見れば現在の状態を確認できます。

```:確認
$ adb shell dumpsys deviceidle
  ...
  mScreenOn=false
  mCharging=false
  mSigMotionActive=true
  mState=IDLE
  ...
```

_※例の Issue でも質問されている様に、`IDLE` と `IDLE MAINTENANCE` の違いがよくわかりません。_

この状態でアプリの検証をすればよさそうです。

## 元に戻す

おそらくこれで元に戻せます。

```:unplug,idle状態から元に戻す
$ adb shell dumpsys deviceidle disable
$ adb shell dumpsys battery reset
```

# 「電池の最適化」ホワイトリストの操作

「電池の最適化」設定画面にて無効にしているアプリ（パッケージ）の一覧です。同じ `dumpsys deviceidle` でホワイトリストの操作および確認が可能です。
http://qiita.com/items/8b0e9c1c51b8942ee7c0

現在のところ、設定画面とコマンドによる操作が同期しないバグがあるようです。

# 参考資料

- http://developer.android.com/intl/ja/preview/testing/guide.html
- https://newcircle.com/s/post/1739/2015/06/12/diving-into-android-m-doze
- http://stackoverflow.com/questions/31533972/how-to-shift-device-in-doze-mode-android-preview-m
- https://code.google.com/p/android-developer-preview/issues/detail?id=2930&thanks=2930&ts=1439405162