Skip to content

Commit 98aef13

Browse files
committed
android: add sharedpreference listeners to service
1 parent 42e0f48 commit 98aef13

File tree

1 file changed

+166
-33
lines changed

1 file changed

+166
-33
lines changed

android/app/src/main/java/me/kavishdevar/librepods/services/AirPodsService.kt

Lines changed: 166 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,35 @@ object ServiceManager {
146146
}
147147

148148
// @Suppress("unused")
149-
class AirPodsService : Service() {
149+
class AirPodsService : Service(), SharedPreferences.OnSharedPreferenceChangeListener {
150150
var macAddress = ""
151151

152+
data class ServiceConfig(
153+
var deviceName: String = "AirPods",
154+
var earDetectionEnabled: Boolean = true,
155+
var conversationalAwarenessPauseMusic: Boolean = false,
156+
var personalizedVolume: Boolean = false,
157+
var longPressNC: Boolean = true,
158+
var offListeningMode: Boolean = false,
159+
var showPhoneBatteryInWidget: Boolean = true,
160+
var singleANC: Boolean = true,
161+
var longPressTransparency: Boolean = true,
162+
var conversationalAwareness: Boolean = true,
163+
var relativeConversationalAwarenessVolume: Boolean = true,
164+
var longPressAdaptive: Boolean = true,
165+
var loudSoundReduction: Boolean = true,
166+
var longPressOff: Boolean = false,
167+
var volumeControl: Boolean = true,
168+
var headGestures: Boolean = true,
169+
var adaptiveStrength: Int = 51,
170+
var toneVolume: Int = 75,
171+
var conversationalAwarenessVolume: Int = 43,
172+
var textColor: Long = -1L,
173+
var qsClickBehavior: String = "cycle"
174+
)
175+
176+
private lateinit var config: ServiceConfig
177+
152178
inner class LocalBinder : Binder() {
153179
fun getService(): AirPodsService = this@AirPodsService
154180
}
@@ -170,6 +196,76 @@ class AirPodsService : Service() {
170196

171197
inMemoryLogs.addAll(sharedPreferencesLogs.getStringSet(packetLogKey, emptySet()) ?: emptySet())
172198
_packetLogsFlow.value = inMemoryLogs.toSet()
199+
200+
sharedPreferences = getSharedPreferences("settings", MODE_PRIVATE)
201+
initializeConfig()
202+
203+
sharedPreferences.registerOnSharedPreferenceChangeListener(this)
204+
}
205+
206+
private fun initializeConfig() {
207+
config = ServiceConfig(
208+
deviceName = sharedPreferences.getString("name", "AirPods") ?: "AirPods",
209+
earDetectionEnabled = sharedPreferences.getBoolean("automatic_ear_detection", true),
210+
conversationalAwarenessPauseMusic = sharedPreferences.getBoolean("conversational_awareness_pause_music", false),
211+
personalizedVolume = sharedPreferences.getBoolean("personalized_volume", false),
212+
longPressNC = sharedPreferences.getBoolean("long_press_nc", true),
213+
offListeningMode = sharedPreferences.getBoolean("off_listening_mode", false),
214+
showPhoneBatteryInWidget = sharedPreferences.getBoolean("show_phone_battery_in_widget", true),
215+
singleANC = sharedPreferences.getBoolean("single_anc", true),
216+
longPressTransparency = sharedPreferences.getBoolean("long_press_transparency", true),
217+
conversationalAwareness = sharedPreferences.getBoolean("conversational_awareness", true),
218+
relativeConversationalAwarenessVolume = sharedPreferences.getBoolean("relative_conversational_awareness_volume", true),
219+
longPressAdaptive = sharedPreferences.getBoolean("long_press_adaptive", true),
220+
loudSoundReduction = sharedPreferences.getBoolean("loud_sound_reduction", true),
221+
longPressOff = sharedPreferences.getBoolean("long_press_off", false),
222+
volumeControl = sharedPreferences.getBoolean("volume_control", true),
223+
headGestures = sharedPreferences.getBoolean("head_gestures", true),
224+
adaptiveStrength = sharedPreferences.getInt("adaptive_strength", 51),
225+
toneVolume = sharedPreferences.getInt("tone_volume", 75),
226+
conversationalAwarenessVolume = sharedPreferences.getInt("conversational_awareness_volume", 43),
227+
textColor = sharedPreferences.getLong("textColor", -1L),
228+
qsClickBehavior = sharedPreferences.getString("qs_click_behavior", "cycle") ?: "cycle"
229+
)
230+
}
231+
232+
override fun onSharedPreferenceChanged(preferences: SharedPreferences?, key: String?) {
233+
if (preferences == null || key == null) return
234+
235+
when(key) {
236+
"name" -> config.deviceName = preferences.getString(key, "AirPods") ?: "AirPods"
237+
"automatic_ear_detection" -> config.earDetectionEnabled = preferences.getBoolean(key, true)
238+
"conversational_awareness_pause_music" -> config.conversationalAwarenessPauseMusic = preferences.getBoolean(key, false)
239+
"personalized_volume" -> config.personalizedVolume = preferences.getBoolean(key, false)
240+
"long_press_nc" -> config.longPressNC = preferences.getBoolean(key, true)
241+
"off_listening_mode" -> {
242+
config.offListeningMode = preferences.getBoolean(key, false)
243+
updateNoiseControlWidget()
244+
}
245+
"show_phone_battery_in_widget" -> {
246+
config.showPhoneBatteryInWidget = preferences.getBoolean(key, true)
247+
widgetMobileBatteryEnabled = config.showPhoneBatteryInWidget
248+
updateBattery()
249+
}
250+
"single_anc" -> config.singleANC = preferences.getBoolean(key, true)
251+
"long_press_transparency" -> config.longPressTransparency = preferences.getBoolean(key, true)
252+
"conversational_awareness" -> config.conversationalAwareness = preferences.getBoolean(key, true)
253+
"relative_conversational_awareness_volume" -> config.relativeConversationalAwarenessVolume = preferences.getBoolean(key, true)
254+
"long_press_adaptive" -> config.longPressAdaptive = preferences.getBoolean(key, true)
255+
"loud_sound_reduction" -> config.loudSoundReduction = preferences.getBoolean(key, true)
256+
"long_press_off" -> config.longPressOff = preferences.getBoolean(key, false)
257+
"volume_control" -> config.volumeControl = preferences.getBoolean(key, true)
258+
"head_gestures" -> config.headGestures = preferences.getBoolean(key, true)
259+
"adaptive_strength" -> config.adaptiveStrength = preferences.getInt(key, 51)
260+
"tone_volume" -> config.toneVolume = preferences.getInt(key, 75)
261+
"conversational_awareness_volume" -> config.conversationalAwarenessVolume = preferences.getInt(key, 43)
262+
"textColor" -> config.textColor = preferences.getLong(key, -1L)
263+
"qs_click_behavior" -> config.qsClickBehavior = preferences.getString(key, "cycle") ?: "cycle"
264+
}
265+
266+
if (key == "mac_address") {
267+
macAddress = preferences.getString(key, "") ?: ""
268+
}
173269
}
174270

175271
private fun logPacket(packet: ByteArray, source: String) {
@@ -541,7 +637,7 @@ class AirPodsService : Service() {
541637
it.setInt(
542638
R.id.widget_transparency_button,
543639
"setBackgroundResource",
544-
if (ancStatus == 3) (if (sharedPreferences.getBoolean("off_listening_mode", true)) R.drawable.widget_button_checked_shape_middle else R.drawable.widget_button_checked_shape_start) else (if (sharedPreferences.getBoolean("off_listening_mode", true)) R.drawable.widget_button_shape_middle else R.drawable.widget_button_shape_start)
640+
if (ancStatus == 3) (if (config.offListeningMode) R.drawable.widget_button_checked_shape_middle else R.drawable.widget_button_checked_shape_start) else (if (config.offListeningMode) R.drawable.widget_button_shape_middle else R.drawable.widget_button_shape_start)
545641
)
546642
it.setInt(
547643
R.id.widget_adaptive_button,
@@ -555,19 +651,19 @@ class AirPodsService : Service() {
555651
)
556652
it.setViewVisibility(
557653
R.id.widget_off_button,
558-
if (sharedPreferences.getBoolean("off_listening_mode", true)) View.VISIBLE else View.GONE
654+
if (config.offListeningMode) View.VISIBLE else View.GONE
559655
)
560656
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
561657
it.setViewLayoutMargin(
562658
R.id.widget_transparency_button,
563659
RemoteViews.MARGIN_START,
564-
if (sharedPreferences.getBoolean("off_listening_mode", true)) 2f else 12f,
660+
if (config.offListeningMode) 2f else 12f,
565661
TypedValue.COMPLEX_UNIT_DIP
566662
)
567663
} else {
568664
it.setViewPadding(
569665
R.id.widget_transparency_button,
570-
if (sharedPreferences.getBoolean("off_listening_mode", true)) 2.dpToPx() else 12.dpToPx(),
666+
if (config.offListeningMode) 2.dpToPx() else 12.dpToPx(),
571667
12.dpToPx(),
572668
2.dpToPx(),
573669
12.dpToPx()
@@ -598,7 +694,7 @@ class AirPodsService : Service() {
598694
if (connected) {
599695
updatedNotification = NotificationCompat.Builder(this, "background_service_status")
600696
.setSmallIcon(R.drawable.airpods)
601-
.setContentTitle(airpodsName)
697+
.setContentTitle(airpodsName ?: config.deviceName)
602698
.setContentText(
603699
"""${
604700
batteryList?.find { it.component == BatteryComponent.LEFT }?.let {
@@ -648,14 +744,14 @@ class AirPodsService : Service() {
648744
@RequiresApi(Build.VERSION_CODES.Q)
649745
fun handleIncomingCall() {
650746
if (isInCall) return
651-
652-
initGestureDetector()
653-
654-
gestureDetector?.startDetection { accepted ->
655-
if (accepted) {
656-
answerCall()
657-
} else {
658-
rejectCall()
747+
if (config.headGestures) {
748+
initGestureDetector()
749+
gestureDetector?.startDetection { accepted ->
750+
if (accepted) {
751+
answerCall()
752+
} else {
753+
rejectCall()
754+
}
659755
}
660756
}
661757
}
@@ -943,7 +1039,7 @@ class AirPodsService : Service() {
9431039
editor.apply()
9441040
}
9451041

946-
earDetectionEnabled = sharedPreferences.getBoolean("automatic_ear_detection", true)
1042+
initializeConfig()
9471043

9481044
ancModeReceiver = object : BroadcastReceiver() {
9491045
override fun onReceive(context: Context?, intent: Intent?) {
@@ -955,7 +1051,7 @@ class AirPodsService : Service() {
9551051
}
9561052
} else {
9571053
val currentMode = ancNotification.status
958-
val offListeningMode = sharedPreferences.getBoolean("off_listening_mode", true)
1054+
val offListeningMode = config.offListeningMode
9591055

9601056
val nextMode = if (offListeningMode) {
9611057
when (currentMode) {
@@ -1013,7 +1109,7 @@ class AirPodsService : Service() {
10131109
when (state) {
10141110
TelephonyManager.CALL_STATE_RINGING -> {
10151111
if (CrossDevice.isAvailable && !isConnectedLocally && earDetectionNotification.status.contains(0x00)) takeOver()
1016-
if (sharedPreferences.getBoolean("head_gestures", false)) {
1112+
if (config.headGestures) {
10171113
callNumber = phoneNumber
10181114
handleIncomingCall()
10191115
}
@@ -1032,7 +1128,7 @@ class AirPodsService : Service() {
10321128
}
10331129
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE)
10341130

1035-
if (sharedPreferences.getBoolean("show_phone_battery_in_widget", true)) {
1131+
if (config.showPhoneBatteryInWidget) {
10361132
widgetMobileBatteryEnabled = true
10371133
val batteryChangedIntentFilter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
10381134
batteryChangedIntentFilter.addAction(AirPodsNotifications.DISCONNECT_RECEIVERS)
@@ -1067,19 +1163,16 @@ class AirPodsService : Service() {
10671163
} else {
10681164
intent.getParcelableExtra("device") as BluetoothDevice?
10691165
}
1070-
val name = this@AirPodsService.getSharedPreferences("settings", MODE_PRIVATE)
1071-
.getString("name", device?.name)
1072-
if (this@AirPodsService.getSharedPreferences("settings", MODE_PRIVATE)
1073-
.getString("name", null) == null
1074-
) {
1075-
this@AirPodsService.getSharedPreferences("settings", MODE_PRIVATE).edit {
1076-
putString("name", name)
1077-
}
1166+
1167+
if (config.deviceName == "AirPods" && device?.name != null) {
1168+
config.deviceName = device?.name ?: "AirPods"
1169+
sharedPreferences.edit { putString("name", config.deviceName) }
10781170
}
1171+
10791172
Log.d("AirPodsCrossDevice", CrossDevice.isAvailable.toString())
10801173
if (!CrossDevice.isAvailable) {
1081-
Log.d("AirPodsService", "$name connected")
1082-
showPopup(this@AirPodsService, name.toString())
1174+
Log.d("AirPodsService", "${config.deviceName} connected")
1175+
showPopup(this@AirPodsService, config.deviceName)
10831176
connectToSocket(device!!)
10841177
Log.d("AirPodsService", "Setting metadata")
10851178
setMetadatas(device!!)
@@ -1090,7 +1183,7 @@ class AirPodsService : Service() {
10901183
}
10911184
updateNotificationContent(
10921185
true,
1093-
name.toString(),
1186+
config.deviceName,
10941187
batteryNotification.getBattery()
10951188
)
10961189
}
@@ -1351,7 +1444,7 @@ class AirPodsService : Service() {
13511444
earReceiver = object : BroadcastReceiver() {
13521445
override fun onReceive(context: Context, intent: Intent) {
13531446
val data = intent.getByteArrayExtra("data")
1354-
if (data != null && earDetectionEnabled) {
1447+
if (data != null && config.earDetectionEnabled) {
13551448
inEar =
13561449
if (data.find { it == 0x02.toByte() } != null || data.find { it == 0x03.toByte() } != null) {
13571450
data[0] == 0x00.toByte() || data[1] == 0x00.toByte()
@@ -1657,6 +1750,11 @@ class AirPodsService : Service() {
16571750
0x00
16581751
)
16591752
)
1753+
1754+
if (config.offListeningMode != enabled) {
1755+
config.offListeningMode = enabled
1756+
sharedPreferences.edit { putBoolean("off_listening_mode", enabled) }
1757+
}
16601758
updateNoiseControlWidget()
16611759
}
16621760

@@ -1676,6 +1774,11 @@ class AirPodsService : Service() {
16761774
0x00
16771775
)
16781776
sendPacket(bytes)
1777+
1778+
if (config.adaptiveStrength != strength) {
1779+
config.adaptiveStrength = strength
1780+
sharedPreferences.edit { putInt("adaptive_strength", strength) }
1781+
}
16791782
}
16801783

16811784
fun setPressSpeed(speed: Int) {
@@ -1741,12 +1844,22 @@ class AirPodsService : Service() {
17411844
0x00
17421845
)
17431846
sendPacket(bytes)
1847+
1848+
if (config.volumeControl != enabled) {
1849+
config.volumeControl = enabled
1850+
sharedPreferences.edit { putBoolean("volume_control", enabled) }
1851+
}
17441852
}
17451853

17461854
fun setToneVolume(volume: Int) {
17471855
val bytes =
17481856
byteArrayOf(0x04, 0x00, 0x04, 0x00, 0x09, 0x00, 0x1F, volume.toByte(), 0x50, 0x00, 0x00)
17491857
sendPacket(bytes)
1858+
1859+
if (config.toneVolume != volume) {
1860+
config.toneVolume = volume
1861+
sharedPreferences.edit { putInt("tone_volume", volume) }
1862+
}
17501863
}
17511864

17521865
val earDetectionNotification = AirPodsNotifications.EarDetection()
@@ -1755,10 +1868,11 @@ class AirPodsService : Service() {
17551868
val conversationAwarenessNotification =
17561869
AirPodsNotifications.ConversationalAwarenessNotification()
17571870

1758-
var earDetectionEnabled = true
1759-
17601871
fun setEarDetection(enabled: Boolean) {
1761-
earDetectionEnabled = enabled
1872+
if (config.earDetectionEnabled != enabled) {
1873+
config.earDetectionEnabled = enabled
1874+
sharedPreferences.edit { putBoolean("automatic_ear_detection", enabled) }
1875+
}
17621876
}
17631877

17641878
fun getBattery(): List<Battery> {
@@ -1865,6 +1979,12 @@ class AirPodsService : Service() {
18651979
) + nameBytes
18661980
sendPacket(bytes)
18671981
val hex = bytes.joinToString(" ") { "%02X".format(it) }
1982+
1983+
if (config.deviceName != name) {
1984+
config.deviceName = name
1985+
sharedPreferences.edit { putString("name", name) }
1986+
}
1987+
18681988
updateNotificationContent(true, name, batteryNotification.getBattery())
18691989
Log.d("AirPodsService", "setName: $name, sent packet: $hex")
18701990
}
@@ -1877,12 +1997,22 @@ class AirPodsService : Service() {
18771997
"04 00 04 00 17 00 00 00 10 00 12 00 08 E${if (enabled) "6" else "5"} 05 10 02 42 0B 08 50 10 02 1A 05 02 ${if (enabled) "32" else "00"} 00 00 00"
18781998
bytes = hex.split(" ").map { it.toInt(16).toByte() }.toByteArray()
18791999
sendPacket(bytes)
2000+
2001+
if (config.personalizedVolume != enabled) {
2002+
config.personalizedVolume = enabled
2003+
sharedPreferences.edit { putBoolean("personalized_volume", enabled) }
2004+
}
18802005
}
18812006

18822007
fun setLoudSoundReduction(enabled: Boolean) {
18832008
val hex = "52 1B 00 0${if (enabled) "1" else "0"}"
18842009
val bytes = hex.split(" ").map { it.toInt(16).toByte() }.toByteArray()
18852010
sendPacket(bytes)
2011+
2012+
if (config.loudSoundReduction != enabled) {
2013+
config.loudSoundReduction = enabled
2014+
sharedPreferences.edit { putBoolean("loud_sound_reduction", enabled) }
2015+
}
18862016
}
18872017

18882018
fun findChangedIndex(oldArray: BooleanArray, newArray: BooleanArray): Int {
@@ -2036,6 +2166,9 @@ class AirPodsService : Service() {
20362166
override fun onDestroy() {
20372167
clearPacketLogs()
20382168
Log.d("AirPodsService", "Service stopped is being destroyed for some reason!")
2169+
2170+
sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
2171+
20392172
try {
20402173
unregisterReceiver(bluetoothReceiver)
20412174
} catch (e: Exception) {

0 commit comments

Comments
 (0)