Skip to content

feat: smart rotation for widget stacks - #1504

Open
jawzf wants to merge 1 commit into
sameerasw:developfrom
jawzf:feat/021-smart-stack
Open

jawzf wants to merge 1 commit into
sameerasw:developfrom
jawzf:feat/021-smart-stack

Conversation

@jawzf

@jawzf jawzf commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Description

Adds Smart rotation to widget stacks. In a stack's settings, Show what matters now (off by default, so existing stacks behave as before) brings forward the widget that matters right now and holds it there, pausing the timer:

  1. the widget of the app that's playing music;
  2. otherwise a calendar app's widget when an event starts within the next 30 minutes;
  3. otherwise a battery widget while a charger is plugged in.

When it switches:

  • When the screen turns on (the lock screen still covers the homescreen, so the switch isn't seen) and when a signal changes (playback starts or stops, charger plugged or unplugged). Never on a timer while you might be looking at the stack.
  • If you switch with the arrows or edges, smart picks leave that stack alone until the screen turns off.
  • When the reason ends (music paused, charger unplugged), the stack stays on that widget and the timer carries on from there.

How it works:

  • StackSmartPick.pick is a small pure function (unit tested) that takes the hosted widgets' provider components and the current signals, and returns the first match in priority order. Calendar apps are the ones declaring CATEGORY_APP_CALENDAR; battery widgets are matched by "batter" in the provider class (Battery…, Batteries…), which covers Essentials' own Battery Status widget.
  • StackHost reuses MediaSessionSource for playback, CalendarEventUtil.queryNextUpcomingEvent (run off the main thread on screen on) for events and the sticky battery intent's EXTRA_PLUGGED for charging. All event driven; no polling, alarms, new permissions or manifest entries.
  • Missing notification access or calendar access shows a Grant row under the switch.
  • Also removes the beta badge from Widget stack.

Notes:

  • Unlock (ACTION_USER_PRESENT) isn't used: it's sent by System UI, so it never reaches the stack's RECEIVER_NOT_EXPORTED receiver. Screen on is used instead.
  • BatteryManager.isCharging stayed true after unplugging in testing, so "charging" means a charger is plugged in.
  • Known: on the emulator, 1 of 6 screen-on picks left the launcher showing the previous widget (the pick and render were logged correctly), so the stack stayed there until the next change. Not seen on the phone.

Type of change

  • Bug fix
  • New feature
  • UI / visual update
  • Performance improvement
  • Refactoring / cleanup
  • Translations
  • Build / CI tooling

UI changes

1_settings_smart_rotation

The new Smart rotation section in the stack's settings.

2_home_music

Music playing: the stack holds the player's widget.

3_home_charging

Charger plugged in: the stack holds the battery widget.

Checklist

  • The base branch is set to develop (not main).
  • The app builds cleanly locally with ./gradlew assembleDebug (and assembleRelease).
  • Unit tests pass with ./gradlew testDebugUnitTest (new: StackSmartPickTest).
  • Tested on the Android 17 emulator (Clock, YouTube Music, Calendar month view and Battery Status in one stack): music hold and release, manual override until screen off, charging hold and release, calendar pick on screen on with an event 20 minutes out, Grant rows, switch off restores plain rotation.
  • Tested on a Pixel 11 Pro (Android 17): music and charging holds work. The calendar switch wasn't seen on the phone (no event starting within 30 minutes during the test).
  • Per-stack setting stored with the stack's config in WidgetStackRepository, like its interval and controls.
  • No new search entry: it's a per-stack option in the stack's own settings sheet.
  • Reuses RoundedCardContainer and the stack sheet's existing row and Grant button style.
  • New strings are in strings.xml (English only).
  • No new dependencies or manifest permissions. Release APK +4 KB (18,660 → 18,664 KB).

🤖 Generated with Claude Code

A stack with Smart rotation on brings forward the widget that matters
now and holds it, pausing the timer: the app playing music, a calendar
app when an event starts within 30 minutes, or a battery widget while a
charger is plugged in. It picks when the screen turns on or a signal
changes, never while the stack is in view, and a manual switch leaves
the stack alone until the screen turns off. Also drops the beta badge
from Widget stack.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jawzf
jawzf force-pushed the feat/021-smart-stack branch from d71a50c to ee51105 Compare October 25, 2026 09:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

1 participant