Skip to content

Commit 98b15a4

Browse files
committed
Introduce StopBeaconScanningReceiver and improve BluetoothSensorManager
1 parent d31412a commit 98b15a4

9 files changed

Lines changed: 120 additions & 122 deletions

File tree

app/src/main/kotlin/io/homeassistant/companion/android/notifications/MessagingManager.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -456,13 +456,13 @@ class MessagingManager @Inject constructor(
456456
}
457457

458458
DeviceCommandData.COMMAND_BLE_TRANSMITTER -> {
459-
if (!commandBleTransmitter(context, jsonData, sensorRepository, bluetoothSensorManager)) {
459+
if (!commandBleTransmitter(jsonData, sensorRepository, bluetoothSensorManager)) {
460460
sendNotification(jsonData)
461461
}
462462
}
463463

464464
DeviceCommandData.COMMAND_BEACON_MONITOR -> {
465-
if (!commandBeaconMonitor(context, jsonData, sensorRepository)) {
465+
if (!commandBeaconMonitor(jsonData, bluetoothSensorManager)) {
466466
sendNotification(jsonData)
467467
}
468468
}

common/src/main/AndroidManifest.xml

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,10 @@
66
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
77

88
<application>
9-
<receiver android:name=".sensors.SensorUpdateReceiver"
10-
android:exported="false">
11-
<intent-filter>
12-
<action android:name="io.homeassistant.companion.android.UPDATE_SENSORS" />
13-
</intent-filter>
14-
</receiver>
9+
<!-- Registered for the explicit ACTION_STOP_BEACON_SCANNING PendingIntent (beacon notification action) -->
10+
<receiver
11+
android:name=".sensors.StopBeaconScanningReceiver"
12+
android:exported="false" />
1513

1614
<receiver
1715
android:name=".notifications.NotificationDeleteReceiver"

common/src/main/kotlin/io/homeassistant/companion/android/common/bluetooth/ble/IBeaconMonitor.kt

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package io.homeassistant.companion.android.common.bluetooth.ble
22

3-
import android.content.Context
43
import io.homeassistant.companion.android.common.sensors.BluetoothSensorManager
5-
import io.homeassistant.companion.android.common.sensors.SensorUpdateReceiver
64
import kotlin.math.abs
75
import kotlin.math.round
86
import org.altbeacon.beacon.Beacon
@@ -42,7 +40,7 @@ class IBeaconMonitor {
4240
beacons = listOf()
4341
}
4442

45-
fun setBeacons(context: Context, newBeacons: Collection<Beacon>) {
43+
fun setBeacons(newBeacons: Collection<Beacon>) {
4644
lastSeenBeacons = newBeacons // unfiltered list, for the settings UI
4745
var requireUpdate = false
4846
val tmp = mutableMapOf<String, IBeacon>()
@@ -73,7 +71,7 @@ class IBeaconMonitor {
7371
}
7472
val sorted = sort(tmp.values).toMutableList()
7573
if (requireUpdate) {
76-
sendUpdate(context, sorted)
74+
sendUpdate(sorted)
7775
return
7876
}
7977
for ((i, existingBeacon) in beacons.withIndex()) {
@@ -88,15 +86,15 @@ class IBeaconMonitor {
8886
}
8987
}
9088
if (requireUpdate) {
91-
sendUpdate(context, sorted)
89+
sendUpdate(sorted)
9290
return
9391
}
9492
}
9593

96-
private fun sendUpdate(context: Context, tmp: List<IBeacon>) {
94+
private fun sendUpdate(tmp: List<IBeacon>) {
9795
beacons = tmp
9896
sensorManager.updateBeaconMonitoringSensor()
99-
SensorUpdateReceiver.updateSensors(context)
97+
sensorManager.requestBluetoothSensorUpdate()
10098
}
10199

102100
fun setUUIDFilter(uuidFilter: List<String>, uuidFilterExclude: Boolean) {

common/src/main/kotlin/io/homeassistant/companion/android/common/bluetooth/ble/MonitoringManager.kt

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,12 @@ import android.app.NotificationChannel
44
import android.app.NotificationManager
55
import android.app.PendingIntent
66
import android.content.Context
7-
import android.content.Intent
87
import android.os.Build
98
import androidx.core.app.NotificationCompat
109
import androidx.core.content.getSystemService
1110
import io.homeassistant.companion.android.common.BuildConfig
1211
import io.homeassistant.companion.android.common.R
13-
import io.homeassistant.companion.android.common.sensors.SensorReceiverBase
14-
import io.homeassistant.companion.android.common.sensors.SensorUpdateReceiver
12+
import io.homeassistant.companion.android.common.sensors.StopBeaconScanningReceiver
1513
import io.homeassistant.companion.android.common.util.CHANNEL_BEACON_MONITOR
1614
import io.homeassistant.companion.android.common.util.SdkVersion
1715
import kotlinx.coroutines.CoroutineScope
@@ -68,10 +66,7 @@ class MonitoringManager {
6866
scope.launch(Dispatchers.Main) {
6967
beaconManager.getRegionViewModel(region).rangedBeacons.observeForever { beacons ->
7068
if (beaconManager.isAnyConsumerBound) {
71-
haMonitor.setBeacons(
72-
context,
73-
beacons,
74-
)
69+
haMonitor.setBeacons(beacons)
7570
}
7671
}
7772
}
@@ -90,12 +85,10 @@ class MonitoringManager {
9085
val notifManager = context.getSystemService<NotificationManager>()!!
9186
notifManager.createNotificationChannel(channel)
9287
}
93-
val stopScanningIntent = Intent(context, SensorUpdateReceiver::class.java)
94-
stopScanningIntent.action = SensorReceiverBase.ACTION_STOP_BEACON_SCANNING
9588
val stopScanningPendingIntent = PendingIntent.getBroadcast(
9689
context,
9790
0,
98-
stopScanningIntent,
91+
StopBeaconScanningReceiver.stopScanningIntent(context),
9992
PendingIntent.FLAG_MUTABLE,
10093
)
10194
builder.addAction(0, context.getString(R.string.disable), stopScanningPendingIntent)

common/src/main/kotlin/io/homeassistant/companion/android/common/notifications/DeviceCommands.kt

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
package io.homeassistant.companion.android.common.notifications
22

3-
import android.content.Context
43
import io.homeassistant.companion.android.common.sensors.BluetoothSensorManager
5-
import io.homeassistant.companion.android.common.sensors.BluetoothSensorManager.Companion.enableDisableBLETransmitter
6-
import io.homeassistant.companion.android.common.sensors.BluetoothSensorManager.Companion.enableDisableBeaconMonitor
74
import io.homeassistant.companion.android.common.sensors.SensorRepository
8-
import io.homeassistant.companion.android.common.sensors.SensorUpdateReceiver
95
import java.util.UUID
106
import timber.log.Timber
117

@@ -107,11 +103,7 @@ private fun checkCommandFormat(data: Map<String, String>): Boolean {
107103
}
108104
}
109105

110-
suspend fun commandBeaconMonitor(
111-
context: Context,
112-
data: Map<String, String>,
113-
sensorRepository: SensorRepository,
114-
): Boolean {
106+
suspend fun commandBeaconMonitor(data: Map<String, String>, bluetoothSensorManager: BluetoothSensorManager): Boolean {
115107
if (!checkCommandFormat(data)) {
116108
Timber.d(
117109
"Invalid beacon monitor command received, posting notification to device",
@@ -121,16 +113,15 @@ suspend fun commandBeaconMonitor(
121113
val command = data[NotificationData.COMMAND]
122114
Timber.d("Processing command: ${data[NotificationData.MESSAGE]}")
123115
if (command == DeviceCommandData.TURN_OFF) {
124-
sensorRepository.enableDisableBeaconMonitor(context, false)
116+
bluetoothSensorManager.enableDisableBeaconMonitor(false)
125117
}
126118
if (command == DeviceCommandData.TURN_ON) {
127-
sensorRepository.enableDisableBeaconMonitor(context, true)
119+
bluetoothSensorManager.enableDisableBeaconMonitor(true)
128120
}
129121
return true
130122
}
131123

132124
suspend fun commandBleTransmitter(
133-
context: Context,
134125
data: Map<String, String>,
135126
sensorRepository: SensorRepository,
136127
bluetoothSensorManager: BluetoothSensorManager,
@@ -144,10 +135,10 @@ suspend fun commandBleTransmitter(
144135
val command = data[NotificationData.COMMAND]
145136
Timber.d("Processing command: ${data[NotificationData.MESSAGE]}")
146137
if (command == DeviceCommandData.TURN_OFF) {
147-
sensorRepository.enableDisableBLETransmitter(false)
138+
bluetoothSensorManager.enableDisableBLETransmitter(false)
148139
}
149140
if (command == DeviceCommandData.TURN_ON) {
150-
sensorRepository.enableDisableBLETransmitter(true)
141+
bluetoothSensorManager.enableDisableBLETransmitter(true)
151142
}
152143
if (command in DeviceCommandData.BLE_COMMANDS) {
153144
sensorRepository.updateSettingValue(
@@ -196,6 +187,6 @@ suspend fun commandBleTransmitter(
196187
)
197188
}
198189
bluetoothSensorManager.requestSensorUpdate()
199-
SensorUpdateReceiver.updateSensors(context)
190+
bluetoothSensorManager.requestBluetoothSensorUpdate()
200191
return true
201192
}

common/src/main/kotlin/io/homeassistant/companion/android/common/sensors/BluetoothSensorManager.kt

Lines changed: 56 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import android.Manifest
33
import android.annotation.SuppressLint
44
import android.content.Context
55
import android.os.Build
6+
import dagger.Lazy
67
import dagger.hilt.android.qualifiers.ApplicationContext
78
import io.homeassistant.companion.android.common.R as commonR
89
import io.homeassistant.companion.android.common.bluetooth.BluetoothDevice
@@ -32,6 +33,8 @@ class BluetoothSensorManager @Inject constructor(
3233
@ApplicationContext override val applicationContext: Context,
3334
override val sensorRepository: SensorRepository,
3435
override val serverManager: ServerManager,
36+
// Lazy to break the dependency cycle: SensorUpdater injects the Set<SensorManager> that contains this manager.
37+
private val sensorUpdater: Lazy<SensorUpdater>,
3538
) : SensorManager {
3639
companion object {
3740

@@ -120,7 +123,7 @@ class BluetoothSensorManager @Inject constructor(
120123
updateType = SensorManager.BasicSensor.UpdateType.INTENT,
121124
)
122125

123-
val monitoringManager = MonitoringManager()
126+
private val monitoringManager = MonitoringManager()
124127

125128
@ProvidesSensor
126129
val beaconMonitor = SensorManager.BasicSensor(
@@ -133,44 +136,6 @@ class BluetoothSensorManager @Inject constructor(
133136
entityCategory = SensorManager.ENTITY_CATEGORY_DIAGNOSTIC,
134137
updateType = SensorManager.BasicSensor.UpdateType.CUSTOM,
135138
)
136-
137-
suspend fun SensorRepository.enableDisableBLETransmitter(transmitEnabled: Boolean) {
138-
val sensorEntity = get(bleTransmitter.id)
139-
if (sensorEntity.none { it.enabled }) {
140-
return
141-
}
142-
143-
add(
144-
SensorSetting(
145-
bleTransmitter.id,
146-
SETTING_BLE_TRANSMIT_ENABLED,
147-
transmitEnabled.toString(),
148-
SensorSettingType.TOGGLE,
149-
),
150-
)
151-
}
152-
153-
suspend fun SensorRepository.enableDisableBeaconMonitor(applicationContext: Context, monitorEnabled: Boolean) {
154-
val sensorEntity = get(beaconMonitor.id)
155-
if (sensorEntity.none { it.enabled }) {
156-
return
157-
}
158-
159-
if (monitorEnabled) {
160-
monitoringManager.startMonitoring(applicationContext, beaconMonitoringDevice)
161-
} else {
162-
monitoringManager.stopMonitoring(applicationContext, beaconMonitoringDevice)
163-
}
164-
add(
165-
SensorSetting(
166-
beaconMonitor.id,
167-
SETTING_BEACON_MONITOR_ENABLED,
168-
monitorEnabled.toString(),
169-
SensorSettingType.TOGGLE,
170-
),
171-
)
172-
SensorUpdateReceiver.updateSensors(applicationContext)
173-
}
174139
}
175140

176141
private val ioScope: CoroutineScope = CoroutineScope(Dispatchers.IO)
@@ -243,6 +208,58 @@ class BluetoothSensorManager @Inject constructor(
243208
updateBeaconMonitoringSensor()
244209
}
245210

211+
suspend fun enableDisableBLETransmitter(transmitEnabled: Boolean) {
212+
val sensorEntity = sensorRepository.get(bleTransmitter.id)
213+
if (sensorEntity.none { it.enabled }) {
214+
return
215+
}
216+
217+
sensorRepository.add(
218+
SensorSetting(
219+
bleTransmitter.id,
220+
SETTING_BLE_TRANSMIT_ENABLED,
221+
transmitEnabled.toString(),
222+
SensorSettingType.TOGGLE,
223+
),
224+
)
225+
}
226+
227+
suspend fun enableDisableBeaconMonitor(monitorEnabled: Boolean) {
228+
val sensorEntity = sensorRepository.get(beaconMonitor.id)
229+
if (sensorEntity.none { it.enabled }) {
230+
return
231+
}
232+
233+
if (monitorEnabled) {
234+
monitoringManager.startMonitoring(applicationContext, beaconMonitoringDevice)
235+
} else {
236+
monitoringManager.stopMonitoring(applicationContext, beaconMonitoringDevice)
237+
}
238+
sensorRepository.add(
239+
SensorSetting(
240+
beaconMonitor.id,
241+
SETTING_BEACON_MONITOR_ENABLED,
242+
monitorEnabled.toString(),
243+
SensorSettingType.TOGGLE,
244+
),
245+
)
246+
requestBluetoothSensorUpdate()
247+
}
248+
249+
/**
250+
* Updates and syncs only this manager's Bluetooth sensors, without touching the other managers.
251+
* Used after a beacon or BLE transmitter change; runs fire-and-forget on the manager's scope.
252+
*/
253+
fun requestBluetoothSensorUpdate() {
254+
ioScope.launch {
255+
sensorUpdater.get().updateSensors(
256+
intent = null,
257+
getSensorSettingsIntent = { _, _, _, _ -> null },
258+
managers = setOf(this@BluetoothSensorManager),
259+
)
260+
}
261+
}
262+
246263
private suspend fun updateBluetoothConnectionSensor() {
247264
if (!isEnabled(bluetoothConnection)) {
248265
return

common/src/main/kotlin/io/homeassistant/companion/android/common/sensors/SensorUpdateReceiver.kt

Lines changed: 0 additions & 41 deletions
This file was deleted.

0 commit comments

Comments
 (0)