Skip to content

Commit b4b49fb

Browse files
authored
Battery alerts (#303)
1 parent 5b90d95 commit b4b49fb

8 files changed

Lines changed: 191 additions & 3 deletions

File tree

app/src/main/java/com/valterc/ki2/karoo/Ki2ExtensionContext.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.valterc.ki2.karoo
33
import android.content.Context
44
import com.valterc.ki2.input.ActionManager
55
import com.valterc.ki2.karoo.audio.AudioManager
6+
import com.valterc.ki2.karoo.device.KarooSensorDeviceTracking
67
import com.valterc.ki2.karoo.service.ServiceClient
78
import com.valterc.ki2.karoo.shifting.ShiftCountHandler
89
import io.hammerhead.karooext.KarooSystemService
@@ -14,4 +15,5 @@ class Ki2ExtensionContext(val extension: String, val context: Context) {
1415
val audioManager: AudioManager = AudioManager(this)
1516
val actionManager: ActionManager = ActionManager(this)
1617
val shiftCountHandler: ShiftCountHandler = ShiftCountHandler(this)
18+
val karooDeviceTracking: KarooSensorDeviceTracking = KarooSensorDeviceTracking()
1719
}

app/src/main/java/com/valterc/ki2/karoo/Ki2ExtensionService.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import android.content.ComponentName
44
import android.content.Intent
55
import com.valterc.ki2.BuildConfig
66
import com.valterc.ki2.data.device.DeviceId
7+
import com.valterc.ki2.karoo.battery.BatteryAlertHandler
78
import com.valterc.ki2.karoo.datatypes.text.FrontGearIndexDataType
89
import com.valterc.ki2.karoo.datatypes.text.FrontGearSizeDataType
910
import com.valterc.ki2.karoo.datatypes.text.FrontShiftCountDataType
@@ -24,7 +25,7 @@ import com.valterc.ki2.karoo.datatypes.visual.GearsIndexVisualDataType
2425
import com.valterc.ki2.karoo.datatypes.visual.GearsSizeVisualDataType
2526
import com.valterc.ki2.karoo.overlay.OverlayWindowHandler
2627
import com.valterc.ki2.karoo.shifting.ShiftingAudioAlertHandler
27-
import com.valterc.ki2.karoo.shifting.ShiftingDevice
28+
import com.valterc.ki2.karoo.device.ShiftingDevice
2829
import com.valterc.ki2.karoo.update.UpdateHandler
2930
import io.hammerhead.karooext.extension.KarooExtension
3031
import io.hammerhead.karooext.internal.Emitter
@@ -94,6 +95,7 @@ class Ki2ExtensionService : KarooExtension("ki2", BuildConfig.VERSION_NAME) {
9495
handlers.add(UpdateHandler(extensionContext))
9596
handlers.add(OverlayWindowHandler(this, extensionContext))
9697
handlers.add(ShiftingAudioAlertHandler(extensionContext))
98+
handlers.add(BatteryAlertHandler(extensionContext))
9799
}
98100
}
99101
}
@@ -116,7 +118,9 @@ class Ki2ExtensionService : KarooExtension("ki2", BuildConfig.VERSION_NAME) {
116118

117119
override fun connectDevice(uid: String, emitter: Emitter<DeviceEvent>) {
118120
Timber.i("[%s] Device connect", uid)
119-
ShiftingDevice(extensionContext, DeviceId(uid)).connect(emitter)
121+
val deviceId = DeviceId(uid)
122+
extensionContext.karooDeviceTracking.deviceConnect(deviceId)
123+
ShiftingDevice(extensionContext, deviceId).connect(emitter)
120124
}
121125

122126
override fun onDestroy() {

app/src/main/java/com/valterc/ki2/karoo/audio/AudioManager.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,20 @@ class AudioManager(private val context: Ki2ExtensionContext) {
115115
)
116116
}
117117

118+
fun playKarooDeviceWarning() {
119+
context.karooSystem.dispatch(
120+
PlayBeepPattern(
121+
listOf(
122+
PlayBeepPattern.Tone(1975.f, 125.d),
123+
PlayBeepPattern.Tone(null, 125.d),
124+
PlayBeepPattern.Tone(1975.f, 125.d),
125+
PlayBeepPattern.Tone(null, 125.d),
126+
PlayBeepPattern.Tone(1975.f, 125.d)
127+
)
128+
)
129+
)
130+
}
131+
118132
fun playLowestGearAudioAlert() {
119133
tryTriggerAudioAlert {
120134
playAudio(audioAlertLowestGear)
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package com.valterc.ki2.karoo.battery
2+
3+
import com.valterc.ki2.R
4+
import com.valterc.ki2.data.device.BatteryInfo
5+
import com.valterc.ki2.data.device.DeviceId
6+
import com.valterc.ki2.data.device.DeviceName
7+
import com.valterc.ki2.data.preferences.PreferencesView
8+
import com.valterc.ki2.karoo.Ki2ExtensionContext
9+
import com.valterc.ki2.karoo.RideHandler
10+
import io.hammerhead.karooext.models.InRideAlert
11+
import io.hammerhead.karooext.models.RideState
12+
import io.hammerhead.karooext.models.SystemNotification
13+
import java.util.function.BiConsumer
14+
import java.util.function.Consumer
15+
16+
class BatteryAlertHandler(extensionContext: Ki2ExtensionContext) : RideHandler(extensionContext) {
17+
18+
private var batteryLevelLow: Int? = null
19+
private var batteryLevelCritical: Int? = null
20+
private val notificationMap = mutableMapOf<DeviceId, BatteryAlertRecord>()
21+
22+
private val preferencesConsumer = Consumer<PreferencesView> { preferences ->
23+
batteryLevelLow = preferences.getBatteryLevelLow(extensionContext.context)
24+
batteryLevelCritical = preferences.getBatteryLevelCritical(extensionContext.context)
25+
26+
notificationMap.values.forEach { batteryRecord ->
27+
checkBatteryAndNotify(batteryRecord)
28+
}
29+
}
30+
31+
private val batteryConsumer = BiConsumer<DeviceId, BatteryInfo> { deviceId, batteryInfo ->
32+
notificationMap[deviceId]?.let { batteryRecord ->
33+
batteryRecord.batteryInfo = batteryInfo
34+
} ?: run {
35+
notificationMap[deviceId] = BatteryAlertRecord(deviceId, batteryInfo)
36+
}
37+
38+
notificationMap[deviceId]?.let { batteryRecord ->
39+
checkBatteryAndNotify(batteryRecord)
40+
}
41+
}
42+
43+
init {
44+
extensionContext.serviceClient.registerUnfilteredBatteryInfoWeakListener(batteryConsumer)
45+
extensionContext.serviceClient.registerPreferencesWeakListener(preferencesConsumer)
46+
}
47+
48+
override fun onRideStart() {
49+
notificationMap.values.forEach { batteryRecord ->
50+
checkBatteryAndNotify(batteryRecord)
51+
}
52+
}
53+
54+
override fun onRideResume() {
55+
notificationMap.values.forEach { batteryRecord ->
56+
checkBatteryAndNotify(batteryRecord)
57+
}
58+
}
59+
60+
override fun onRideEnd() {
61+
notificationMap.values.forEach { batteryRecord ->
62+
batteryRecord.alertedInRide = false
63+
}
64+
}
65+
66+
private fun checkBatteryAndNotify(batteryAlertRecord: BatteryAlertRecord) {
67+
if (extensionContext.karooDeviceTracking.isDeviceConnected(batteryAlertRecord.deviceId)) {
68+
// If the device was added to Karoo, let Karoo handle the battery notification
69+
return
70+
}
71+
72+
batteryAlertRecord.batteryInfo?.let { batteryInfo ->
73+
val batteryLevelCritical = batteryLevelCritical
74+
val batteryLevelLow = batteryLevelLow
75+
76+
if (batteryLevelCritical != null && batteryInfo.value <= batteryLevelCritical) {
77+
notify(batteryAlertRecord, batteryInfo, BatteryAlertType.Critical)
78+
} else if (batteryLevelLow != null && batteryInfo.value <= batteryLevelLow) {
79+
notify(batteryAlertRecord, batteryInfo, BatteryAlertType.Low)
80+
}
81+
}
82+
}
83+
84+
private fun notify(
85+
batteryAlertRecord: BatteryAlertRecord,
86+
batteryInfo: BatteryInfo,
87+
batteryAlertType: BatteryAlertType
88+
) {
89+
if (batteryAlertRecord.alert == batteryAlertType && batteryAlertRecord.alertedInRide) {
90+
return
91+
}
92+
93+
val devicePreferences =
94+
extensionContext.serviceClient.getDevicePreferences(batteryAlertRecord.deviceId)
95+
val deviceName =
96+
devicePreferences?.getName(extensionContext.context) ?: DeviceName.getDefaultName(
97+
extensionContext.context,
98+
batteryAlertRecord.deviceId
99+
)
100+
val title = extensionContext.context.getString(R.string.text_di2_low_battery)
101+
val detail = extensionContext.context.getString(
102+
R.string.text_param_low_battery,
103+
deviceName,
104+
batteryInfo.value
105+
)
106+
107+
if (!batteryAlertRecord.alertedInRide && rideState is RideState.Recording) {
108+
batteryAlertRecord.alertedInRide = true
109+
extensionContext.karooSystem.dispatch(
110+
InRideAlert(
111+
"ki2-ride-alert-battery-${batteryAlertRecord.deviceId.uid}",
112+
R.drawable.ic_hh_battery,
113+
title,
114+
detail,
115+
12_000,
116+
backgroundColor = R.color.hh_red_600,
117+
textColor = R.color.white
118+
)
119+
)
120+
extensionContext.audioManager.playKarooDeviceWarning()
121+
}
122+
123+
extensionContext.karooSystem.dispatch(
124+
SystemNotification(
125+
"ki2-notification-battery-${batteryAlertRecord.deviceId.uid}",
126+
detail,
127+
header = title,
128+
style = if (batteryAlertType == BatteryAlertType.Critical) SystemNotification.Style.ERROR else SystemNotification.Style.EVENT
129+
)
130+
)
131+
132+
batteryAlertRecord.alert = batteryAlertType
133+
}
134+
135+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.valterc.ki2.karoo.battery
2+
3+
import com.valterc.ki2.data.device.BatteryInfo
4+
import com.valterc.ki2.data.device.DeviceId
5+
6+
class BatteryAlertRecord(val deviceId: DeviceId,
7+
var batteryInfo: BatteryInfo? = null,
8+
var alert : BatteryAlertType? = null,
9+
var alertedInRide: Boolean = false)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.valterc.ki2.karoo.battery
2+
3+
enum class BatteryAlertType {
4+
Low,
5+
Critical
6+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.valterc.ki2.karoo.device
2+
3+
import com.valterc.ki2.data.device.DeviceId
4+
5+
class KarooSensorDeviceTracking {
6+
7+
private val deviceMap = mutableMapOf<DeviceId, Boolean>()
8+
9+
fun deviceConnect(uid: DeviceId) {
10+
deviceMap[uid] = true
11+
}
12+
13+
fun isDeviceConnected(uid: DeviceId) : Boolean {
14+
return deviceMap[uid] == true
15+
}
16+
17+
}

app/src/main/java/com/valterc/ki2/karoo/shifting/ShiftingDevice.kt renamed to app/src/main/java/com/valterc/ki2/karoo/device/ShiftingDevice.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.valterc.ki2.karoo.shifting
1+
package com.valterc.ki2.karoo.device
22

33
import com.valterc.ki2.data.connection.ConnectionInfo
44
import com.valterc.ki2.data.connection.ConnectionStatus
@@ -10,6 +10,7 @@ import com.valterc.ki2.data.preferences.device.DevicePreferencesView
1010
import com.valterc.ki2.data.shifting.ShiftingInfo
1111
import com.valterc.ki2.karoo.Ki2ExtensionContext
1212
import com.valterc.ki2.karoo.datatypes.Ki2DataType
13+
import com.valterc.ki2.karoo.shifting.ShiftingGearingHelper
1314
import io.hammerhead.karooext.internal.Emitter
1415
import io.hammerhead.karooext.models.BatteryStatus
1516
import io.hammerhead.karooext.models.ConnectionStatus as KarooConnectionStatus

0 commit comments

Comments
 (0)