Commit Graph
33 Commits
Author SHA1 Message Date
darken d7988189a0 fix(reaction): Stamp connect times from the ACL broadcast
The connection timestamp cache was only maintained while the connected-devices
flow had a subscriber. If the process died while a device stayed connected and
that device then disconnected and reconnected with nothing running, the
restarted collection found the old entry still keyed by a currently-connected
address, kept it through the prune, and reported the original connect time —
so the popup age check rejected an arbitrarily old connection.

The ACL broadcasts arrive at a manifest-registered receiver that wakes the
process regardless of any flow subscription, so the stamp is taken there
instead: connect stamps (keeping an existing one, which is the earlier and
therefore truer time), disconnect drops the entry. The flow keeps its own
stamp-on-first-sight and prune as a backstop for the force-stopped state and
missed broadcasts.

ACL_DISCONNECTED was already in the receiver's expected actions but was never
registered in the manifest. It does not start the monitor: a disconnect is not
a reason to start monitoring, and the start triggers here are deliberately
conservative.
2026-08-31 15:54:51 +02:00
darken 971fcbd34c fix(upgrade): Add a persistent acknowledgement safety net for Play purchases
Play auto-refunds (and revokes) purchases not acknowledged within 3 days.
The in-process ack machinery covers every case where the process lives
long enough; what it cannot cover is a process death around the Play
sheet (aggressive OEM task killers) followed by the user not reopening
the app before the deadline.

Add a gplay-only WorkManager safety net:
- PurchaseAckWorker: self-completing sweep via a new bounded
  BillingManager.ensureAllAcknowledged() that refreshes and acknowledges
  in the same coroutine (the reactive ack collector is async, so a worker
  cannot prove its acks happened through it). Retries with exponential
  backoff until the purchase's refund deadline, then gives up visibly.
- PurchaseAckScheduler: two unique work identities. A launch watch
  (REPLACE, armed and awaited before launchBillingFlow with a 30min delay
  so it cannot complete while the user is still in the sheet) and a
  discovered-purchase rescue (KEEP, 1min delay, armed directly from an
  ack pass that finds unacknowledged purchases, pre-attempt). Separate
  identities so a new purchase flow can never displace a pending rescue.
  Both triggers are fail-open: a broken WorkManager never blocks a
  purchase or an ack. WorkManager resolves via Provider at first arm so
  eager Application-time construction of the billing stack cannot
  trigger WorkManager's on-demand initialization prematurely.
- Nothing cancels the work from the foreground path: an ack pass can see
  zero unacked purchases while the sheet is still open, so the worker
  completes itself after its own reconciliation instead.

The ack pass now runs under a mutex (the worker sweep and the reactive
collector would otherwise race the token bookkeeping) and reports
per-outcome counts for the sweep result mapping.

This is a port of d4rken-org/sdmaid-se#2685; the ported sources are
byte-identical to the donor apart from the package rename.

CAPod had no explicit WorkManager wiring at all (work-runtime only
arrived transitively through Glance), so this also adds it:
- addWorkerManager() pinning androidx.work 2.7.1, the version already
  resolved via Glance, plus androidx.hilt:hilt-work and its KSP
  compiler. work-runtime-ktx is required at 2.7.1: CoroutineWorker,
  Operation.await, OneTimeWorkRequestBuilder and workDataOf all still
  live in the ktx artifact at that version. androidx.hilt moves 1.0.0 ->
  1.2.0 (by conflict resolution) because 1.0.0's hilt-compiler ships no
  KSP SymbolProcessorProvider, so @HiltWorker would generate nothing.
- WorkManagerModule providing the singleton WorkManager.
- App implements Configuration.Provider with the injected
  HiltWorkerFactory. WorkManager 2.7.1 still declares that interface as
  getWorkManagerConfiguration(), not the later property form.
- The manifest removes androidx.work's startup initializer so the
  on-demand configuration is the one that takes effect.

FOSS stays untouched behaviour-wise: all new billing types live in
src/gplay, workers need no manifest entry, and the worker factory
resolves the worker only in gplay variants.
2026-08-18 17:55:19 +02:00
darken acc6e92b2d feat(tile): Add ANC Quick Settings tile 2026-05-03 10:58:05 +02:00
darken 86b685f28b feat(widget): Add ANC control widget
New home-screen widget that toggles AirPods ANC modes (Off / ANC / Transparency / Adaptive) directly, with six adaptive layouts that pick based on widget size (QUAD_CORNERS, ROW_ICONS, COLUMN_ICONS, GRID_2X2, ROW, COLUMN). Consolidated battery+ANC configuration into a single ViewModel that detects widget type from AppWidgetManager. ACTIVE state uses Material3 secondaryContainer/onSecondaryContainer for guaranteed contrast. Includes live config preview, preview subtitle, stale-selection guard, device-label toggle, and aligned icons with the app's AncModeSelector.
2026-04-17 20:10:48 +02:00
darken 3423786f06 chore: Remove redundant package name from manifest 2026-03-09 17:41:08 +01:00
darken b609c1aced feat(support): Add contact support form and enhanced debug recorder
Add structured contact form with category selection (Question/Feature/Bug), description with word count validation, expected behavior field for bugs, and debug log picker with inline recording.

