Skip to content

Commit fa928f4

Browse files
committed
fix: aggressive sleep fires reliably after every scheduled refresh
2 parents 9aa9d59 + dba9d04 commit fa928f4

File tree

3 files changed

+63
-19
lines changed

3 files changed

+63
-19
lines changed

AGENTS.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,8 @@ docker exec <container_id> bash -c "<command>"
8585
## Worktrees
8686

8787
Active development happens in the worktree at `/home/coder/trmnl-nook-sleep` on branch `feature/tap-menu-sleep`. The main checkout is at `/home/coder/trmnl-nook-simple-touch`.
88+
89+
> **CRITICAL for agents:** The devcontainer mounts `/home/coder/trmnl-nook-sleep` as `/workspace`.
90+
> All source edits MUST be made to files under `/home/coder/trmnl-nook-sleep/` (the worktree).
91+
> Editing `/home/coder/trmnl-nook-simple-touch/` (the main checkout) has NO effect on builds.
92+
> Always verify with: `docker inspect <container_id> --format '{{range .Mounts}}{{.Source}} -> {{.Destination}}{{println}}{{end}}'`

CHANGELOG.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
## [v0.12.0] - 2026-03-29
6+
7+
### Fixed
8+
- **Aggressive sleep now reliably fires after every scheduled refresh.** Previously the super-sleep check used `fetchReason` and flag state that could be clobbered by `onResume()`, meaning the device often stayed awake after displaying a new image. Simplified to: if Aggressive Sleep is enabled and the fetch was not triggered by the user (menu tap), call `sleepNow()` immediately after the image renders — no flags, no race conditions.
9+
- `sleepPending` is now correctly cleared in `onResume()` and the screen timeout is always restored to 120 s on wake, regardless of sleep path.
10+
11+
### Notes
12+
- All source edits must target the worktree at `/home/coder/trmnl-nook-sleep/` — see AGENTS.md.
13+
14+
---
15+
16+
## [v0.11.0] - 2026-03-28
17+
18+
### Added
19+
- **Aggressive Sleep** (`Settings → General → Aggressive sleep`): puts the device to sleep immediately after each scheduled image refresh rather than waiting for the screensaver timeout. Battery savings vs. standard deep sleep are TBD.
20+
- **Sleep button** (`Settings → System → Sleep`): manually triggers an immediate sleep from the settings screen.
21+
- `android.permission.WRITE_SETTINGS` permission — used to set `SCREEN_OFF_TIMEOUT = 1000 ms` to trigger Android's natural screen-off path (no root required). Restored to 120 s on wake.
22+
- `AGENTS.md`: documents the build environment, all failed sleep approaches, and the working `WRITE_SETTINGS` trick.
23+
24+
### Changed
25+
- Screensaver/sleep-ready delay reduced from 5 s to 2 s.
26+
- Deep sleep hint always visible when "Sleep between updates" is enabled.
27+
- README: added Aggressive Sleep section and listed it in Features.
28+
29+
### Removed
30+
- `android.permission.DEVICE_POWER` (was unused / ungrantable).
31+
32+
---
33+
34+
## [v0.10.0] - 2026-03-25
35+
36+
### Added
37+
- Gift Mode restart flow improvements.
38+
39+
---
40+
41+
*Older releases are documented on the [GitHub Releases](https://github.com/usetrmnl/trmnl-nook-simple-touch/releases) page.*

src/com/bpmct/trmnl_nook_simple_touch/DisplayActivity.java

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ public class DisplayActivity extends Activity {
9393
private BroadcastReceiver connectivityReceiver;
9494
private Runnable pendingSleepRunnable;
9595
private Runnable pendingScreenOffRunnable;
96-
/** True while sleepNow() is armed — blocks onResume from re-asserting FLAG_KEEP_SCREEN_ON. */
96+
/** True while sleepNow() is armed — blocks onResume from re-asserting FLAG_KEEP_SCREEN_ON
97+
* and restoring the 120s screen timeout until the device actually wakes. */
9798
private volatile boolean sleepPending = false;
9899
private Runnable pendingWifiWarmupRunnable;
99100
private Runnable pendingConnectivityTimeoutRunnable;
@@ -374,18 +375,14 @@ protected void onResume() {
374375
getWindow().setFlags(
375376
WindowManager.LayoutParams.FLAG_FULLSCREEN,
376377
WindowManager.LayoutParams.FLAG_FULLSCREEN);
377-
if (!sleepPending) {
378-
setKeepScreenAwake(true);
379-
// Restore screen timeout to normal (in case sleep button set it to 1s)
380-
try {
381-
android.provider.Settings.System.putInt(
382-
getContentResolver(),
383-
android.provider.Settings.System.SCREEN_OFF_TIMEOUT,
384-
120000);
385-
} catch (Throwable t) { /* ignore */ }
386-
} else {
387-
logD("onResume: sleepPending=true, skipping setKeepScreenAwake");
388-
}
378+
sleepPending = false;
379+
try {
380+
android.provider.Settings.System.putInt(
381+
getContentResolver(),
382+
android.provider.Settings.System.SCREEN_OFF_TIMEOUT,
383+
120000);
384+
} catch (Throwable t) { /* ignore */ }
385+
setKeepScreenAwake(true);
389386

390387
boolean wifiJustOn = ensureWifiOnWhenForeground();
391388

@@ -1289,7 +1286,7 @@ private void sleepNow() {
12891286
pendingScreenOffRunnable = new Runnable() {
12901287
public void run() {
12911288
pendingScreenOffRunnable = null;
1292-
sleepPending = false;
1289+
// NOTE: sleepPending stays true until onResume() after the real wake.
12931290
logD("sleepNow: setting screen_off_timeout=1000 to force natural sleep");
12941291
try {
12951292
android.provider.Settings.System.putInt(
@@ -1595,11 +1592,12 @@ protected void onPostExecute(Object result) {
15951592
a.forceFullRefresh();
15961593
a.logD("displayed image");
15971594
a.logD("next display in " + (a.refreshMs / 1000L) + "s");
1598-
// Super Sleep: if enabled and this was a background (timer/alarm) fetch, sleep immediately
1599-
if (ApiPrefs.isSuperSleep(a)
1600-
&& ApiPrefs.isAllowSleep(a)
1601-
&& !fromMenu
1602-
&& ("timer".equals(a.fetchReason) || "alarm".equals(a.fetchReason))) {
1595+
// Super Sleep: sleep immediately after every background image render.
1596+
// Skip only if user tapped Next from the menu.
1597+
boolean superSleep = ApiPrefs.isSuperSleep(a);
1598+
boolean allowSleep = ApiPrefs.isAllowSleep(a);
1599+
a.logD("super-sleep check: superSleep=" + superSleep + " allowSleep=" + allowSleep + " fromMenu=" + fromMenu);
1600+
if (superSleep && allowSleep && !fromMenu) {
16031601
a.logD("super sleep: sleeping immediately after image load");
16041602
a.sleepNow();
16051603
} else {

0 commit comments

Comments
 (0)