Skip to content

Releases: Alaa91H/NexaFlow

NexaFlow v3.85.1

Choose a tag to compare

@github-actions github-actions released this 21 Sep 23:50

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 TriggerType and ActionType enum 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.md entry, so the notes below
    are the actual, reviewed change record for this release.

Install

  • Download NexaFlow-<version>.apk from 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

Choose a tag to compare

@github-actions github-actions released this 21 Sep 17:51

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 the DATA_CHANGED intent 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. A onDataChanged handler 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 exact wear://* URI shape the cache read parses, and DTO round-trip
    through the same Json decoder 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 TriggerType and ActionType enum 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.md entry, so the notes below
    are the actual, reviewed change record for this release.

Install

  • Download NexaFlow-<version>.apk from 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

Choose a tag to compare

@github-actions github-actions released this 21 Sep 16:41

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 dedicated TriggerMatchPolicy centralizes 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. CHARGER and
    AIRPLANE_MODE are classified as definitive-false-when-false state reads
    (like TIME and DEVICE): a false answer is a verified current state and
    an unreadable state surfaces as Unknown, 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:00 is 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 TriggerType and ActionType enum 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.md entry, so the notes below
    are the actual, reviewed change record for this release.

Install

  • Download NexaFlow-<version>.apk from 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

Choose a tag to compare

@github-actions github-actions released this 21 Sep 13:20

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-forget DataItem push 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-automation triggerMatch policy — 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 (via TriggerStateEvaluator) 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 TriggerType and ActionType enum 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.md entry, so the notes below
    are the actual, reviewed change record for this release.

Install

  • Download NexaFlow-<version>.apk from 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

Choose a tag to compare