Enhance RecorderActivity with full-screen hero layout, file list, Share/Keep/Discard actions. Migrate debug logs from flat files to session directories in external files dir. Add DebugLogZipper, EmailTool attachment support, log folder size display, and clear stored logs.
2026-03-03 13:20:31 +01:00
darken 12d2c4dd06 fix: Pre-release cleanup of manifest, resource leaks, and dependencies
- Fix BleScanResultReceiver package name in manifest (.bluetooth → .common.bluetooth)
- Fix HandlerThread leak in BluetoothManager2 when registerReceiver() throws
- Cache battery values in MonitorNotifications to match hardening pattern
- Remove duplicate fragment-ktx dependency and align fragment-testing version
- Remove deprecated lifecycle-extensions dependency
2026-02-09 15:50:39 +01:00
darken ebfffb1536 fix: Replace WorkManager with ForegroundService to eliminate excessive wakelocks
Replace MonitorWorker (CoroutineWorker) with MonitorService (ForegroundService)
to eliminate persistent ProcessorForegroundLck wakelock reported in Android Vitals.
Add BootCompletedReceiver for post-reboot auto-start.
Remove WorkManager dependency entirely.
2026-02-08 14:19:11 +01:00
darken 49fc0f018a Implemented widget configuration for multiple profiles 2025-09-29 19:29:43 +02:00
darken be8f4919c8 Merge main and common module to simplify. 2025-09-29 13:36:43 +02:00
darken 79ec3ba932 Remove obsolete configuration in manifest 2025-05-14 21:04:28 +02:00
darken 3eaf99390e Record debug logs without foreground service
Some overhaul of log recording to get rid of the `FOREGROUND_SERVICE_SPECIAL_USE` which is a headache with Google
2024-09-23 15:05:11 +02:00
darken 0ee7915e31 Fix WorkManager init crash
```
Caused by java.lang.IllegalStateException: WorkManager is not initialized properly.  You have explicitly disabled WorkManagerInitializer in your manifest, have not manually called WorkManager#initialize at this point, and your Application does not implement Configuration.Provider.
  at androidx.work.impl.WorkManagerImpl.getInstance (WorkManagerImpl.java)
  at androidx.work.impl.foreground.SystemForegroundDispatcher.<init> (SystemForegroundDispatcher.java)
  at androidx.work.impl.foreground.SystemForegroundService.initializeDispatcher (SystemForegroundService.java)
  at androidx.work.impl.foreground.SystemForegroundService.onCreate (SystemForegroundService.java)
  at android.app.ActivityThread.handleCreateService (ActivityThread.java:4726)
```
2024-09-23 14:12:25 +02:00
darken 0c8b121c2c Request FOREGROUND_SERVICE_SPECIAL_USE for debug log service 2023-10-28 19:50:56 +02:00
darken 06e67e04ac Move permission 2023-10-28 17:58:09 +02:00
Matthias Urhahn 0fc9716f06 Only apply Bugsnag to gplay build flavor (#88)
* wip

* Setup bugsnag only in gplay builds.

* Bugsnag does not support uploading mapping files or build information from library modules. This should be done from the application module which produces your APK instead.

* Only apply Bugsnag plugin for the right flavors.

* Run unit tests in debug, otherwise we run issues requiring api keys in the env
2023-02-01 11:17:50 +01:00
darken 70ceb389b5 Move shared permissions into the common module. 2023-01-25 14:44:38 +01:00
GitGitro e90ab95cd0 add monochrome icon, closes #50,closes #23 2022-11-07 15:31:31 +01:00
darken b9f4992a33 A CAPod widget, oh my! ¯\_(ツ)_/¯ 2022-11-05 11:53:09 +01:00
darken 2d96822014 Add request for POST_NOTIFICATIONS on Android 13.
Closes #29
2022-09-19 22:26:43 +02:00
darken 87bef9cb9c Icon and reintroduce splash screen 2022-09-14 18:00:18 +02:00
darken 2210561af3 Refactoring 2022-09-14 18:00:18 +02:00
darken 688748da36 Go multi-module: app-common, app-phone, app-wear 2022-09-14 18:00:18 +02:00
darken d5d2ae784c Add popup via system alert window. 2022-01-25 09:59:57 +01:00
darken 07842fa8df Add Gplay and FOSS upgrade scaffolding 2022-01-16 22:37:03 +01:00
darken fb408aa455 Icon, Splash and Theme changes. 2022-01-07 17:11:01 +01:00
darken c706747f11 Add ignore battery optimizations if monitor mode is ALWAYS 2022-01-07 14:43:00 +01:00
darken 4405faa907 Handle permissions on < Android 12 2022-01-05 12:14:34 +01:00
darken 77486d85d8 Fix activity dupe when opening via notification 2022-01-05 09:42:43 +01:00
darken 022e0c7405 Pod status cards, mvp 2021-12-31 17:35:08 +01:00
darken 88278625f1 Rename CAP -> CAPod 2021-12-29 22:30:49 +01:00
darken 817c65ee3b Adds debug log recording. 2021-12-29 22:18:53 +01:00
darken 443af25fce POC, decoding works. 2021-12-28 17:11:50 +01:00