FLAG_KEEP_SCREEN_ON を入れても画面が黒くなるのはスクリーンセーバ
※本記事にはアフィリエイトリンクを含む場合があります。内容は広告の有無に影響されません。
結論
Android で FLAG_KEEP_SCREEN_ON を設定しても画面が黒くなるのは、スクリーンセーバがフラグの効かない瞬間に発動するためで、screensaver_enabled を 0 にするまで消灯は止まらない。
結論
スクリーンセーバ(Daydream)です。
FLAG_KEEP_SCREEN_ON を立てても、スリープを無効にしても、スクリーンセーバは別系統で動きます。フラグが効いていない一瞬に発動するので、他を全部塞いでもここだけ残ります。
adb shell settings put secure screensaver_enabled 0
adb shell settings put secure screensaver_activate_on_sleep 0
adb shell settings put secure screensaver_activate_on_dock 0
そしてこの設定は再起動で元に戻ります。そこまでやらないと直った気になって終わります。
症状
- 常時表示させたいのに、しばらくすると画面だけ黒くなる
- 本体は生きている。処理は動き続けている
FLAG_KEEP_SCREEN_ONは入れてある- スリープ時間も伸ばしてある
- なのに消える。しかもいつ消えるか読めない
読めないのが特徴です。タイムアウトなら時間が一定になるはずですが、スクリーンセーバは「フラグが効いていない瞬間」に入り込むので、再現条件が掴めません。
消灯の経路は1つではない
ここが厄介なところで、画面が消える道が複数あります。1つ塞いでも別の道が残ります。
# HDMI-CEC の連動オフ(他機器の電源に引きずられる)
adb shell settings put global hdmi_control_auto_device_off_enabled 0
# 無信号での自動電源オフ
adb shell settings put global no_signal_auto_power_off 0
# 画面オフのタイムアウト
adb shell settings put system screen_off_timeout 2147483647
# スリープ
adb shell settings put secure sleep_timeout -1
# ★ スクリーンセーバ ── ここが最有力
adb shell settings put secure screensaver_enabled 0
adb shell settings put secure screensaver_activate_on_sleep 0
adb shell settings put secure screensaver_activate_on_dock 0
# 給電中は起きたままにする
adb shell settings put global stay_on_while_plugged_in 7
screen_off_timeout と sleep_timeout を直して安心してしまいがちですが、スクリーンセーバはそのどちらとも別の設定です。
adb では届かない層がある
テレビを表示装置に使っている場合、もう一段あります。本体のオフタイマーは firmware が自前の設定を見ていることがあり、adb から書いても効きません。
実際に、ある機種で 16:30 に電源が落ち続けたことがあります。settings list global には tv_timer_power_off_timer_values のような項目が見えるのに、そこへ書いても firmware は自分の設定を優先していました。
**この層だけは端末の設定画面から消すしかありません。**タイマー・電源・省エネあたりにあります。
adb で全部片付くと思っていると、ここで止まります。
再起動で全部戻る
いちばん見落とすのがこれです。
**settings put で書いた値は、再起動すると消えます。**手で流したコマンドは「今すぐ効く」対策であって、恒久ではありません。端末が夜中に再起動すれば、翌朝は元通りです。
恒久化するには、アプリ自身が起動のたびに再適用する形にします。そのための権限を一度だけ与えます。
# Settings.Secure / Settings.Global への書き込み
adb shell pm grant <パッケージ名> android.permission.WRITE_SECURE_SETTINGS
# Settings.System(screen_off_timeout)は appops 経由
adb shell appops set <パッケージ名> WRITE_SETTINGS allow
WRITE_SECURE_SETTINGS は signature|privileged|development の権限ですが、pm grant なら一般のアプリにも付与できます。
付いたかどうかを確かめる
権限が無いとき、アプリは例外を握って何もしません。落ちないので、付与し忘れに気づけません。
logcat で実際の書き込みを見ます。
adb logcat -s <タグ>
sleep_timeout=-1 や screen_off_timeout=MAX のように書けた値が出れば成功です。skip: と出ていれば SecurityException で、権限が無いまま no-op になっています。
「エラーが出ていない」を成功の根拠にしないのがここでの要点です。
まとめると層は4つ
| 層 | 消し方 | 再起動で戻る |
|---|---|---|
| スクリーンセーバ | screensaver_* を 0 |
✅ 戻る |
| スリープ・画面オフ | sleep_timeout / screen_off_timeout |
✅ 戻る |
| CEC・無信号オフ | hdmi_control_* / no_signal_* |
✅ 戻る |
| 本体のオフタイマー | 端末の設定画面から | 戻らない |
上の3層は再起動で戻るので、アプリ側で再適用する仕組みが要ります。いちばん下の層だけは adb では触れず、代わりに一度消せば残ります。
同じ端末を長期運用したときに何が起きたかは Google TV を Device Owner でキオスク化して1年運用した結果 にまとめています。
よくある質問
Q1スリープ設定を全部切ったのに画面が消えます
スクリーンセーバ(Daydream)が残っています。sleep_timeout や screen_off_timeout とは別系統の設定なので、それらを無効にしても発動します。screensaver_enabled・screensaver_activate_on_sleep・screensaver_activate_on_dock の3つを 0 にしてください。
Q2adb で設定したのに、翌日また消えていました
settings put で書いた値は再起動で元に戻ります。端末が夜間に再起動すると振り出しです。恒久化するには WRITE_SECURE_SETTINGS を pm grant で与え、アプリ自身が起動時に再適用する形にします。
Q3adb で書いてもまったく効かない設定があります
テレビ本体のオフタイマーは firmware が自前の設定を見ていることがあり、adb から書いても無視されます。この場合は端末の設定画面(タイマー・電源・省エネ)から無効にするしかありません。
Q4WRITE_SECURE_SETTINGS は一般のアプリに付与できますか?
できます。signature|privileged|development の権限ですが、adb の pm grant で一般アプリにも付与できます。付与しなくてもアプリを前面に戻す動作は生きますが、OS 側のスリープ設定を書き換える部分は黙って何もしません。