Skip to content

feat(controller): in-app OTA update progress dialog + cancel (F15, PR B)#32

Merged
luisguzman-adfa merged 3 commits into
mainfrom
feat/ota-updater-progress-ux
Jun 23, 2026
Merged

feat(controller): in-app OTA update progress dialog + cancel (F15, PR B)#32
luisguzman-adfa merged 3 commits into
mainfrom
feat/ota-updater-progress-ux

Conversation

@luisguzman-adfa

@luisguzman-adfa luisguzman-adfa commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

PR B — in-app OTA update progress UX (stacked on #30 / PR A)

Builds the user-facing half of the OTA updater on top of PR A (feat/ota-updater-security-redesign, #30). This branch is based on it, so the diff here is PR B only.

What this adds

A modal progress dialog that appears when an update download starts, showing live progress and a Cancel/Install flow. The DownloadManager system notification is kept alongside it.

State machine: IDLE → DOWNLOADING → VERIFYING → READY → INSTALLING (or ERROR).

  • Downloading: determinate bar + % while the total size is known; indeterminate otherwise. Cancel removes the download (DownloadManager.remove(id)).
  • Verifying: on completion the APK is checked for the same-signer certificate (F15) before anything is offered.
  • Ready: "✓ Signature verified — ready to install"; the Install button launches the system installer.
  • Error: surfaces verify/download failures in the dialog.

Clean Architecture slice (org.iiab.controller.update)

  • domainDownloadProgress (pure value object), OtaDownloadGateway (port: query/cancel). Unit-tested, no Android deps.
  • dataDownloadManagerGateway implements the port over DownloadManager (COLUMN_STATUS / bytes; remove() to cancel).
  • presentationUpdateUiState (with pure fromDownload mapping), UpdateViewModel (androidx.lifecycle, polls ~400ms, cancel), UpdateViewModelFactory (manual DI, mirrors the other slices).

MainActivity wiring

  • startDownload: track(id) + show dialog after enqueue.
  • downloadReceiver: on success → verifyDownloadedApk()onReady() / onError().
  • installApk() split into verifyDownloadedApk() (exists + same-cert signature) and launchInstaller() (unknown-sources check + FileProvider install), driven by the dialog's Install button.

i18n

9 new strings added to all 6 locales (en/es/fr/pt/hi/ru), apostrophes escaped for AAPT2.

Tests

DownloadProgressTest (percent clamp/round, indeterminate, terminal, negative clamp) and UpdateUiStateTest (running→downloading, indeterminate, success→verifying, failed→error). Pure JVM.

Verification done locally

Brace balance, all 6 string XMLs parse, and all new R.string/R.id/R.layout refs resolve. Full lint/compile via CI gate.

Author/copyright: AppDevForAll.

…X (PR B)

First piece of PR B (UpdateViewModel + in-app progress/cancel/state UX, on top of
PR A #30). Pure domain DownloadProgress (status + downloaded/total bytes, percent
with clamping, indeterminate + terminal helpers), unit-tested. ViewModel, data
source (DownloadManager query), cancel, and the in-app progress UI follow.
…ress (PR B)

Presentation/data slice for PR B (on top of PR A #30), behavior-neutral until wired:
- domain: OtaDownloadGateway port (query progress / cancel).
- data: DownloadManagerGateway (queries DownloadManager COLUMN_STATUS / bytes; remove() to cancel).
- presentation: UpdateUiState (IDLE/DOWNLOADING/VERIFYING/READY/INSTALLING/ERROR + percent,
  with pure fromDownload mapping) + UpdateViewModel (polls ~400ms while downloading; cancel)
  + UpdateViewModelFactory. Unit-tested (UpdateUiStateTest + DownloadProgressTest).

Next: modal progress dialog layout + MainActivity wiring (keep system notification).
Wires the PR B slice into the real OTA flow (modal dialog; system notification kept):
- startDownload: track(id) + show modal dialog after enqueue.
- downloadReceiver: on success -> verifyDownloadedApk() -> VM.onReady() (or onError).
- split installApk() into verifyDownloadedApk() (exists + same-cert signature) and
  launchInstaller() (unknown-sources check + FileProvider install), driven by the
  dialog's Install button; VM.onInstalling() on launch.
- dialog: determinate bar + % while downloading, indeterminate for verify/install,
  '✓ Signature verified' ready state; Cancel -> VM.cancel() -> DownloadManager.remove(id).
- new layout dialog_ota_progress.xml; 9 strings x 6 locales (escaped).
@luisguzman-adfa luisguzman-adfa changed the base branch from feat/ota-updater-security-redesign to main June 23, 2026 19:22
@luisguzman-adfa luisguzman-adfa marked this pull request as draft June 23, 2026 19:41
@luisguzman-adfa luisguzman-adfa marked this pull request as ready for review June 23, 2026 19:41
@luisguzman-adfa luisguzman-adfa merged commit ec5670a into main Jun 23, 2026
@luisguzman-adfa luisguzman-adfa deleted the feat/ota-updater-progress-ux branch June 24, 2026 02:12
luisguzman-adfa added a commit that referenced this pull request Jun 24, 2026
- Status banner: Phase 0 done + Phase 1 core-complete; Phase 2 not started
  (~37 raw threads); Phase 3 partial (slices land but god classes grew —
  DeployFragment ~3022, MainActivity ~2384); M15 done, M8/M9 open.
- Phase 1 line: F15 A+B (#30/#32) + rootfs validation (#31) + integrity (#37) done.
- Integrity/writer entry: marked DONE via #37 (was 'next PR').
- F4 + M7: confirmed mitigated by inspection (onPause teardown + remove-before-post).
- Lint workaround: added root-cause analysis with concrete carve targets
  (addNewTerminalSession ~727 LOC; DeployFragment bind* methods) for D1/F1.

Docs only; no code change.
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