feat(sync): disable automatic sync by default#184
Conversation
Android sync silently no-ops for most users because the app-scoped data directory (Android/data/.../files/sync/) is inaccessible to Syncthing and other sync clients since Android 11 scoped storage restrictions. Running the 15-minute scheduler in this state wastes battery and risks OOM crashes (see aw-server-rust#630). Gate SyncScheduler.start() and SyncAlarmReceiver behind AWPreferences.isSyncEnabled() (default: false). setSyncEnabled(true) is the hook for a future settings toggle or Storage Access Framework setup flow. Closes #1357 (partial — disables auto-sync; SAF setup flow is follow-up)
Greptile SummaryThis PR disables Android sync by default and adds cleanup for stale sync alarms. The main changes are:
Confidence Score: 5/5This looks safe to merge.
Important Files Changed
Reviews (2): Last reviewed commit: "fix(sync): cancel stale AlarmManager ala..." | Re-trigger Greptile |
| if (!AWPreferences(context).isSyncEnabled()) { | ||
| Log.i(TAG, "Sync is disabled; skipping alarm-triggered sync") | ||
| return | ||
| } |
There was a problem hiding this comment.
Disabled Sync Leaves Alarm Armed
When an older build or a previous enabled session has already registered the repeating wakeup alarm, this branch skips the sync work but leaves that alarm active. Because SyncScheduler.stop() does not cancel the AlarmManager fallback, the app can keep waking every 15 minutes and logging this path even though sync is now disabled.
There was a problem hiding this comment.
Fixed in 1d8d23a: added SyncScheduler.cancelAlarm(context) to the disabled-sync branch in SyncAlarmReceiver. When the alarm fires but sync is off, we now cancel the AlarmManager wakeup via FLAG_NO_CREATE PendingIntent retrieval + am.cancel(), so no further 15-minute wakeups occur. The cancel logic lives in a new SyncScheduler.companion object to keep the PendingIntent construction in one place.
When the alarm fires but sync is disabled (e.g. after a downgrade or before the user enables the pref), cancel the alarm via SyncScheduler.cancelAlarm() instead of just skipping. Addresses Greptile P1: disabled sync left the wakeup alarm armed, causing 15-minute wake-ups that silently no-op.
|
@greptileai review |
… Play Store upload) (#190) * fix: remove FOREGROUND_SERVICE_DATA_SYNC permission + service type Sync is disabled by default (#184) and not yet demonstrable, so the Google Play Console FOREGROUND_SERVICE_DATA_SYNC declaration (which requires a video demo) was blocking the v0.14.0 Play Store upload. Remove: - FOREGROUND_SERVICE_DATA_SYNC uses-permission from AndroidManifest.xml - android:foregroundServiceType="dataSync" from BackgroundService declaration - ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC from startForeground() call The base FOREGROUND_SERVICE permission is preserved for the monitoring service. Re-add the data_sync type and permission when sync is actually implemented and demonstrable. Closes #189 (item 1) Unblocks v0.14.0 Play Store production upload * fix: use FOREGROUND_SERVICE_TYPE_SPECIAL_USE on Android 14+ On Android 14+ (API 34+) with targetSdk 35, startForeground() requires a valid foreground service type declared in the manifest. Passing type 0 with no foregroundServiceType attribute throws MissingForegroundServiceTypeException at runtime, crashing BackgroundService on any Android 14+ device. FOREGROUND_SERVICE_TYPE_SPECIAL_USE is the correct type for ActivityWatch's local HTTP server use case — it doesn't fit the 2024/2025 taxonomy (camera, microphone, location, health, etc.) and Google added specialUse specifically for this situation. The Play Store form for specialUse requires a text description (no demo video), so this unblocks the v0.14.0 upload. Changes: - Add FOREGROUND_SERVICE_SPECIAL_USE permission - Declare foregroundServiceType='specialUse' on BackgroundService - Pass ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE on API 34+, 0 otherwise * fix: add PROPERTY_SPECIAL_USE_FGS_SUBTYPE manifest property Greptile flagged that specialUse without a subtype property can leave Play review without a machine-readable rationale. The property documents AW's use case (local on-device HTTP server for the web UI) directly in the manifest, aligned with the Play Console declaration form.
Background
Closes ActivityWatch/activitywatch#1357 (partial — addresses the default-off requirement; Storage Access Framework setup flow is a follow-up).
Problem
SyncSchedulerfires every 15 minutes unconditionally, but Android sync is effectively broken for most users:Android/data/net.activitywatch.android/files/sync/) is app-scoped storage, inaccessible to Syncthing and other sync clients since Android 11 scoped storage restrictions.pull_all()silently no-ops (no remote db files found).pushworks, but data stays trapped on the phone.Changes
AWPreferences.kt— addsisSyncEnabled()(default:false) andsetSyncEnabled(Boolean). Thefalsedefault means new installs won't start the scheduler automatically.setSyncEnabled(true)is the hook for a future settings toggle or Storage Access Framework setup flow.BackgroundService.kt— gatessyncScheduler.start()onprefs.isSyncEnabled(). If disabled, logs a message instead of starting the 15-minute chain.SyncAlarmReceiver.kt— gates the AlarmManager fallback path on the same preference. Without this, an alarm registered before a downgrade/reinstall could still fire sync even with the new default.What's not in this PR
Testing
AWPreferences.isSyncEnabled()returnsfalse→ scheduler never starts.syncEnabledis absent in SharedPreferences → samefalsedefault applies.setSyncEnabled(true)→ scheduler starts on nextBackgroundService.onStartCommand().