Skip to content

feat: add Locale plugin integration for automation apps - #974

Draft
vibhor1102 wants to merge 5 commits into
Nain57:masterfrom
vibhor1102:feature/automation-trigger
Draft

feat: add Locale plugin integration for automation apps#974
vibhor1102 wants to merge 5 commits into
Nain57:masterfrom
vibhor1102:feature/automation-trigger

Conversation

@vibhor1102

@vibhor1102 vibhor1102 commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR adds a user-facing Locale-plugin integration for automation hosts such as Tasker, MacroDroid, and Automate. It replaces the need for users to construct raw scenario-control intents themselves with host-native configuration screens, while also allowing Smart scenarios to send named events back to an automation host.

The detailed background, design discussion, FAQs, and the full set of demos are in Discussion #949.

Demo: External Action

Screenrecorder-2026-07-09-14-37-15-704.mp4

The video shows the intended low-friction flow: give an External Action a meaningful name in Klick'r, configure the matching event once in the automation app, then use it as a normal automation trigger.

What this adds

Incoming scenario controls

The app now exposes two Locale setting plugins:

  • Launch Scenario opens a configuration screen listing Smart and Dumb scenarios. The selected scenario is stored by database ID and type, so the host does not need to know Klick'r internals.
  • Stop Scenario is a separate, immediately-configured setting which stops the currently loaded scenario.

The configuration result follows the Locale bundle/blurb contract. The payload is JSON signed with an HMAC-SHA256 key kept in AndroidKeyStore; the receiver reconstructs and verifies the exact payload before resolving it. Missing, malformed, unsigned, or altered settings are rejected instead of allowing another local app to forge a launch/stop request.

Scenario IDs are resolved from the current database at execution time, so deleted scenarios fail safely. The executor deliberately treats launch as selecting/loading a scenario, rather than silently pressing Play: a request for an already loaded Dumb scenario is a no-op; replacing a different scenario stops the existing one and leaves the requested scenario ready for the user. For a Smart scenario with an already active screen-recording session, Klick'r can switch the selected scenario without requesting MediaProjection again.

Outgoing External Action events

Smart scenarios gain an External Action type. An action carries a user-defined, non-empty name and is persisted through the normal action database, compatibility, and mapping paths. When executed, it broadcasts a Locale/Tasker REQUEST_QUERY carrying that name as pass-through data.

The event-plugin configuration screen stores the name the host should listen for. On the corresponding QUERY_CONDITION, Klick'r returns satisfied only when the configured and fired names match. The scenario editor also offers existing names as reusable choices, so repeated signals stay consistent without exposing implementation details to the user.

Android background-launch handling

MediaProjection consent cannot be shown reliably from every background state, especially on a locked device or under OEM background-launch restrictions. The receiver therefore uses the following guarded flow:

  1. Resolve and validate the requested action off the broadcast thread.
  2. Prefer a normal direct helper-activity launch only when the device is interactive and the scenario editor is not open.
  3. If Android/OEM policy prevents the helper from opening, or it does not acknowledge within 1.5 seconds, show a notification continuation instead.
  4. Record a failed direct launch and show the existing Don't Kill My App guidance the next time Klick'r is opened. A deliberate lock-screen notification fallback does not create a false failure report.

Request IDs plus an in-process tracker and small persisted hand-off store prevent delayed Android delivery, an old notification tap, or a second launch attempt from reviving stale work. The implementation also defers to the notification path when the scenario configuration UI is open, avoiding an external request silently replacing work the user is editing.

Notification permission is offered during Launch Scenario setup to support this fallback, but declining it does not block saving the automation.

Structure and compatibility

  • Generalizes the existing Quick Settings feature module into feature:external-launch, preserving the tile while giving both tile and plugin controls one shared service boundary.
  • Adds the action database migration/schema, domain/UI mappers, editor UI, icons, resource text, and compatibility handling needed for External Action.
  • Adds English and existing translated resource entries for the new plugin and fallback copy.
  • Leaves the existing generic Intent action in place; this is a user-friendly integration layer, not a removal of the existing developer-oriented capability.

Validation

  • git diff --check upstream/master...feature/automation-trigger passes.
  • Hosted validation on the feature implementation passed both Run unit tests and Build patched debug APK: Actions run 29183012946.
  • The new unit coverage exercises signed configuration decoding, external-event configuration decoding, Smart/Dumb/Stop action resolution, duplicate Dumb-scenario protection, direct/fallback request freshness, and configuration restoration.

The hosted validation was run before removing the fork-only debug workflow and its ABI build-speed tuning from this upstream branch; the integration source under review is unchanged by that cleanup.

Status

The public plugin surface, launch behavior, and background-launch fallback described above are finalized. They were discussed and demonstrated in Discussion #949; this remains a draft only for upstream review before approval.

The only remaining UI-organization decision is whether External Action should remain distinct from the existing raw Intent action or be combined with it. That question is isolated in a separate PR comment.

@vibhor1102

Copy link
Copy Markdown
Contributor Author

@Nain57, one remaining UI-organization choice to decide separately from the finalized Locale-plugin behavior:

Should External Action remain a distinct Smart-scenario action, as implemented here, or should it be combined with the existing raw Intent action?

I kept it separate because it gives Tasker/MacroDroid users an end-to-end friendly flow: name the signal in Klick'r, select the same name while configuring the host event, then use it as a normal automation trigger. The existing Intent action remains untouched for the developer/advanced use cases you mentioned in Discussion #949.

However, since the raw Intent action is already useful and its dialog could potentially support multiple external-communication formats, I can merge this UI into it if that is the preferred long-term organization. This is the only remaining design choice from my side; the plugin surface, launch semantics, and background fallback are finalized.

@vibhor1102

Copy link
Copy Markdown
Contributor Author

@Nain57 The decision remains open whether to:

  • integrate it as another mode within the "intents" action, and rename it
  • Or, create a new action like i initially implemented

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant