Releases: Alaa91H/NexaFlow
Release list
NexaFlow v3.85.1
Fixed
- Skipped-run reasons are now visible in the UI. Skipped executions store an exact gate reason (e.g.
Skipped: not all trigger conditions are true (charger, run time)) in the backend diagnostic message, but both the history list and the execution-details screen showed only a generic localized "Task was skipped." label. The stored reason is now surfaced verbatim beneath the summary in the routine history row and on the execution-details header, so a silent skip is always diagnosable from the UI without connecting a debugger. Backend messages remain untouched (diagnostics protocol preserved); presentation-only change.
Notes
- The skip-reason protocol (
Skipped:message prefix recorded by the engine) predates this release; this change closes the visibility gap between the persisted diagnostics and the user-facing history without altering any recorded data or engine behavior.
Quality evidence
The tag workflow gates publication on the following automated checks. Consult the exact tag run and validation record for results; these checks do not establish physical-device coverage:
- Android Lint (zero-tolerance: UnusedResources, MissingTranslation, ExtraTranslation,
UnusedIds, CheckResult, HardcodedText, TypographyDashes) and Detekt static analysis. - Catalog parity gates: every
TriggerTypeandActionTypeenum value must exist
exactly once in the builder picker (restricted entries are pinned explicitly). - Full unit-test suite, including Room migration, scheduler, lifecycle, and recovery
regression coverage. - Release build with R8 full shrinking, APK signature verification (v2/v3 schemes and
certificate-fingerprint match against the production keystore), 16 KB page-size
alignment check, zipalign verification, bundletool AAB validation, and Gradle
dependency verification (SHA-256 checksums for every artifact). - Tag hygiene: the tag must match the newest
CHANGELOG.mdentry, so the notes below
are the actual, reviewed change record for this release.
Install
- Download
NexaFlow-<version>.apkfrom the assets below and install it. - Android updates require a compatible version code and the same signing certificate.
Back up important tasks before upgrading. - Pre-release tags (
alpha/beta/rc) are marked as pre-releases automatically.
Documentation
NexaFlow v3.84.0
Fixed
- Watch shows automations instantly, even while the phone app is asleep.
Studied two open-source companions with proven sync (PixelWater,
WearFiles) and adopted their decisive pattern: on startup the watch now
reads the cached automation DataItem directly from the local Data Layer
store (getDataItems) instead of depending entirely on the live
request chain (pull-request message → phone listener service → push →
DATA_CHANGED). The snapshot may be one edit stale, but the UI shows real
content immediately; the background pull request then refreshes it. Any
single failure in that chain previously left the watch on its
"Connecting" spinner forever. - Symmetric process wake-up on the phone side. The phone listener now
also declares theDATA_CHANGEDintent filter for/nexaflow/paths
(the pattern both reference apps use), so Play Services can start the
phone process for Data Layer traffic with the same reliability it already
had for command messages. AonDataChangedhandler consumes the buffer
and ignores self-echo, keeping the audit surface explicit and reviewed.
Tests
- Snapshot contract suite: wire-format parity for the automation path and
payload key between the standalone wear module and the phone constants,
the exactwear://*URI shape the cache read parses, and DTO round-trip
through the sameJsondecoder both entry points share.
Quality evidence
The tag workflow gates publication on the following automated checks. Consult the exact tag run and validation record for results; these checks do not establish physical-device coverage:
- Android Lint (zero-tolerance: UnusedResources, MissingTranslation, ExtraTranslation,
UnusedIds, CheckResult, HardcodedText, TypographyDashes) and Detekt static analysis. - Catalog parity gates: every
TriggerTypeandActionTypeenum value must exist
exactly once in the builder picker (restricted entries are pinned explicitly). - Full unit-test suite, including Room migration, scheduler, lifecycle, and recovery
regression coverage. - Release build with R8 full shrinking, APK signature verification (v2/v3 schemes and
certificate-fingerprint match against the production keystore), 16 KB page-size
alignment check, zipalign verification, bundletool AAB validation, and Gradle
dependency verification (SHA-256 checksums for every artifact). - Tag hygiene: the tag must match the newest
CHANGELOG.mdentry, so the notes below
are the actual, reviewed change record for this release.
Install
- Download
NexaFlow-<version>.apkfrom the assets below and install it. - Android updates require a compatible version code and the same signing certificate.
Back up important tasks before upgrading. - Pre-release tags (
alpha/beta/rc) are marked as pre-releases automatically.
Documentation
NexaFlow v3.83.0
Fixed
- Edited trigger removals now persist reliably. The automation builder waits for
its ViewModel-owned save job to finish before leaving the navigation stack.
Previously the screen could pop immediately after Save, clear the destination
ViewModel, and cancel the in-flight Room write; removed triggers could then
reappear when the task was opened again. A regression test now guards the
post-save ordering. Fixes #7.
Changed
- Trigger-match ALL mode is now a full evaluation policy, not just a
multi-trigger gate. The dedicatedTriggerMatchPolicycentralizes the
ANY/ALL combination (truth table: ANY requires at least one verifiably
satisfied condition; ALL requires every condition verifiably satisfied;
an empty condition list can never start a run under either mode), and the
execution engine routes every trigger evaluation through it. A task with a
single condition in ALL mode is now live-evaluated like any other —
the firing monitor only starts the evaluation and is never treated as
proof that its condition still holds. - Honest typed condition results for state-read adapters.
CHARGERand
AIRPLANE_MODEare classified as definitive-false-when-false state reads
(likeTIMEandDEVICE): a false answer is a verified current state and
an unreadable state surfaces asUnknown, so the ALL gate and the manual
run gate no longer over-report unverifiable conditions.
Added
- Builder advisory for event-only triggers in ALL mode. When a task set
to "all conditions" contains a momentary trigger that can never be
re-verified from device state (notification, boot, NFC tag scan, SMS,
webhook, sensor, plugin, geofence, ...), the builder shows an explicit
warning that such a condition will keep the task from running in ALL mode,
instead of failing silently at runtime. Localized across all 10 supported
languages.
Tests
- Complete ANY/ALL truth-table policy suite (17 cases) including 3-condition
combinations, the empty-condition guard, and event-only advisory
classification. - Cross-midnight time-range matrix:
22:00–07:00is satisfied at 22:30,
01:00 and 06:59 and unsatisfied at 12:00, 18:00 and 07:01, plus the
charging-at-night acceptance scenario. - Engine gate tests for ALL mode with a single condition (both the skip and
the run path) proving a firing monitor is not current truth.
Quality evidence
The tag workflow gates publication on the following automated checks. Consult the exact tag run and validation record for results; these checks do not establish physical-device coverage:
- Android Lint (zero-tolerance: UnusedResources, MissingTranslation, ExtraTranslation,
UnusedIds, CheckResult, HardcodedText, TypographyDashes) and Detekt static analysis. - Catalog parity gates: every
TriggerTypeandActionTypeenum value must exist
exactly once in the builder picker (restricted entries are pinned explicitly). - Full unit-test suite, including Room migration, scheduler, lifecycle, and recovery
regression coverage. - Release build with R8 full shrinking, APK signature verification (v2/v3 schemes and
certificate-fingerprint match against the production keystore), 16 KB page-size
alignment check, zipalign verification, bundletool AAB validation, and Gradle
dependency verification (SHA-256 checksums for every artifact). - Tag hygiene: the tag must match the newest
CHANGELOG.mdentry, so the notes below
are the actual, reviewed change record for this release.
Install
- Download
NexaFlow-<version>.apkfrom the assets below and install it. - Android updates require a compatible version code and the same signing certificate.
Back up important tasks before upgrading. - Pre-release tags (
alpha/beta/rc) are marked as pre-releases automatically.
Documentation
NexaFlow v3.82.0
Fixed
- Wear OS sync no longer stays on "Connecting". Two root causes closed:
the phone now declares a Data Layer capability (nexaflow.sync) and
re-pushes the automation snapshot whenever a wearable node connects
(previously a single fire-and-forgetDataItempush at process start was
silently lost if the watch was not reachable at that moment); and the watch
now actively requests a sync via the MessageClient pull-request protocol
when the app is opened or resumed, instead of waiting for a push that may
never come. Together the watch recovers in every order of events — watch
opens first, phone restarts while watch is away, or a transient GMS failure.
Added
- ALL/ANY trigger matching (community request). Automations with multiple
triggers previously always fired when any trigger fired (implicit OR).
A new per-automationtriggerMatchpolicy — exposed in the builder as a
selector above the trigger list — lets users require ALL conditions to
hold simultaneously: e.g. enable DND only when charging AND between
22:00–07:00. In ALL mode the engine verifies the remaining triggers' live
state (viaTriggerStateEvaluator) after the initiating trigger fires;
event-only trigger types (notification, screen-off, package install/uninstall,
boot, …) cannot be confirmed after the fact and therefore disqualify ALL
matching for that automation, falling back to documented OR semantics.
Serialized as an optional field — existing automations and backups keep
their historical ANY behavior unchanged.
Quality evidence
The tag workflow gates publication on the following automated checks. Consult the exact tag run and validation record for results; these checks do not establish physical-device coverage:
- Android Lint (zero-tolerance: UnusedResources, MissingTranslation, ExtraTranslation,
UnusedIds, CheckResult, HardcodedText, TypographyDashes) and Detekt static analysis. - Catalog parity gates: every
TriggerTypeandActionTypeenum value must exist
exactly once in the builder picker (restricted entries are pinned explicitly). - Full unit-test suite, including Room migration, scheduler, lifecycle, and recovery
regression coverage. - Release build with R8 full shrinking, APK signature verification (v2/v3 schemes and
certificate-fingerprint match against the production keystore), 16 KB page-size
alignment check, zipalign verification, bundletool AAB validation, and Gradle
dependency verification (SHA-256 checksums for every artifact). - Tag hygiene: the tag must match the newest
CHANGELOG.mdentry, so the notes below
are the actual, reviewed change record for this release.
Install
- Download
NexaFlow-<version>.apkfrom the assets below and install it. - Android updates require a compatible version code and the same signing certificate.
Back up important tasks before upgrading. - Pre-release tags (
alpha/beta/rc) are marked as pre-releases automatically.
Documentation
NexaFlow v3.81.0
Added
- Package operations migrated to the semantic router (Phase B). Force-stop
(APPLICATION_CLOSE_APP,SYSTEM_FORCE_STOP_APP), clear-data
(SYSTEM_CLEAR_APP_DATA), and package enable/disable (SYSTEM_ENABLE_APP,
SYSTEM_DISABLE_APP) now execute as typed semantic operations
(PACKAGE_FORCE_STOP,PACKAGE_CLEAR_DATA,PACKAGE_SET_ENABLED_STATE)
through the Shizuku and Root typed strategies — closedpm/amargv over
the UserService AIDL, never workflow-supplied shell text. - Real package-state read-back. A new bounded
ReadPackageEnabledState
privileged operation (pm list packages -d, one deterministic output line)
gives verification and UNKNOWN-reconciliation an actual post-condition read;
the public-API strategy contributesPackageManagerenabled-setting reads,
so a Shizuku/Root-originated UNKNOWN can be settled through the Android API
when available. Unexpected output shapes stay honest-null, never guesses. - Honest failure semantics. A package dispatch that may have landed before
a transport drop surfaces as UNKNOWN and reconciles by reading state instead
of blind re-execution;PACKAGE_CLEAR_DATAis registered with
UNSUPPORTEDcompensation (data destruction is irreversible) and HIGH risk. - Legacy-config compatibility. The historical
package/packageName
config aliases resolve in the mapper;SYSTEM_ENABLE_APP/SYSTEM_DISABLE_APP
carry their intent in the action type for pre-configVersion automations;
unparseable explicit flags are rejected rather than defaulted.
Changed
OperationRegistrygrows to 32 registered operations (28 state pairs plus
the four package operations); parity gates extended with a package
counterpart test, an honest-compensation assertion for clear-data, and the
documented privileged-only exception for package writes.
Quality evidence
The tag workflow gates publication on the following automated checks. Consult the exact tag run and validation record for results; these checks do not establish physical-device coverage:
- Android Lint (zero-tolerance: UnusedResources, MissingTranslation, ExtraTranslation,
UnusedIds, CheckResult, HardcodedText, TypographyDashes) and Detekt static analysis. - Catalog parity gates: every
TriggerTypeandActionTypeenum value must exist
exactly once in the builder picker (restricted entries are pinned explicitly). - Full unit-test suite, including Room migration, scheduler, lifecycle, and recovery
regression coverage. - Release build with R8 full shrinking, APK signature verification (v2/v3 schemes and
certificate-fingerprint match against the production keystore), 16 KB page-size
alignment check, zipalign verification, bundletool AAB validation, and Gradle
dependency verification (SHA-256 checksums for every artifact). - Tag hygiene: the tag must match the newest
CHANGELOG.mdentry, so the notes below
are the actual, reviewed change record for this release.
Install
- Download
NexaFlow-<version>.apkfrom the assets below and install it. - Android updates require a compatible version code and the same signing certificate.
Back up important tasks before upgrading. - Pre-release tags (
alpha/beta/rc) are marked as pre-releases automatically.
Documentation
NexaFlow v3.80.0
Added
- Shizuku typed strategy — Phase B of the capability-adaptive migration.
ShizukuTypedStrategyroutes semantic operations through the closed
PrivilegedOperationalgebra viaPrivilegedRunner.runShizukuOperation
(UserService AIDL, direct argv, neversh -c). Implemented operations:
Wi-Fi / Bluetooth / airplane mode / NFC / mobile data / hotspot / DND state
writes, plus bounded read-back for reconciliation and verification through
the reviewed settings-read allowlist. The strategy is the only place a new
Shizuku argv shape may be added — workflow input can never become a shell
expression through this path. - Honest Shizuku readiness. Availability distinguishes three states:
not granted (permission required), granted but UserService not bound
(GRANTED_NOT_BOUND — reported unavailable with a reconnect path, never
executable), and ready. A granted permission alone is no longer treated as
readiness for typed operations. - Real environment-event wiring.
EnvironmentEventWiringconnects the
semantic-layerEnvironmentEventBusto the actual Shizuku lifecycle
listener: binder received, binder dead, and UserService
connected/disconnected transitions publish targeted
ShizukuStateChangedevents. TheEnvironmentInvalidatorerases only
Shizuku-backed evidence and health — root evidence survives a Shizuku
binder death (targeted invalidation, never a full capability rescan).
Wiring is idempotent and injected through a listener-registration seam so
it is unit-testable without the Shizuku server.
Changed
- Production DI now ships four semantic strategies (public Android API,
Shizuku typed, root typed, Settings hand-off); the registry-parity gate
updated accordingly. Router fallback and UNKNOWN-reconciliation semantics
are unchanged and now exercised for the Shizuku path: a radio toggle that
may have landed before a transport drop surfaces asUNKNOWNand
reconciles by reading the actual state, never re-executes.
Quality evidence
The tag workflow gates publication on the following automated checks. Consult the exact tag run and validation record for results; these checks do not establish physical-device coverage:
- Android Lint (zero-tolerance: UnusedResources, MissingTranslation, ExtraTranslation,
UnusedIds, CheckResult, HardcodedText, TypographyDashes) and Detekt static analysis. - Catalog parity gates: every
TriggerTypeandActionTypeenum value must exist
exactly once in the builder picker (restricted entries are pinned explicitly). - Full unit-test suite, including Room migration, scheduler, lifecycle, and recovery
regression coverage. - Release build with R8 full shrinking, APK signature verification (v2/v3 schemes and
certificate-fingerprint match against the production keystore), 16 KB page-size
alignment check, zipalign verification, bundletool AAB validation, and Gradle
dependency verification (SHA-256 checksums for every artifact). - Tag hygiene: the tag must match the newest
CHANGELOG.mdentry, so the notes below
are the actual, reviewed change record for this release.
Install
- Download
NexaFlow-<version>.apkfrom the assets below and install it. - Android updates require a compatible version code and the same signing certificate.
Back up important tasks before upgrading. - Pre-release tags (
alpha/beta/rc) are marked as pre-releases automatically.
Documentation
NexaFlow v3.79.0
Fixed
- Task runs silently skipped — four root causes eliminated. User-reported:
many automations did not execute on a connected device. Static analysis and
device logcat review traced every skip path to the admission layer, not the
actions:- Save-time snapshot race —
saveAutomationread the capability snapshot
synchronously while the refresh triggered on screen entry was still in
flight, so the pre-scan answer classified runnable tasks as inadmissible
and saved them disabled. Admission is now decided on
CapabilityStateStore.freshSnapshot(): request a refresh, wait (bounded,
4 s budget) for an observation made at or after the request. Inside the
store's 30 s minimum-refresh backoff the recent snapshot is returned
immediately, so the save flow can never hang. - Stale snapshot blocking runs — the whole-run capability gate blocked
any task whose snapshot was inadmissible, including snapshots observed
hours earlier while the process sat in the background. A snapshot older
than 60 s is now treated as not evidence about the device: the gate
admits and every action path re-verifies the concrete capability live
before its first side effect (diagnostic timeline entry
CAPABILITY_BLOCKED_STALE_SNAPSHOT). - Fresh-block learning — a block on a genuinely fresh, observed
unavailability now schedules a targeted capability refresh
(capabilitySnapshotInvalidator), so a grant that lands right after a
blocked run is seen by the next run instead of re-blocking on the same
evidence forever. - Grant visibility after failure — when an action failed with "No
elevated runtime", the engine only invalidated the root-probe cache,
which the 5 s storm-spacing guard then silently swallowed; a grant that
landed a second earlier stayed hidden through every "refresh".
SystemAppStatusDetector.refreshAndProbe()now bypasses the spacing
guard deliberately (documented: one extrasuspawn is the price of
never hiding a fresh grant), and the engine retries the action exactly
once when the re-probe flips to granted — safe, because the previous run
never reached the elevated runtime and no side effect can have started.
- Save-time snapshot race —
Tests
CapabilityGateFreshnessTest(4 tests): stale snapshot admits, startup
race admits, fresh block records and schedules a refresh, fresh admissible
runs.SaveAdmissionFreshnessTest(2 tests):freshSnapshotreturns a
post-refresh observation; respects the backoff window without hanging.RefreshAndProbeTest(3 tests): forced refresh bypasses the spacing guard,
result is cached for ordinary callers, invalidate-only can never observe a
grant. All tests seed a deterministic baseline so none depends on leftover
probe state or wall-clock distance.- Full suite: 816 unit tests across
core/execution,core/rom-integration
anddomain— 0 failures, 0 skipped.
Quality evidence
The tag workflow gates publication on the following automated checks. Consult the exact tag run and validation record for results; these checks do not establish physical-device coverage:
- Android Lint (zero-tolerance: UnusedResources, MissingTranslation, ExtraTranslation,
UnusedIds, CheckResult, HardcodedText, TypographyDashes) and Detekt static analysis. - Catalog parity gates: every
TriggerTypeandActionTypeenum value must exist
exactly once in the builder picker (restricted entries are pinned explicitly). - Full unit-test suite, including Room migration, scheduler, lifecycle, and recovery
regression coverage. - Release build with R8 full shrinking, APK signature verification (v2/v3 schemes and
certificate-fingerprint match against the production keystore), 16 KB page-size
alignment check, zipalign verification, bundletool AAB validation, and Gradle
dependency verification (SHA-256 checksums for every artifact). - Tag hygiene: the tag must match the newest
CHANGELOG.mdentry, so the notes below
are the actual, reviewed change record for this release.
Install
- Download
NexaFlow-<version>.apkfrom the assets below and install it. - Android updates require a compatible version code and the same signing certificate.
Back up important tasks before upgrading. - Pre-release tags (
alpha/beta/rc) are marked as pre-releases automatically.
Documentation
NexaFlow v3.78.0
Changed
- Product-neutral codebase (vendor decoupling) — NexaFlow no longer names
commercial ROMs, OEMs or devices anywhere in its code, resources, UI or docs.
The engine reasons about capability tiers, never products:RomFamilyredefined from 27 vendor-named entries to 8 neutral
capability tiers (CUSTOM_ROM_PRIVILEGED,CUSTOM_ROM_PRIVACY,
OEM_SKIN_PRIVILEGED,OEM_SKIN,OEM_STOCK,STOCK_GOOGLE,AOSP,
OTHER) describing what a build can do, not what it is called.RomDetectionMatrixkeeps every detection fingerprint (version
properties, brand constraints, manufacturer fallbacks) as protocol evidence
in one reviewed table, now mapping to the neutral tiers.- Files renamed:
EvolutionXSettingsBridge→CustomSettingsBridge,
EvolverCatalog→RomSettingCatalog,EvoActionHandler→
RomSettingsActionHandler,EvolverSettingPickerDialog→
RomSettingPickerDialog; the vendor autostart deep-link resolver now picks
the first vendor gate activity that actually resolves on the device. - Serialized action-type names neutralized with full backward
compatibility:EVO_*actions are nowROM_*
(ROM_CUSTOM_SETTING,ROM_QS_TILES,ROM_STATUS_BAR,ROM_LOCKSCREEN,
ROM_NAVIGATION,ROM_THEME,ROM_AMBIENT_AOD,ROM_NOTIFICATIONS,
ROM_BATCH) andSYSTEM_OPEN_GALAXY_STOREis now
SYSTEM_OPEN_DEVICE_STORE. Legacy@JsonNamesaliases keep every existing
saved automation, backup and execution record readable. - All user-facing strings (11 languages) reworded neutrally — the custom
ROM settings picker, the device-store action and the ROM-setting trigger no
longer advertise any product; per-locale translations re-verified. - Real device setting keys are preserved as protocol surface (
evo_*,
sysui_*,lineage_*prefixes) so the picker and the ROM-setting monitor
keep working against actual on-device settings providers.
Added
- Vendor-neutrality CI gate (
scripts/check_vendor_neutrality.py, wired
into the lint job with a self-test): any commercial ROM/OEM/device name
outside the protocol-allowlisted files fails CI, so vendor coupling cannot
silently return.
Quality evidence
The tag workflow gates publication on the following automated checks. Consult the exact tag run and validation record for results; these checks do not establish physical-device coverage:
- Android Lint (zero-tolerance: UnusedResources, MissingTranslation, ExtraTranslation,
UnusedIds, CheckResult, HardcodedText, TypographyDashes) and Detekt static analysis. - Catalog parity gates: every
TriggerTypeandActionTypeenum value must exist
exactly once in the builder picker (restricted entries are pinned explicitly). - Full unit-test suite, including Room migration, scheduler, lifecycle, and recovery
regression coverage. - Release build with R8 full shrinking, APK signature verification (v2/v3 schemes and
certificate-fingerprint match against the production keystore), 16 KB page-size
alignment check, zipalign verification, bundletool AAB validation, and Gradle
dependency verification (SHA-256 checksums for every artifact). - Tag hygiene: the tag must match the newest
CHANGELOG.mdentry, so the notes below
are the actual, reviewed change record for this release.
Install
- Download
NexaFlow-<version>.apkfrom the assets below and install it. - Android updates require a compatible version code and the same signing certificate.
Back up important tasks before upgrading. - Pre-release tags (
alpha/beta/rc) are marked as pre-releases automatically.
Documentation
NexaFlow v3.77.0
Added
- Capability-Adaptive Execution layer (Phase A) — a single semantic decision
point for device-state operations, replacing per-handler privilege guessing:
OperationRegistrydeclares typedOperationSpeccontracts and
CapabilityRouterselects the best available strategy per device.- 24 paired semantic operations across connectivity, display and audio
interruption (WIFI_GET_STATE/WIFI_SET_STATE,BLUETOOTH_*,
MOBILE_DATA_*,HOTSPOT_*,NFC_*,LOCATION_*,AIRPLANE_MODE_*,
ROTATION_*,BRIGHTNESS_GET/BRIGHTNESS_SET,SCREEN_TIMEOUT_*,
DND_*,DATA_SAVER_*), each with typed parameter schemas, risk,
idempotency, retry-safety, verification and compensation contracts. CapabilityRouterpicks the least-privileged available strategy using
explainable candidates — live availability, verified per-device evidence,
strategy health with bounded cooldowns, and explicit user policy — rather
than static privilege scores. Root is never chosen merely because it is
available.CapabilityEvidenceStoreandStrategyHealthTrackerrecord
verified successes, failures, latency and cooldowns per (operation,
strategy, device fingerprint).EnvironmentInvalidatorapplies targeted
invalidation from environment events: a Shizuku binder death invalidates
only Shizuku evidence, never a full rescan.- Honest
UNKNOWNoutcome: a transport timeout after a possible side
effect is reconciled by reading the actual device state through the
operation's paired GET instead of being reported as a definite failure or
retried blindly. Exactly one execution, then observation. - Strategies shipped:
AndroidApiStateStrategy(public framework APIs
only, with correct API-level guards),RootTypedStrategy(exclusively
through two new closedPrivilegedOperationshapes,SetServiceStateand
ReadSettingState— no workflow-supplied shell text), and
SettingsUserActionStrategy(truthfulPENDING_USER_ACTION, never fake
success). Shizuku typed, device-owner and OEM strategies are declared in
the contract but not selected until implemented. - Routing migration:
SYSTEM_WIFI,SYSTEM_BLUETOOTH,SYSTEM_LOCATION,
SYSTEM_AIRPLANE_MODE,SYSTEM_SCREEN_ROTATION,SYSTEM_BRIGHTNESS,
SYSTEM_SCREEN_TIMEOUT,SYSTEM_DND,SYSTEM_NFC,SYSTEM_HOTSPOT,
SYSTEM_MOBILE_DATAandSYSTEM_DATA_SAVERnow route through the unified
path first and fall back to their reviewed legacy handlers when the
operation is unsupported, so existing automations keep working unchanged. - Registry parity gates: every operation must name at least one shipped
strategy, every write operation must have a readable counterpart, writes
require verification, and no operation may be reachable only through
privileged strategies.
- 24 paired semantic operations across connectivity, display and audio
- Typed
PrivilegedOperationadditions (append-only wire contract):
SetServiceState(closedsvcradio services) andReadSettingState
(allowlisted reconciliation reads) keep the AIDL boundary free of free-form
shell input. - Documentation: new capability-adaptive-execution contract; README,
ARCHITECTURE and CAPABILITY_CATALOG updated to describe the unified decision
path truthfully.
Tests
CapabilityRouterTest(11 cases): least-privilege preference, privileged
opt-in gating, transport-only fallback,UNKNOWNreconciliation for both
matching and contradicting read-back, evidence recording, health-cooldown
deprioritization, unregistered-operation and missing-parameter rejection.SemanticActionMapperTest(7 cases): strict typed parsing — legacy toggles
keep their documented default only for pre-configVersionautomations,
unparseable booleans are rejected instead of defaulted, and every migrated
action type maps to its semantic operation.OperationRegistryParityTest(5 cases): the registry gates listed above.- Full module suites pass: 807 unit tests across
domain,core:execution
andcore:rom-integrationwith zero failures; Detekt, Lint and
assembleDebugare green.
Changed
CapabilityActionMapperprivileged-backend resolution and the legacy
handler paths remain in place for unmigrated actions;SystemControlleris
no longer on the execution path of migrated device-state operations.
Quality evidence
The tag workflow gates publication on the following automated checks. Consult the exact tag run and validation record for results; these checks do not establish physical-device coverage:
- Android Lint (zero-tolerance: UnusedResources, MissingTranslation, ExtraTranslation,
UnusedIds, CheckResult, HardcodedText, TypographyDashes) and Detekt static analysis. - Catalog parity gates: every
TriggerTypeandActionTypeenum value must exist
exactly once in the builder picker (restricted entries are pinned explicitly). - Full unit-test suite, including Room migration, scheduler, lifecycle, and recovery
regression coverage. - Release build with R8 full shrinking, APK signature verification (v2/v3 schemes and
certificate-fingerprint match against the production keystore), 16 KB page-size
alignment check, zipalign verification, bundletool AAB validation, and Gradle
dependency verification (SHA-256 checksums for every artifact). - Tag hygiene: the tag must match the newest
CHANGELOG.mdentry, so the notes below
are the actual, reviewed change record for this release.
Install
- Download
NexaFlow-<version>.apkfrom the assets below and install it. - Android updates require a compatible version code and the same signing certificate.
Back up important tasks before upgrading. - Pre-release tags (
alpha/beta/rc) are marked as pre-releases automatically.
Documentation
NexaFlow v3.76.0
Added
-
Wear OS companion app — a new
:wearmodule delivers a native Wear OS 3
watch companion that surfaces NexaFlow automations directly on the user's
wrist, enabling monitoring and execution without reaching for the phone.- Automation list screen (
AutomationListScreen): circular-display-optimised
ScalingLazyColumnpresenting every automation with its enable/disable state,
last-run outcome badge, and a dedicated "Run Now" button per card. While a
run command is in-flight the button is replaced by aCircularProgressIndicator
so the user always knows the watch is acting. - Automation detail screen (
AutomationDetailScreen): swipe-to-dismiss
detail view showing the full automation name, a timestamped last-run result
chip (success ✓ / failure ✗ with message excerpt), an enable/disable
ToggleButton, and a prominent "Run Now" button. - Navigation:
SwipeDismissableNavHostprovides the standard Wear OS
swipe-back gesture between the list and detail destinations. - Sealed UI state model (
WearUiState): four states —Connecting
(awaiting first sync),Empty(phone has no automations),Loaded(normal
view), andRunning(a manual run is in-flight) — drive the UI without
intermediate booleans or nullable fields. - Real-time data sync via the Wearable Data Layer:
WearSyncRepository
holds aStateFlow<List<WearAutomationDto>>that is updated by the
backgroundWearDataListenerServiceon everyDATA_CHANGEDevent without
polling or explicit refresh. - Watch → Phone command channel:
WearDataLayerClientdiscovers the
nearest connected phone node viaNodeClientand sends typed
MessageClientmessages. Run commands are encoded as the automation ID;
toggle commands encode"automationId:true/false"over a
WearableListenerServicebridge. - Hilt dependency injection in the watch app:
WearModuleprovides
singletonMessageClientandNodeClientinstances;WearViewModelis a
standard@HiltViewModel;WearDataListenerServiceuses
@AndroidEntryPoint. - String resources localised in all 11 supported locales:
en ar de es fr hi ja pt ru tr zh-rCN. - Companion APK bundled via
wearApp(project(":wear"))in:appso a
single Play Store install delivers both the phone and watch APKs.
- Automation list screen (
-
Phone-side Wear OS bridge (in
:app):WearSyncManager: subscribes toAutomationRepositoryand
HistoryRepositoryvia acombineflow, debounces rapid saves by 500 ms
to coalesce bulk operations, serialises the result toWearAutomationDto
JSON, and pushes it as an urgent DataItem to all connected watches. A
monotonicupdatedAttimestamp forces aDATA_CHANGEDdelivery even when
the automation list is unchanged, guaranteeing state convergence after a
watch reconnect.WearCommandListenerService: aWearableListenerServicedeclared in the
phone manifest with aMESSAGE_RECEIVEDfilter scoped to/nexaflow/
paths. UsesEntryPointAccessors(instead of@AndroidEntryPoint) for safe
Hilt injection in a platform-managed service. Routes run commands to
ExecutionEngine.forceRun()and toggle commands to
AutomationRepository.updateAutomationStatus()followed by
ExecutionEngine.notifyAutomationsChanged()so stateful monitors react
immediately.WearSyncManageris started inNexaFlowApplication.onCreate()inside the
existing best-effort startup block; failures are caught and logged without
impacting any other startup component.
-
Shared Wear OS protocol constants added to
AutomationIntents.kt
(WEAR_PATH_AUTOMATIONS,WEAR_PATH_RUN_COMMAND,WEAR_PATH_TOGGLE_COMMAND,
WEAR_KEY_PAYLOAD,WEAR_KEY_UPDATED_AT,WEAR_TOGGLE_SEPARATOR) as the
single authoritative source for the Data Layer communication contract on the
phone side, mirrored byWearProtocolin the watch module. -
New Gradle dependencies (
libs.versions.toml):com.google.android.gms:play-services-wearable:19.0.0— Data Layer API
(both modules).androidx.wear.compose:compose-material3:1.5.0-alpha26— Wear OS
Material 3 component library.androidx.wear.compose:compose-foundation:1.5.0-alpha26—ScalingLazyColumn
and watch-optimised layout primitives.androidx.wear.compose:compose-navigation:1.5.0-alpha26—
SwipeDismissableNavHost.org.mockito.kotlin:mockito-kotlin:5.4.0(test) — mock support for
WearDataLayerClientin unit tests.app.cash.turbine:turbine:1.2.0(test) —StateFlowassertion helpers.
Tests
WearAutomationDtoSerializationTest(7 cases): round-trip JSON
serialisation, null optional fields,ignoreUnknownKeysforward
compatibility, malformed JSON graceful degradation, empty-array handling,
state replacement on successive calls, and multi-DTO parsing.WearViewModelTest(5 cases): initialConnectingstate,Loaded
transition after first sync,Emptystate on empty push,runNow
command delegation verification,toggleEnabledcommand delegation
verification. UsesStandardTestDispatcherfor deterministic coroutine
control.WearSyncManagerDtoTest(4 cases): phone-side DTO round-trip
serialisation, nullable-field encoding, empty-list serialisation, and
lastRunMessagetruncation boundary.WearCommandProtocolTest(8 cases): toggle payload encoding fortrueand
false, separator parsing, invalid-boolean rejection, missing-separator
detection, and protocol path constant verification.
Validation
- Zero string parity problems across all 11 locales verified via
check_strings_parity.py(covers both:appand:wearresource trees). - Zero hardcoded non-English strings in shipped Kotlin sources verified via
check_hardcoded_text.py(425 sources clean). - Builder catalog parity verified clean (
CATALOG_PARITY: OK — 56 triggers, 176 actions) viaaudit_catalog_and_releases.py catalog. No new trigger or
action enum values were added in this release. - All 11 locale
values-*/strings.xmlfiles created for the:wearmodule
with exact key parity againstvalues/strings.xml.
Quality evidence
The tag workflow gates publication on the following automated checks. Consult the exact tag run and validation record for results; these checks do not establish physical-device coverage:
- Android Lint (zero-tolerance: UnusedResources, MissingTranslation, ExtraTranslation,
UnusedIds, CheckResult, HardcodedText, TypographyDashes) and Detekt static analysis. - Catalog parity gates: every
TriggerTypeandActionTypeenum value must exist
exactly once in the builder picker (restricted entries are pinned explicitly). - Full unit-test suite, including Room migration, scheduler, lifecycle, and recovery
regression coverage. - Release build with R8 full shrinking, APK signature verification (v2/v3 schemes and
certificate-fingerprint match against the production keystore), 16 KB page-size
alignment check, zipalign verification, bundletool AAB validation, and Gradle
dependency verification (SHA-256 checksums for every artifact). - Tag hygiene: the tag must match the newest
CHANGELOG.mdentry, so the notes below
are the actual, reviewed change record for this release.
Install
- Download
NexaFlow-<version>.apkfrom the assets below and install it. - Android updates require a compatible version code and the same signing certificate.
Back up important tasks before upgrading. - Pre-release tags (
alpha/beta/rc) are marked as pre-releases automatically.