11/*
22 * LibrePods - AirPods liberated from Apple’s ecosystem
3- *
3+ *
44 * Copyright (C) 2025 LibrePods contributors
5- *
5+ *
66 * This program is free software: you can redistribute it and/or modify
77 * it under the terms of the GNU Affero General Public License as published
88 * by the Free Software Foundation, either version 3 of the License.
9- *
9+ *
1010 * This program is distributed in the hope that it will be useful,
1111 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1212 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1313 * GNU Affero General Public License for more details.
14- *
14+ *
1515 * You should have received a copy of the GNU Affero General Public License
1616 * along with this program. If not, see <https://www.gnu.org/licenses/>.
1717 */
1818
1919package me.kavishdevar.librepods
2020
21- import android.Manifest
2221import android.annotation.SuppressLint
2322import android.bluetooth.BluetoothDevice
2423import android.bluetooth.BluetoothManager
@@ -29,63 +28,53 @@ import android.util.Log
2928import androidx.activity.ComponentActivity
3029import androidx.activity.compose.setContent
3130import androidx.activity.enableEdgeToEdge
32- import androidx.annotation.RequiresPermission
33- import androidx.compose.foundation.layout.Arrangement
34- import androidx.compose.foundation.layout.Column
35- import androidx.compose.foundation.layout.fillMaxSize
36- import androidx.compose.foundation.layout.padding
37- import androidx.compose.foundation.rememberScrollState
38- import androidx.compose.foundation.verticalScroll
39- import androidx.compose.runtime.Composable
31+ import androidx.compose.runtime.mutableFloatStateOf
32+ import androidx.compose.runtime.mutableIntStateOf
4033import androidx.compose.runtime.mutableStateOf
41- import androidx.compose.runtime.remember
42- import androidx.compose.ui.Alignment
43- import androidx.compose.ui.Modifier
44- import androidx.compose.ui.unit.dp
4534import androidx.navigation.compose.NavHost
4635import androidx.navigation.compose.composable
4736import androidx.navigation.compose.rememberNavController
48- import me.kavishdevar.librepods.screens.AccessibilitySettingsScreen
49- import me.kavishdevar.librepods.screens.EqualizerSettingsScreen
50- import me.kavishdevar.librepods.ui.theme.LibrePodsTheme
51- import org.lsposed.hiddenapibypass.HiddenApiBypass
5237import kotlinx.coroutines.CoroutineScope
5338import kotlinx.coroutines.Dispatchers
5439import kotlinx.coroutines.Job
5540import kotlinx.coroutines.delay
5641import kotlinx.coroutines.launch
5742import kotlinx.coroutines.withContext
5843import kotlinx.coroutines.withTimeout
44+ import me.kavishdevar.librepods.screens.AccessibilitySettingsScreen
45+ import me.kavishdevar.librepods.screens.EqualizerSettingsScreen
46+ import me.kavishdevar.librepods.ui.theme.LibrePodsTheme
47+ import org.lsposed.hiddenapibypass.HiddenApiBypass
5948import java.io.IOException
6049import java.nio.ByteBuffer
6150import java.nio.ByteOrder
6251
52+ @Suppress(" PrivatePropertyName" )
6353class CustomDevice : ComponentActivity () {
6454 private val TAG = " AirPodsAccessibilitySettings"
6555 private var socket: BluetoothSocket ? = null
6656 private val deviceAddress = " 28:2D:7F:C2:05:5B"
67- private val psm = 31
6857 private val uuid: ParcelUuid = ParcelUuid .fromString(" 00000000-0000-0000-0000-00000000000" )
6958
7059 // Data states
7160 private val isConnected = mutableStateOf(false )
72- private val leftAmplification = mutableStateOf (1.0f )
73- private val leftTone = mutableStateOf (1.0f )
74- private val leftAmbientNoiseReduction = mutableStateOf (0.5f )
61+ private val leftAmplification = mutableFloatStateOf (1.0f )
62+ private val leftTone = mutableFloatStateOf (1.0f )
63+ private val leftAmbientNoiseReduction = mutableFloatStateOf (0.5f )
7564 private val leftConversationBoost = mutableStateOf(false )
7665 private val leftEQ = mutableStateOf(FloatArray (8 ) { 50.0f })
7766
78- private val rightAmplification = mutableStateOf (1.0f )
79- private val rightTone = mutableStateOf (1.0f )
80- private val rightAmbientNoiseReduction = mutableStateOf (0.5f )
67+ private val rightAmplification = mutableFloatStateOf (1.0f )
68+ private val rightTone = mutableFloatStateOf (1.0f )
69+ private val rightAmbientNoiseReduction = mutableFloatStateOf (0.5f )
8170 private val rightConversationBoost = mutableStateOf(false )
8271 private val rightEQ = mutableStateOf(FloatArray (8 ) { 50.0f })
8372
8473 private val singleMode = mutableStateOf(false )
85- private val amplification = mutableStateOf (1.0f )
86- private val balance = mutableStateOf (0.5f )
74+ private val amplification = mutableFloatStateOf (1.0f )
75+ private val balance = mutableFloatStateOf (0.5f )
8776
88- private val retryCount = mutableStateOf (0 )
77+ private val retryCount = mutableIntStateOf (0 )
8978 private val showRetryButton = mutableStateOf(false )
9079 private val maxRetries = 3
9180
@@ -146,18 +135,19 @@ class CustomDevice : ComponentActivity() {
146135 socket?.close()
147136 }
148137
138+ @SuppressLint(" MissingPermission" )
149139 private suspend fun connectL2CAP () {
150- retryCount.value = 0
140+ retryCount.intValue = 0
151141 // Close any existing socket
152142 socket?.close()
153143 socket = null
154- while (retryCount.value < maxRetries) {
144+ while (retryCount.intValue < maxRetries) {
155145 try {
156- Log .d(TAG , " Starting L2CAP connection setup, attempt ${retryCount.value + 1 } " )
146+ Log .d(TAG , " Starting L2CAP connection setup, attempt ${retryCount.intValue + 1 } " )
157147 HiddenApiBypass .addHiddenApiExemptions(" Landroid/bluetooth/BluetoothSocket;" )
158148 val manager = getSystemService(BLUETOOTH_SERVICE ) as BluetoothManager
159149 val device: BluetoothDevice = manager.adapter.getRemoteDevice(deviceAddress)
160- socket = createBluetoothSocket(device, psm )
150+ socket = createBluetoothSocket(device)
161151
162152 withTimeout(5000L ) {
163153 socket?.connect()
@@ -177,9 +167,9 @@ class CustomDevice : ComponentActivity() {
177167
178168 return
179169 } catch (e: Exception ) {
180- Log .e(TAG , " Failed to connect, attempt ${retryCount.value + 1 } : ${e.message} " )
181- retryCount.value ++
182- if (retryCount.value < maxRetries) {
170+ Log .e(TAG , " Failed to connect, attempt ${retryCount.intValue + 1 } : ${e.message} " )
171+ retryCount.intValue ++
172+ if (retryCount.intValue < maxRetries) {
183173 delay(2000 ) // Wait 2 seconds before retry
184174 }
185175 }
@@ -193,7 +183,7 @@ class CustomDevice : ComponentActivity() {
193183 }
194184 }
195185
196- private fun createBluetoothSocket (device : BluetoothDevice , psm : Int ): BluetoothSocket {
186+ private fun createBluetoothSocket (device : BluetoothDevice ): BluetoothSocket {
197187 val type = 3 // L2CAP
198188 val constructorSpecs = listOf (
199189 arrayOf(device, type, true , true , 31 , uuid),
@@ -300,18 +290,18 @@ class CustomDevice : ComponentActivity() {
300290 leftEQ.value = newLeftEQ
301291 if (singleMode.value) rightEQ.value = newLeftEQ
302292
303- leftAmplification.value = buffer.float
304- Log .d(TAG , " Parsed left amplification: ${leftAmplification.value } " )
305- leftTone.value = buffer.float
306- Log .d(TAG , " Parsed left tone: ${leftTone.value } " )
307- if (singleMode.value) rightTone.value = leftTone.value
293+ leftAmplification.floatValue = buffer.float
294+ Log .d(TAG , " Parsed left amplification: ${leftAmplification.floatValue } " )
295+ leftTone.floatValue = buffer.float
296+ Log .d(TAG , " Parsed left tone: ${leftTone.floatValue } " )
297+ if (singleMode.value) rightTone.floatValue = leftTone.floatValue
308298 val leftConvFloat = buffer.float
309299 leftConversationBoost.value = leftConvFloat > 0.5f
310300 Log .d(TAG , " Parsed left conversation boost: $leftConvFloat (${leftConversationBoost.value} )" )
311301 if (singleMode.value) rightConversationBoost.value = leftConversationBoost.value
312- leftAmbientNoiseReduction.value = buffer.float
313- Log .d(TAG , " Parsed left ambient noise reduction: ${leftAmbientNoiseReduction.value } " )
314- if (singleMode.value) rightAmbientNoiseReduction.value = leftAmbientNoiseReduction.value
302+ leftAmbientNoiseReduction.floatValue = buffer.float
303+ Log .d(TAG , " Parsed left ambient noise reduction: ${leftAmbientNoiseReduction.floatValue } " )
304+ if (singleMode.value) rightAmbientNoiseReduction.floatValue = leftAmbientNoiseReduction.floatValue
315305
316306 // Right bud
317307 val newRightEQ = rightEQ.value.copyOf()
@@ -321,24 +311,24 @@ class CustomDevice : ComponentActivity() {
321311 }
322312 rightEQ.value = newRightEQ
323313
324- rightAmplification.value = buffer.float
325- Log .d(TAG , " Parsed right amplification: ${rightAmplification.value } " )
326- rightTone.value = buffer.float
327- Log .d(TAG , " Parsed right tone: ${rightTone.value } " )
314+ rightAmplification.floatValue = buffer.float
315+ Log .d(TAG , " Parsed right amplification: ${rightAmplification.floatValue } " )
316+ rightTone.floatValue = buffer.float
317+ Log .d(TAG , " Parsed right tone: ${rightTone.floatValue } " )
328318 val rightConvFloat = buffer.float
329319 rightConversationBoost.value = rightConvFloat > 0.5f
330320 Log .d(TAG , " Parsed right conversation boost: $rightConvFloat (${rightConversationBoost.value} )" )
331- rightAmbientNoiseReduction.value = buffer.float
332- Log .d(TAG , " Parsed right ambient noise reduction: ${rightAmbientNoiseReduction.value } " )
321+ rightAmbientNoiseReduction.floatValue = buffer.float
322+ Log .d(TAG , " Parsed right ambient noise reduction: ${rightAmbientNoiseReduction.floatValue } " )
333323
334324 Log .d(TAG , " Settings parsed successfully" )
335325
336326 // Update single mode values if in single mode
337327 if (singleMode.value) {
338- val avg = (leftAmplification.value + rightAmplification.value ) / 2
339- amplification.value = avg.coerceIn(0f , 1f )
340- val diff = rightAmplification.value - leftAmplification.value
341- balance.value = (0.5f + diff / (2 * avg)).coerceIn(0f , 1f )
328+ val avg = (leftAmplification.floatValue + rightAmplification.floatValue ) / 2
329+ amplification.floatValue = avg.coerceIn(0f , 1f )
330+ val diff = rightAmplification.floatValue - leftAmplification.floatValue
331+ balance.floatValue = (0.5f + diff / (2 * avg)).coerceIn(0f , 1f )
342332 }
343333 }
344334
@@ -363,19 +353,19 @@ class CustomDevice : ComponentActivity() {
363353 for (eq in leftEQ.value) {
364354 buffer.putFloat(eq)
365355 }
366- buffer.putFloat(leftAmplification.value )
367- buffer.putFloat(leftTone.value )
356+ buffer.putFloat(leftAmplification.floatValue )
357+ buffer.putFloat(leftTone.floatValue )
368358 buffer.putFloat(if (leftConversationBoost.value) 1.0f else 0.0f )
369- buffer.putFloat(leftAmbientNoiseReduction.value )
359+ buffer.putFloat(leftAmbientNoiseReduction.floatValue )
370360
371361 // Right bud
372362 for (eq in rightEQ.value) {
373363 buffer.putFloat(eq)
374364 }
375- buffer.putFloat(rightAmplification.value )
376- buffer.putFloat(rightTone.value )
365+ buffer.putFloat(rightAmplification.floatValue )
366+ buffer.putFloat(rightTone.floatValue )
377367 buffer.putFloat(if (rightConversationBoost.value) 1.0f else 0.0f )
378- buffer.putFloat(rightAmbientNoiseReduction.value )
368+ buffer.putFloat(rightAmbientNoiseReduction.floatValue )
379369
380370 val packet = buffer.array()
381371 Log .d(TAG , " Packet length: ${packet.size} " )
@@ -393,4 +383,4 @@ class CustomDevice : ComponentActivity() {
393383 }
394384 }
395385 }
396- }
386+ }
0 commit comments