feat(stopwatch): the foreground service, its silent notification and the receiver
The service is alive exactly while the stopwatch is not idle, and it is `specialUse` with the subtype spelled out — reusing `systemExempted` would have the app claim it is continuing alarm functionality, which it is not. No wake lock, ever: the notification carries the platform chronometer counting up from a base derived when it is posted and never stored, so the system draws the ticking and the process can sleep through it. Its channel is `IMPORTANCE_LOW` because nothing here ever alerts. The Lap, Pause, Resume and Reset buttons are broadcasts carrying no extras — the receiver reads the stored run rather than trusting an intent — and the body opens the Stopwatch tab. Boot, time change and package replacement all reach the third engine now, alongside the other two.
This commit is contained in:
@@ -34,6 +34,13 @@
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED" />
|
||||
|
||||
<!-- The stopwatch's foreground service. specialUse, not systemExempted:
|
||||
that type's justification is an app with an exact-alarm permission
|
||||
continuing alarm functionality in the background, and a stopwatch
|
||||
schedules nothing, wakes nothing and rings nothing. Claiming it would
|
||||
have the app tell the platform something untrue (M7 D3). -->
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
|
||||
|
||||
<!-- Keep the CPU awake for the length of a ring; the screen is the window's
|
||||
business, not this one's. -->
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
@@ -126,6 +133,27 @@
|
||||
android:name=".timer.receiver.TimerActionReceiver"
|
||||
android:exported="false" />
|
||||
|
||||
<!-- The stopwatch: one foreground service, up while the run is not
|
||||
idle. specialUse rather than systemExempted (M7 D3), and not
|
||||
shortService, which caps at ~3 minutes against a stopwatch that may
|
||||
run for hours. It holds no wake lock: there is no deadline to wake
|
||||
for, and the elapsed value is derived from a persisted monotonic
|
||||
anchor at read time. The <property> is API 31+ and ignored below. -->
|
||||
<service
|
||||
android:name=".stopwatch.service.StopwatchService"
|
||||
android:exported="false"
|
||||
android:foregroundServiceType="specialUse">
|
||||
<property
|
||||
android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
|
||||
android:value="stopwatch" />
|
||||
</service>
|
||||
|
||||
<!-- The stopwatch notification's buttons. Broadcasts rather than service
|
||||
starts, and they carry nothing: there is one stopwatch (M7 D16). -->
|
||||
<receiver
|
||||
android:name=".stopwatch.receiver.StopwatchActionReceiver"
|
||||
android:exported="false" />
|
||||
|
||||
<!-- Protected system broadcasts are delivered to unexported receivers —
|
||||
this is how androidx.work declares its own RescheduleReceiver.
|
||||
LOCKED_BOOT_COMPLETED is deliberately absent: the database and the
|
||||
|
||||
Reference in New Issue
Block a user