FLAG_KEEP_SCREEN_ON Ignored: It's the Screensaver
※本記事にはアフィリエイトリンクを含む場合があります。内容は広告の有無に影響されません。
結論
On Android, a screen still goes black with FLAG_KEEP_SCREEN_ON set because the screensaver fires in the instant the flag isn't in effect — it won't stop until screensaver_enabled is set to 0.
The answer
It’s the screensaver (Daydream).
FLAG_KEEP_SCREEN_ON and disabling sleep run on a separate track from the screensaver. It fires in the instant the flag isn’t in effect, so it’s the one thing left standing after you’ve blocked everything else.
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
And these settings reset on reboot. Stop before that step and you’ll think it’s fixed when it isn’t.
The symptom
- A display meant to stay on goes black after a while
- The device itself is alive — processing keeps running
FLAG_KEEP_SCREEN_ONis already set- Sleep timeout is already extended
- It still goes dark, and you can’t predict when
The unpredictability is the tell. A timeout would produce a consistent interval, but the screensaver slips in during “the instant the flag isn’t in effect,” so there’s no fixed reproduction condition to chase.
More than one path to black
This is the annoying part: there are multiple paths to the screen turning off. Blocking one leaves the others open.
# Disable HDMI-CEC power linkage (gets dragged down by another device's power state)
adb shell settings put global hdmi_control_auto_device_off_enabled 0
# Disable auto power-off on no signal
adb shell settings put global no_signal_auto_power_off 0
# Screen-off timeout
adb shell settings put system screen_off_timeout 2147483647
# Sleep
adb shell settings put secure sleep_timeout -1
# ★ Screensaver — the most likely culprit
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
# Stay awake while powered
adb shell settings put global stay_on_while_plugged_in 7
It’s easy to fix screen_off_timeout and sleep_timeout and assume you’re done, but the screensaver is a setting distinct from both of those.
A layer adb can’t reach
If the device is a TV used as the display, there’s one more layer. The set’s own off-timer sometimes reads a firmware-level setting of its own, and ignores writes from adb.
We hit this on one model where the power kept cutting out at 16:30. settings list global showed an item like tv_timer_power_off_timer_values, but writing to it did nothing — the firmware kept preferring its own setting.
This layer can only be cleared from the device’s own settings screen — usually somewhere under timer, power, or energy saving. Assuming adb covers everything stops you cold right here.
Reboot resets all of it
This is the part that’s easiest to miss.
Values written with settings put disappear on reboot. A command you ran by hand is an “effective right now” fix, not a permanent one. If the device restarts overnight, the next morning you’re back where you started.
To make it permanent, have the app itself reapply the settings on every launch. That requires granting a permission once, up front.
# Write access to Settings.Secure / Settings.Global
adb shell pm grant <package-name> android.permission.WRITE_SECURE_SETTINGS
# Settings.System (screen_off_timeout) goes through appops instead
adb shell appops set <package-name> WRITE_SETTINGS allow
WRITE_SECURE_SETTINGS is a signature|privileged|development permission, but pm grant can still assign it to a regular app.
Confirming it actually took
Without the permission, the app catches the exception and does nothing. It doesn’t crash, so a missed grant is easy to overlook.
Check the actual writes in logcat.
adb logcat -s <tag>
If you see the value it actually wrote — something like sleep_timeout=-1 or screen_off_timeout=MAX — it worked. A line reading skip: means a SecurityException, i.e. a no-op with no permission granted.
The key point here: don’t treat “no error appeared” as proof of success.
Four layers, in summary
| Layer | How to clear it | Survives reboot? |
|---|---|---|
| Screensaver | screensaver_* → 0 |
❌ resets |
| Sleep / screen-off | sleep_timeout / screen_off_timeout |
❌ resets |
| CEC / no-signal off | hdmi_control_* / no_signal_* |
❌ resets |
| Device’s own off-timer | From the device settings screen | ✅ persists |
The top three layers reset on reboot, so you need something on the app side to reapply them. Only the bottom layer is out of adb’s reach — but clear it once from the device UI and it stays cleared.
What happened after running the same kind of device long-term is written up in Running a Google TV as a Device-Owner kiosk for several months.
よくある質問
Q1I disabled every sleep setting and the screen still turns off
The screensaver (Daydream) is still active. It's a separate system from sleep_timeout and screen_off_timeout, so disabling those has no effect on it. Set screensaver_enabled, screensaver_activate_on_sleep, and screensaver_activate_on_dock to 0.
Q2I set it with adb, and it was back off the next day
Values written with settings put reset on reboot. If the device restarts overnight, you're back to square one. To make it permanent, grant WRITE_SECURE_SETTINGS with pm grant and have the app itself reapply the settings on every launch.
Q3Some settings I write with adb have no effect at all
A TV's built-in off-timer sometimes reads its own firmware-level setting and ignores writes from adb entirely. In that case you have to disable it from the device's own settings screen (timer, power, energy saving).
Q4Can WRITE_SECURE_SETTINGS be granted to a regular app?
Yes. It's a signature|privileged|development permission, but adb's pm grant can still assign it to a regular app. Without it, bringing the app back to the foreground still works, but anything that rewrites OS-level sleep settings silently does nothing.
この記事の根拠
- ドキュメントファイル 94〜114行目
- ドキュメントファイル 115〜129行目
本文の主張は、上の記録に書かれていることだけです。運用しているリポジトリは非公開のため リンクは張れませんが、どのファイルの何行目を、どのコミット時点で見て書いたかは 記事ごとに残しています。推測で書いた箇所はありません。