fix: Guard MonitorService start against missing Bluetooth permissions

This commit is contained in:
darken
2026-02-09 14:24:45 +01:00
committed by Matthias Urhahn
parent 1af8743533
commit cfed733fa7
2 changed files with 15 additions and 5 deletions
+4 -5
View File
@@ -25,8 +25,8 @@ globs:
### PodMonitor System ### PodMonitor System
- `PodMonitor`: Core service that detects and tracks AirPods via Bluetooth LE - `PodMonitor`: Core service that detects and tracks AirPods via Bluetooth LE
- `MonitorControl`: Manages background monitoring worker lifecycle - `MonitorControl`: Manages MonitorService lifecycle
- `MonitorWorker`: Background worker that continuously scans for AirPods - `MonitorService`: Foreground service that continuously scans for AirPods
- `BluetoothEventReceiver`: Handles system Bluetooth events - `BluetoothEventReceiver`: Handles system Bluetooth events
### Reaction System ### Reaction System
@@ -57,7 +57,7 @@ globs:
The app follows a unidirectional data flow: The app follows a unidirectional data flow:
1. `BluetoothEventReceiver` detects Bluetooth events 1. `BluetoothEventReceiver` detects Bluetooth events
2. `MonitorWorker` scans for AirPods beacon data 2. `MonitorService` scans for AirPods beacon data
3. `PodMonitor` processes and stores device information 3. `PodMonitor` processes and stores device information
4. ViewModels observe monitor data via repositories 4. ViewModels observe monitor data via repositories
5. UI components react to ViewModel state changes 5. UI components react to ViewModel state changes
@@ -65,7 +65,7 @@ The app follows a unidirectional data flow:
## Bluetooth LE Implementation ## Bluetooth LE Implementation
The app uses Android's Bluetooth LE APIs to scan for Apple device advertisements. The core scanning logic is in `MonitorWorker` which runs as a long-lived background task. The app uses Android's Bluetooth LE APIs to scan for Apple device advertisements. The core scanning logic is in `MonitorService` which runs as a foreground service.
## Multi-Platform Considerations ## Multi-Platform Considerations
@@ -80,6 +80,5 @@ Code shared between phone and Wear OS apps is placed in `app-common`. When modif
- **Hilt**: Dependency injection framework - **Hilt**: Dependency injection framework
- **AndroidX Navigation**: Fragment navigation with SafeArgs - **AndroidX Navigation**: Fragment navigation with SafeArgs
- **WorkManager**: Background task scheduling for monitoring
- **Moshi**: JSON serialization for configuration and debugging - **Moshi**: JSON serialization for configuration and debugging
- **Material Design**: UI components following Material Design guidelines - **Material Design**: UI components following Material Design guidelines
@@ -6,6 +6,7 @@ import eu.darken.capod.common.debug.logging.Logging.Priority.VERBOSE
import eu.darken.capod.common.debug.logging.Logging.Priority.WARN import eu.darken.capod.common.debug.logging.Logging.Priority.WARN
import eu.darken.capod.common.debug.logging.log import eu.darken.capod.common.debug.logging.log
import eu.darken.capod.common.debug.logging.logTag import eu.darken.capod.common.debug.logging.logTag
import eu.darken.capod.common.permissions.Permission
import eu.darken.capod.common.startServiceCompat import eu.darken.capod.common.startServiceCompat
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@@ -19,11 +20,21 @@ class MonitorControl @Inject constructor(
forceStart: Boolean = false, forceStart: Boolean = false,
) { ) {
log(TAG, VERBOSE) { "startMonitor(forceStart=$forceStart)" } log(TAG, VERBOSE) { "startMonitor(forceStart=$forceStart)" }
val hasBluetoothPermission =
Permission.BLUETOOTH.isGranted(context) || Permission.BLUETOOTH_CONNECT.isGranted(context)
if (!hasBluetoothPermission) {
log(TAG, WARN) { "Missing Bluetooth permission, not starting monitor service." }
return
}
try { try {
context.startServiceCompat(MonitorService.intent(context, forceStart)) context.startServiceCompat(MonitorService.intent(context, forceStart))
log(TAG) { "Monitor start request sent." } log(TAG) { "Monitor start request sent." }
} catch (e: IllegalStateException) { } catch (e: IllegalStateException) {
log(TAG, WARN) { "Failed to start monitor service: ${e.message}" } log(TAG, WARN) { "Failed to start monitor service: ${e.message}" }
} catch (e: SecurityException) {
log(TAG, WARN) { "Failed to start monitor service, permission issue: ${e.message}" }
} }
} }