@github-actions github-actions released this 21 Sep 09:15

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 — closed pm/am argv 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 contributes PackageManager enabled-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_DATA is registered with
    UNSUPPORTED compensation (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

  • OperationRegistry grows 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 TriggerType and ActionType enum 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.md entry, so the notes below
    are the actual, reviewed change record for this release.

Install

  • Download NexaFlow-<version>.apk from 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

Choose a tag to compare

@github-actions github-actions released this 21 Sep 07:37

Added

  • Shizuku typed strategy — Phase B of the capability-adaptive migration.
    ShizukuTypedStrategy routes semantic operations through the closed
    PrivilegedOperation algebra via PrivilegedRunner.runShizukuOperation
    (UserService AIDL, direct argv, never sh -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. EnvironmentEventWiring connects the
    semantic-layer EnvironmentEventBus to the actual Shizuku lifecycle
    listener: binder received, binder dead, and UserService
    connected/disconnected transitions publish targeted
    ShizukuStateChanged events. The EnvironmentInvalidator erases 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 as UNKNOWN and
    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 TriggerType and ActionType enum 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.md entry, so the notes below
    are the actual, reviewed change record for this release.

Install

  • Download NexaFlow-<version>.apk from 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

Choose a tag to compare

@github-actions github-actions released this 21 Sep 05:55

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 racesaveAutomation read 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 extra su spawn 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.

Tests

  • CapabilityGateFreshnessTest (4 tests): stale snapshot admits, startup
    race admits, fresh block records and schedules a refresh, fresh admissible
    runs.
  • SaveAdmissionFreshnessTest (2 tests): freshSnapshot returns 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
    and domain — 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 TriggerType and ActionType enum 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.md entry, so the notes below
    are the actual, reviewed change record for this release.

Install

  • Download NexaFlow-<version>.apk from 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

Choose a tag to compare

@github-actions github-actions released this 21 Sep 00:04

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:
    • RomFamily redefined 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.
    • RomDetectionMatrix keeps every detection fingerprint (version
      properties, brand constraints, manufacturer fallbacks) as protocol evidence
      in one reviewed table, now mapping to the neutral tiers.
    • Files renamed: EvolutionXSettingsBridgeCustomSettingsBridge,
      EvolverCatalogRomSettingCatalog, 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 now ROM_*
      (ROM_CUSTOM_SETTING, ROM_QS_TILES, ROM_STATUS_BAR, ROM_LOCKSCREEN,
      ROM_NAVIGATION, ROM_THEME, ROM_AMBIENT_AOD, ROM_NOTIFICATIONS,
      ROM_BATCH) and SYSTEM_OPEN_GALAXY_STORE is now
      SYSTEM_OPEN_DEVICE_STORE. Legacy @JsonNames aliases 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 TriggerType and ActionType enum 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.md entry, so the notes below
    are the actual, reviewed change record for this release.

Install

  • Download NexaFlow-<version>.apk from 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

Choose a tag to compare

@github-actions github-actions released this 20 Sep 20:58

Added

  • Capability-Adaptive Execution layer (Phase A) — a single semantic decision
    point for device-state operations, replacing per-handler privilege guessing:
    OperationRegistry declares typed OperationSpec contracts and
    CapabilityRouter selects 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.
    • CapabilityRouter picks 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.
    • CapabilityEvidenceStore and StrategyHealthTracker record
      verified successes, failures, latency and cooldowns per (operation,
      strategy, device fingerprint). EnvironmentInvalidator applies targeted
      invalidation from environment events: a Shizuku binder death invalidates
      only Shizuku evidence, never a full rescan.
    • Honest UNKNOWN outcome: 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 closed PrivilegedOperation shapes, SetServiceState and
      ReadSettingState — no workflow-supplied shell text), and
      SettingsUserActionStrategy (truthful PENDING_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_DATA and SYSTEM_DATA_SAVER now 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.
  • Typed PrivilegedOperation additions (append-only wire contract):
    SetServiceState (closed svc radio services) and ReadSettingState
    (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, UNKNOWN reconciliation 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-configVersion automations,
    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
    and core:rom-integration with zero failures; Detekt, Lint and
    assembleDebug are green.

Changed

  • CapabilityActionMapper privileged-backend resolution and the legacy
    handler paths remain in place for unmigrated actions; SystemController is
    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 TriggerType and ActionType enum 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.md entry, so the notes below
    are the actual, reviewed change record for this release.

Install

  • Download NexaFlow-<version>.apk from 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

Choose a tag to compare

@github-actions github-actions released this 20 Sep 16:47

Added

  • Wear OS companion app — a new :wear module 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
      ScalingLazyColumn presenting 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 a CircularProgressIndicator
      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: SwipeDismissableNavHost provides 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), and Running (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 a StateFlow<List<WearAutomationDto>> that is updated by the
      background WearDataListenerService on every DATA_CHANGED event without
      polling or explicit refresh.
    • Watch → Phone command channel: WearDataLayerClient discovers the
      nearest connected phone node via NodeClient and sends typed
      MessageClient messages. Run commands are encoded as the automation ID;
      toggle commands encode "automationId:true/false" over a
      WearableListenerService bridge.
    • Hilt dependency injection in the watch app: WearModule provides
      singleton MessageClient and NodeClient instances; WearViewModel is a
      standard @HiltViewModel; WearDataListenerService uses
      @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 :app so a
      single Play Store install delivers both the phone and watch APKs.
  • Phone-side Wear OS bridge (in :app):

    • WearSyncManager: subscribes to AutomationRepository and
      HistoryRepository via a combine flow, debounces rapid saves by 500 ms
      to coalesce bulk operations, serialises the result to WearAutomationDto
      JSON, and pushes it as an urgent DataItem to all connected watches. A
      monotonic updatedAt timestamp forces a DATA_CHANGED delivery even when
      the automation list is unchanged, guaranteeing state convergence after a
      watch reconnect.
    • WearCommandListenerService: a WearableListenerService declared in the
      phone manifest with a MESSAGE_RECEIVED filter scoped to /nexaflow/
      paths. Uses EntryPointAccessors (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.
    • WearSyncManager is started in NexaFlowApplication.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 by WearProtocol in 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-alpha26ScalingLazyColumn
      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
      WearDataLayerClient in unit tests.
    • app.cash.turbine:turbine:1.2.0 (test) — StateFlow assertion helpers.

Tests

  • WearAutomationDtoSerializationTest (7 cases): round-trip JSON
    serialisation, null optional fields, ignoreUnknownKeys forward
    compatibility, malformed JSON graceful degradation, empty-array handling,
    state replacement on successive calls, and multi-DTO parsing.
  • WearViewModelTest (5 cases): initial Connecting state, Loaded
    transition after first sync, Empty state on empty push, runNow
    command delegation verification, toggleEnabled command delegation
    verification. Uses StandardTestDispatcher for deterministic coroutine
    control.
  • WearSyncManagerDtoTest (4 cases): phone-side DTO round-trip
    serialisation, nullable-field encoding, empty-list serialisation, and
    lastRunMessage truncation boundary.
  • WearCommandProtocolTest (8 cases): toggle payload encoding for true and
    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 :app and :wear resource 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) via audit_catalog_and_releases.py catalog. No new trigger or
    action enum values were added in this release.
  • All 11 locale values-*/strings.xml files created for the :wear module
    with exact key parity against values/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 TriggerType and ActionType enum 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.md entry, so the notes below
    are the actual, reviewed change record for this release.

Install

  • Download NexaFlow-<version>.apk from 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