Broaden platform action and trigger coverage #22

Open
opened 2026-09-16 21:55:05 +02:00 by morten-olsen · 2 comments
Owner

Goal: cover as much of the Android platform as the app can legitimately reach, in matched get/set pairs plus the trigger
for the same state, so an automation can read a value, change it, and restore it.

The recent Do Not Disturb, volume and audio-playback work is the pattern to follow: a read action, a write action that
reports what it replaced, and an event where Android exposes one.

Existing coverage

State Get Set Trigger
Do Not Disturb yes yes yes
Volume / ringer yes yes no
Audio routes yes n/a yes
Battery / power yes n/a yes
Network / Wi-Fi yes no yes
Screen / lock yes no yes
SMS n/a send receive
Playback n/a yes finished

Candidates

Weighted towards what works without privileged permissions and stays F-Droid compatible — no proprietary services.

  • Ringer mode set, alongside the existing volume read/write.
  • Wi-Fi and Bluetooth enable/disable, which on modern Android means a settings panel intent rather than a silent toggle; worth confirming what is still possible on API 36 before promising a set.
  • Screen brightness and timeout, needing WRITE_SETTINGS, which is a special access like Do Not Disturb.
  • Torch on/off through CameraManager, plus its availability callback as a trigger.
  • Clipboard get/set, with Android 10+ background read restrictions making the get conditional.
  • Media transport controls (play/pause/next) and a currently-playing read, via MediaSession.
  • Notification posted/removed triggers through a notification listener, which ENGINE.md already calls out as an OS-governed exception.
  • Calendar and contacts reads as typed references rather than embedded payloads.
  • Device idle / doze and app foreground state reads.
  • Location once the region event source lands (#1).

Constraints to respect

  • Keep adapters behind the existing registry and gateway seams; no new competing catalogues.
  • Every write declares its effect and, where meaningful, reports the state it replaced, so restore stays authorable.
  • Special-access permissions fail closed with a recovery route, as dnd.set does.
  • Triggers register through BackgroundResourceManager ownership rather than independent managers.
Goal: cover as much of the Android platform as the app can legitimately reach, in matched get/set pairs plus the trigger for the same state, so an automation can read a value, change it, and restore it. The recent Do Not Disturb, volume and audio-playback work is the pattern to follow: a read action, a write action that reports what it replaced, and an event where Android exposes one. ## Existing coverage | State | Get | Set | Trigger | | --- | --- | --- | --- | | Do Not Disturb | yes | yes | yes | | Volume / ringer | yes | yes | no | | Audio routes | yes | n/a | yes | | Battery / power | yes | n/a | yes | | Network / Wi-Fi | yes | no | yes | | Screen / lock | yes | no | yes | | SMS | n/a | send | receive | | Playback | n/a | yes | finished | ## Candidates Weighted towards what works without privileged permissions and stays F-Droid compatible — no proprietary services. - **Ringer mode** set, alongside the existing volume read/write. - **Wi-Fi and Bluetooth enable/disable**, which on modern Android means a settings panel intent rather than a silent toggle; worth confirming what is still possible on API 36 before promising a `set`. - **Screen brightness and timeout**, needing `WRITE_SETTINGS`, which is a special access like Do Not Disturb. - **Torch** on/off through `CameraManager`, plus its availability callback as a trigger. - **Clipboard** get/set, with Android 10+ background read restrictions making the `get` conditional. - **Media transport controls** (play/pause/next) and a currently-playing read, via `MediaSession`. - **Notification posted/removed** triggers through a notification listener, which ENGINE.md already calls out as an OS-governed exception. - **Calendar and contacts** reads as typed references rather than embedded payloads. - **Device idle / doze** and **app foreground** state reads. - **Location** once the region event source lands (#1). ## Constraints to respect - Keep adapters behind the existing registry and gateway seams; no new competing catalogues. - Every write declares its effect and, where meaningful, reports the state it replaced, so restore stays authorable. - Special-access permissions fail closed with a recovery route, as `dnd.set` does. - Triggers register through `BackgroundResourceManager` ownership rather than independent managers.
Author
Owner

First increment landed in 2bd4a83: ringer mode, torch (set + status), clipboard (get + set), and display brightness and
screen timeout behind WRITE_SETTINGS. All verified on a Pixel 9 / API 36 AOSP emulator.

Coverage table updated:

State Get Set Trigger
Ringer mode yes yes no, see #23
Torch yes yes no, see #23
Clipboard yes, focused app only yes n/a
Brightness / screen timeout yes yes, WRITE_SETTINGS n/a

Findings that change the remaining plan

  • Wi-Fi and Bluetooth toggles are not worth attempting. WifiManager.setWifiEnabled is a no-op for apps targeting
    API 29+, and BluetoothAdapter.enable() is deprecated and non-functional from API 33. The only honest option is
    launching a settings panel, which is not an automation. Suggest recording them as permanently unavailable with a
    reason, the way planned event sources already are, rather than leaving them on the candidate list.
  • Clipboard reads need hasText separate from text. Android only lets the focused app read the clipboard, so a
    background run sees nothing; an empty string alone cannot be distinguished from an empty clipboard.
  • Torch has no state getter, only a callback that reports the current value on registration, and that callback needs
    an explicit handler because actions run on a background dispatcher with no Looper.

Still open from the original list

Media transport controls and notification posted/removed both need a notification listener, which ENGINE.md already
calls out as an OS-governed exception and which deserves its own increment. Calendar and contacts reads want the typed
reference seam that FileReference now establishes. Device idle and app-foreground reads are small and could join the
next batch.

First increment landed in 2bd4a83: ringer mode, torch (set + status), clipboard (get + set), and display brightness and screen timeout behind WRITE_SETTINGS. All verified on a Pixel 9 / API 36 AOSP emulator. Coverage table updated: | State | Get | Set | Trigger | | --- | --- | --- | --- | | Ringer mode | yes | **yes** | no, see #23 | | Torch | **yes** | **yes** | no, see #23 | | Clipboard | **yes**, focused app only | **yes** | n/a | | Brightness / screen timeout | **yes** | **yes**, WRITE_SETTINGS | n/a | ## Findings that change the remaining plan - **Wi-Fi and Bluetooth toggles are not worth attempting.** `WifiManager.setWifiEnabled` is a no-op for apps targeting API 29+, and `BluetoothAdapter.enable()` is deprecated and non-functional from API 33. The only honest option is launching a settings panel, which is not an automation. Suggest recording them as permanently unavailable with a reason, the way planned event sources already are, rather than leaving them on the candidate list. - **Clipboard reads need `hasText` separate from `text`.** Android only lets the focused app read the clipboard, so a background run sees nothing; an empty string alone cannot be distinguished from an empty clipboard. - **Torch has no state getter**, only a callback that reports the current value on registration, and that callback needs an explicit handler because actions run on a background dispatcher with no Looper. ## Still open from the original list Media transport controls and notification posted/removed both need a notification listener, which ENGINE.md already calls out as an OS-governed exception and which deserves its own increment. Calendar and contacts reads want the typed reference seam that `FileReference` now establishes. Device idle and app-foreground reads are small and could join the next batch.
Author
Owner

Further increments landed: b03f058, 9b6da33, ef9e9e3, 3029ae6, 6ea922c, bea18a5, 4e1ba1c, bbe4d7f.

The catalogue is now 44 actions/operators and 21 event types. Full instrumented suite (68 tests) green on a Pixel 9 / API 36 AOSP emulator, plus the JVM suite and lint.

Coverage now

Area Get Set Trigger
Do Not Disturb yes yes yes
Volume / ringer mode yes yes no, see #23
Torch yes yes no, see #23
Clipboard yes, focused app only yes n/a
Brightness / timeout / auto-rotate yes yes n/a
Device, locale, power, thermal, storage yes n/a power, battery, time, locale
Apps yes launch installed/updated/removed
Contacts lookup by number n/a n/a
Media now playing transport control n/a
Notifications n/a show, dismiss posted, removed
Audio playback n/a play, stop finished
Intents / events n/a send, publish external ingress

Built-in modifiers

Roughly 30 pure actions covering text, numbers, dates, lists, dictionaries and value selection, so ordinary shaping no longer needs a JavaScript node: split/join, regex match and replace, pad, case, URL and Base64 coding, hashing; arithmetic, rounding, clamping, formatting, parsing, statistics, random; date format/parse/adjust/difference/parts; list get with negative indexes, slice, sort by key, unique, contains; JSON parse/stringify, dotted-path get and set, keys, merge; choose-value and default-if-empty.

Notes for whoever picks this up next

  • number.random declares Read, not Pure, so it is never retried as a deterministic computation.
  • Date adjustment goes through the zoned calendar, so adding a month lands on the next month's same day rather than 30 days later.
  • App updates are reported once, not as a removal plus an install.
  • The notification listener ignores Macros' own notifications, otherwise showing a notification could trigger the automation that showed it.
  • Provider exceptions now become action_threw failures instead of propagating out of the registry.

Still open

Accessibility integration, calendar reads, and "ask for input" (which would map onto durable suspension rather than a blocking dialog). Wi-Fi and Bluetooth toggles remain not worth attempting, per the earlier comment.

Further increments landed: `b03f058`, `9b6da33`, `ef9e9e3`, `3029ae6`, `6ea922c`, `bea18a5`, `4e1ba1c`, `bbe4d7f`. The catalogue is now **44 actions/operators and 21 event types**. Full instrumented suite (68 tests) green on a Pixel 9 / API 36 AOSP emulator, plus the JVM suite and lint. ## Coverage now | Area | Get | Set | Trigger | | --- | --- | --- | --- | | Do Not Disturb | yes | yes | yes | | Volume / ringer mode | yes | yes | no, see #23 | | Torch | yes | yes | no, see #23 | | Clipboard | yes, focused app only | yes | n/a | | Brightness / timeout / auto-rotate | yes | yes | n/a | | Device, locale, power, thermal, storage | yes | n/a | power, battery, time, locale | | Apps | yes | launch | installed/updated/removed | | Contacts | lookup by number | n/a | n/a | | Media | now playing | transport control | n/a | | Notifications | n/a | show, dismiss | posted, removed | | Audio playback | n/a | play, stop | finished | | Intents / events | n/a | send, publish | external ingress | ## Built-in modifiers Roughly 30 pure actions covering text, numbers, dates, lists, dictionaries and value selection, so ordinary shaping no longer needs a JavaScript node: split/join, regex match and replace, pad, case, URL and Base64 coding, hashing; arithmetic, rounding, clamping, formatting, parsing, statistics, random; date format/parse/adjust/difference/parts; list get with negative indexes, slice, sort by key, unique, contains; JSON parse/stringify, dotted-path get and set, keys, merge; choose-value and default-if-empty. ## Notes for whoever picks this up next - `number.random` declares Read, not Pure, so it is never retried as a deterministic computation. - Date adjustment goes through the zoned calendar, so adding a month lands on the next month's same day rather than 30 days later. - App updates are reported once, not as a removal plus an install. - The notification listener ignores Macros' own notifications, otherwise showing a notification could trigger the automation that showed it. - Provider exceptions now become `action_threw` failures instead of propagating out of the registry. ## Still open Accessibility integration, calendar reads, and "ask for input" (which would map onto durable suspension rather than a blocking dialog). Wi-Fi and Bluetooth toggles remain not worth attempting, per the earlier comment.
Sign in to join this conversation.
No labels
bug
enhancement
feature
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
incubator/macros#22
No description provided.