Background updates: reliable scheduling + consolidated permissions UI#135
Merged
Conversation
…ence The background "Update interval" setting (updateIntervalBackground, 5-360 min) was exposed in the UI as if it governed how often sensor values refresh, but it only drove the AndroidService work-timer's DeviceManager rebuild + MQTT reconnect. Actual background scanning ran on a self-restarting 60s listen loop (deviceDiscoveryFinished -> listenDevices_start), so the setting had no effect on scan/publish frequency (device-measured: continuous ~60s regardless). Make the setting real on Android: in the background service (daemon mode) stop self-restarting the listen loop; AndroidService::gotowork() already fires every updateIntervalBackground minutes and starts one ~60s listen window, so the radio now idles between windows. The foreground UI manager (m_daemonMode == false, on mobile and desktop) keeps re-arming, so the live view and continuous system-tray scanning are unchanged. HIL_BENCH_MODE keeps its continuous active scan. Desktop never reads this value (it scans continuously on mains power), so hide the interval picker on desktop and reword the desktop legend to stop implying an interval. Device-verified (LG V30 / Android 9 and S10e / Android 12): background scanning is one ~60s window per interval (5 min -> ~4 min idle; 10 min -> ~9 min idle), foreground stays continuous. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the AndroidService QTimer (a non-wakeup timerfd, deferred to doze maintenance windows — device-measured ~1-3h gaps in true deep doze) with a setAndAllowWhileIdle AlarmManager alarm scheduled from Java. The alarm fires through deep doze (unthrottled while the app is battery-Unrestricted), wakes the CPU, holds a 65s partial wakelock across the scan window, and re-enters C++ via a registered native (nativeOnWorkAlarm -> gotowork on the Qt thread), which reschedules the next alarm. Prototype for validating doze cadence; production should consider setExactAndAllowWhileIdle + USE_EXACT_ALARM for precise timing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Use setExactAndAllowWhileIdle (gated by canScheduleExactAlarms()) so the background refresh fires at the user's exact Update interval through deep doze, instead of setAndAllowWhileIdle which Android batches (~+50% drift, measured ~7.8min for a 5min setting). Declares SCHEDULE_EXACT_ALARM (auto-granted API 31-32, user-grantable 33+); degrades to the inexact AllowWhileIdle alarm when the permission isn't granted or a race throws SecurityException, so it never crashes and still pierces doze. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
On API 34+ SCHEDULE_EXACT_ALARM is denied by default, so the exact-alarm path silently fell back to inexact (~+50% interval drift). Surface it: PermissionManager gains exactAlarmPermission (canScheduleExactAlarms via JNT) + requestExactAlarmPermission (opens Settings -> Alarms & reminders via ACTION_REQUEST_SCHEDULE_EXACT_ALARM). Settings shows an 'Allow' row under the interval picker when background updates are on but the grant is missing; re-checked on resume so it clears after the user grants. No-op / auto-granted on API <=33 and non-Android. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The intent action used to send the user to the "Alarms & reminders"
settings screen was the AlarmManager constant name, which is not an
intent action — the real action is Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM
("android.settings.REQUEST_SCHEDULE_EXACT_ALARM"). With the old string,
startActivity() failed to resolve and the in-app "Allow exact alarms"
button silently did nothing. Verified on the Android 15 and Android 16
emulators that the corrected action opens the proper "Alarms & reminders
/ Allow setting alarms and reminders" screen.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the 2-step "background updates" popup and the standalone "Allow exact alarms" inline row in Settings with one dedicated page that walks the user through every permission needed for reliable background sensor refresh: - Background location (Android-mandated for BLE-in-background; runtime dialog). - Exact alarms (API 31+; opens the system "Alarms & reminders" screen). - Battery optimisation (new — one-tap REQUEST_IGNORE_BATTERY_OPTIMIZATIONS system dialog so Doze / app-standby don't defer background-work alarms). Each row shows live grant status (green ✓ / grey ✗) refreshed both on a short timer after a request returns and on activity resume, so the user sees the row flip as soon as they grant the permission and come back. Settings now navigates to this page (instead of the popup) from both the "Enable background updates" toggle ON path and the "Beta" inline button; when the user returns, settingsManager.systray reflects the background- location grant (preserves prior behaviour). A Connections handler on settingsManager.onSystrayChanged keeps the toggle visual state in sync with the underlying setting after the page sets it (the previous popup's imperative onClosed re-sync went away with it). Adds the JNI plumbing and manifest entry for battery-opt: - TheengsAndroidService.isIgnoringBatteryOptimizations() / .requestIgnoreBatteryOptimizations() - PermissionManager.checkBatteryOptimizationPermission() / .requestBatteryOptimizationPermission() with a Q_PROPERTY/NOTIFY pair so QML rebinds when the OS state changes. - AndroidManifest.xml: REQUEST_IGNORE_BATTERY_OPTIMIZATIONS (flagged as Play-policy-sensitive in a comment). - MobileApplication.qml onResume now also re-checks battery-opt alongside the existing exact-alarm re-check. Removes the now-superseded qml/popups/PopupBackgroundUpdates.qml and its Settings instance + onClosed handler. The old element_exact_alarm block in Settings.qml is gone — exact alarms now live on the page as part of the guided flow. Verified end-to-end on the Android 15 (API 35) and Android 16 (API 36) emulators: all three rows grant correctly and turn green, the foreground service runs, and the Settings toggle reflects the enabled state on return. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1technophile
added a commit
that referenced
this pull request
Jun 2, 2026
Documentation fell behind the 1.5.0 release train after PR #130. Fold the four user-facing PRs that landed since into the existing 1.5.0 section of the changelog and refresh the affected pages on the doc site. - use.md: note the new MQTT-down banner in the device list; replace the manual "Permissions/Battery/Unrestricted" walkthrough with the consolidated in-app Background updates screen (background location + exact alarms + battery-optimisation rows); document that the "Update interval" setting now actually drives the Android background scan cadence (one ~60 s window per interval, idle in between). - build.md: require libsecret-1-dev on Linux; add the new ENABLE_SECURE_STORAGE CMake option for QtKeychain-backed credential storage. - privacy.md: bump the last-updated date; note that broker credentials are persisted in the OS-managed secure store rather than plaintext settings. - CHANGELOG.md: under the existing [1.5.0] entry, add the MQTT-down banner, consolidated Background updates page, and AllowWhileIdle exact-alarm scheduler to Added; the scan-cadence fix and the ENABLE_MBEDTLS=OFF guard to Fixed; and credential storage to Security. PRs covered: #131 (MQTT sentinels), #132 (credential secure storage), #133 (background scan cadence), #135 (background-alarm-doze train, including the consolidated Background updates page and the exact AllowWhileIdle scheduler). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1technophile
added a commit
that referenced
this pull request
Jun 6, 2026
Bump the 1.5.0 release date to 2026-06-06 and fold in the user-facing changes that landed between #130 and the cut: TheengsDecoder v2.3.0 (#137), MQTT sentinels + sampling caption (#131), credential secure storage (#132), background-update scheduling and consolidated permissions UI (#133, #135), the About-screen decoder version and build number (#139), the iOS mbedTLS static-link fix (#138), and the device_bm26 ENABLE_MBEDTLS guard (#134). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3 tasks
1technophile
added a commit
that referenced
this pull request
Jun 6, 2026
Bump the 1.5.0 release date to 2026-06-06 and fold in the user-facing changes that landed between #130 and the cut: TheengsDecoder v2.3.0 (#137), MQTT sentinels + sampling caption (#131), credential secure storage (#132), background-update scheduling and consolidated permissions UI (#133, #135), the About-screen decoder version and build number (#139), the iOS mbedTLS static-link fix (#138), and the device_bm26 ENABLE_MBEDTLS guard (#134). Co-authored-by: Florian <1technophile@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two-part change to make BLE background-sensor refresh actually fire when the
phone is in Doze / app-standby, and to make the permission story for it
discoverable rather than scattered across a popup and an inline Settings row.
Scheduling — fire on time through Doze
(
cad508e).setAndAllowWhileIdleAlarmManageralarm, briefly holding a
WAKE_LOCKso the scan window actually runs in deepdoze (
68617e4,36e049f).SCHEDULE_EXACT_ALARMisgranted; fall back to inexact otherwise. Prompt the user to grant it on
Android 12+ where it is not auto-granted (
3290db6).AlarmManagerconstant name(
android.app.action.REQUEST_SCHEDULE_EXACT_ALARM), which is not a validintent action — so
startActivitysilently failed and the in-app"Allow exact alarms" button did nothing. Corrected to
Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM(9e8aaf2).Permission UX — one page, every required toggle
BackgroundPermissions.qmlscreen with three live-status rows(✓/✗ + per-row "fix" action):
runtime dialog.
REQUEST_IGNORE_BATTERY_OPTIMIZATIONSsystem dialog so Doze /app-standby do not defer the work alarms. Manifest entry is flagged in a
comment as Play-policy-sensitive.
toggle ON-path and the inline "Beta" button, replacing the 2-step
PopupBackgroundUpdatespopup and the standaloneelement_exact_alarmrow (both removed).
resume, so they flip green the moment the user grants the permission and
comes back. A
Connections { onSystrayChanged }keeps the Settings togglevisual in sync with the underlying setting after the page sets it (the
previous popup's imperative
onClosedre-sync went away with it).TheengsAndroidService.isIgnoringBatteryOptimizations/requestIgnoreBatteryOptimizations;PermissionManagerexposes aQ_PROPERTY+NOTIFYpair so QML rebinds when the OS state changes(
5ff9623).Test plan
proper system surface → return → row flips green; foreground service
runs; Settings toggle reflects enabled state.
to the dedicated "Alarms & reminders → Allow setting alarms and
reminders" screen (proving the action-string fix).
adb logcat Qt:V Theengs:V *:Sacross the walkthrough.adb shell dumpsys deviceidle force-idle)— sanity-check that the AllowWhileIdle alarm fires through deep doze
with the battery-opt exemption granted.
OPPO / Huawei) that the "About battery savers" link + autolaunch
guidance is sufficient.
🤖 Generated with Claude Code