diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 8494567..3ebe1af 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -35,8 +35,6 @@
android:label="@string/title_activity_custom_device"
android:theme="@style/Theme.ALN">
-
-
@@ -46,17 +44,10 @@
android:theme="@style/Theme.ALN">
-
-
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/java/me/kavishdevar/aln/AirPodsQSService.kt b/android/app/src/main/java/me/kavishdevar/aln/AirPodsQSService.kt
index 4cc67af..6dc586d 100644
--- a/android/app/src/main/java/me/kavishdevar/aln/AirPodsQSService.kt
+++ b/android/app/src/main/java/me/kavishdevar/aln/AirPodsQSService.kt
@@ -10,20 +10,17 @@ import android.service.quicksettings.TileService
import android.util.Log
class AirPodsQSService: TileService() {
- private val sharedPreferences = ServiceManager.getService()?.getSharedPreferences("me.kavishdevar.aln", Context.MODE_PRIVATE)
- private val offListeningModeEnabled = sharedPreferences?.getBoolean("off_listening_mode", false) == true
- private val ancModes = if (offListeningModeEnabled) listOf(NoiseControlMode.OFF.name, NoiseControlMode.NOISE_CANCELLATION.name, NoiseControlMode.TRANSPARENCY.name, NoiseControlMode.ADAPTIVE.name) else listOf(NoiseControlMode.NOISE_CANCELLATION.name, NoiseControlMode.TRANSPARENCY.name, NoiseControlMode.ADAPTIVE.name)
- private var currentModeIndex = if (offListeningModeEnabled) 3 else 2
+ private val ancModes = listOf(NoiseControlMode.NOISE_CANCELLATION.name, NoiseControlMode.TRANSPARENCY.name, NoiseControlMode.ADAPTIVE.name)
+ private var currentModeIndex = 2
private lateinit var ancStatusReceiver: BroadcastReceiver
private lateinit var availabilityReceiver: BroadcastReceiver
@SuppressLint("InlinedApi")
override fun onStartListening() {
- Log.d("AirPodsQSService", "off mode: $offListeningModeEnabled")
super.onStartListening()
- currentModeIndex = (ServiceManager.getService()?.getANC()?.minus(if (offListeningModeEnabled) 1 else 2)) ?: if (offListeningModeEnabled) 3 else 2
+ currentModeIndex = (ServiceManager.getService()?.getANC()?.minus(1)) ?: -1
if (currentModeIndex == -1) {
- currentModeIndex = if (offListeningModeEnabled) 3 else 2
+ currentModeIndex = 2
}
if (ServiceManager.getService() == null) {
@@ -42,7 +39,7 @@ class AirPodsQSService: TileService() {
ancStatusReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val ancStatus = intent.getIntExtra("data", 4)
- currentModeIndex = ancStatus - if (offListeningModeEnabled) 1 else 2
+ currentModeIndex = ancStatus - 1
updateTile()
}
}
@@ -89,10 +86,9 @@ class AirPodsQSService: TileService() {
override fun onClick() {
super.onClick()
Log.d("QuickSettingTileService", "ANC tile clicked")
- Log.d("QuickSettingTileService", "Current mode index: $currentModeIndex, ancModes size: ${ancModes.size}")
currentModeIndex = (currentModeIndex + 1) % ancModes.size
- Log.d("QuickSettingTileService", "New mode index: $currentModeIndex")
- switchAncMode(if (offListeningModeEnabled) currentModeIndex + 1 else currentModeIndex + 2)
+ Log.d("QuickSettingTileService", "New mode index: $currentModeIndex, would be set to ${currentModeIndex + 1}")
+ switchAncMode()
}
private fun updateTile() {
@@ -102,10 +98,11 @@ class AirPodsQSService: TileService() {
qsTile.updateTile()
}
- private fun switchAncMode(modeIndex: Int) {
- currentModeIndex = if (offListeningModeEnabled) modeIndex else modeIndex - 1
+ private fun switchAncMode() {
val airPodsService = ServiceManager.getService()
- airPodsService?.setANCMode(if (offListeningModeEnabled) modeIndex + 1 else modeIndex)
+ Log.d("QuickSettingTileService", "Setting ANC mode to ${currentModeIndex + 2}")
+ airPodsService?.setANCMode(currentModeIndex + 2)
+ Log.d("QuickSettingTileService", "ANC mode set to ${currentModeIndex + 2}")
updateTile()
}
}
\ No newline at end of file
diff --git a/android/app/src/main/java/me/kavishdevar/aln/AirPodsService.kt b/android/app/src/main/java/me/kavishdevar/aln/AirPodsService.kt
index 1c6cafe..6426433 100644
--- a/android/app/src/main/java/me/kavishdevar/aln/AirPodsService.kt
+++ b/android/app/src/main/java/me/kavishdevar/aln/AirPodsService.kt
@@ -23,10 +23,21 @@ import android.widget.RemoteViews
import androidx.core.app.NotificationCompat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.lsposed.hiddenapibypass.HiddenApiBypass
+object ServiceManager {
+ private var service: AirPodsService? = null
+ @Synchronized
+ fun getService(): AirPodsService? {
+ return service
+ }
+ @Synchronized
+ fun setService(service: AirPodsService?) {
+ this.service = service
+ }
+}
+
@Suppress("unused")
class AirPodsService: Service() {
inner class LocalBinder : Binder() {
@@ -185,6 +196,7 @@ class AirPodsService: Service() {
@SuppressLint("InlinedApi", "MissingPermission")
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d("AirPodsService", "Service started")
+ ServiceManager.setService(this)
startForegroundNotification()
registerReceiver(bluetoothReceiver, BluetoothReceiver.buildFilter(), RECEIVER_EXPORTED)
@@ -215,7 +227,7 @@ class AirPodsService: Service() {
registerReceiver(connectionReceiver, intentFilter, RECEIVER_EXPORTED)
val bluetoothAdapter = getSystemService(BluetoothManager::class.java).adapter
- bluetoothAdapter.bondedDevices.forEach { device ->
+ bluetoothAdapter.bondedDevices.forEach { device ->
if (device.uuids.contains(ParcelUuid.fromString("74ec2172-0bad-4d01-8f77-997b2be0722a"))) {
bluetoothAdapter.getProfileProxy(this, object : BluetoothProfile.ServiceListener {
override fun onServiceConnected(profile: Int, proxy: BluetoothProfile) {
@@ -223,6 +235,9 @@ class AirPodsService: Service() {
val connectedDevices = proxy.connectedDevices
if (connectedDevices.isNotEmpty()) {
connectToSocket(device)
+ this@AirPodsService.sendBroadcast(
+ Intent(AirPodsNotifications.AIRPODS_CONNECTED)
+ )
}
}
bluetoothAdapter.closeProfileProxy(profile, proxy)
@@ -243,6 +258,12 @@ class AirPodsService: Service() {
HiddenApiBypass.addHiddenApiExemptions("Landroid/bluetooth/BluetoothSocket;")
val uuid: ParcelUuid = ParcelUuid.fromString("74ec2172-0bad-4d01-8f77-997b2be0722a")
+ try {
+ socket.close()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+
try {
socket = HiddenApiBypass.newInstance(
BluetoothSocket::class.java,
@@ -282,21 +303,17 @@ class AirPodsService: Service() {
this@AirPodsService.device = device
isConnected = true
socket.let { it ->
- CoroutineScope(Dispatchers.IO).launch {
- it.outputStream.write(Enums.HANDSHAKE.value)
- it.outputStream.flush()
- delay(500)
- it.outputStream.write(Enums.SET_SPECIFIC_FEATURES.value)
- it.outputStream.flush()
- delay(500)
- it.outputStream.write(Enums.REQUEST_NOTIFICATIONS.value)
- it.outputStream.flush()
- }
-
+ it.outputStream.write(Enums.HANDSHAKE.value)
+ it.outputStream.flush()
+ it.outputStream.write(Enums.SET_SPECIFIC_FEATURES.value)
+ it.outputStream.flush()
+ it.outputStream.write(Enums.REQUEST_NOTIFICATIONS.value)
+ it.outputStream.flush()
sendBroadcast(
Intent(AirPodsNotifications.AIRPODS_CONNECTED)
.putExtra("device", device)
)
+
CoroutineScope(Dispatchers.IO).launch {
while (socket.isConnected == true) {
socket.let {
@@ -316,7 +333,7 @@ class AirPodsService: Service() {
}
else if (bytesRead == -1) {
Log.d("AirPods Service", "Socket closed (bytesRead = -1)")
- socket.close()
+// socket.close()
sendBroadcast(Intent(AirPodsNotifications.AIRPODS_DISCONNECTED))
return@launch
}
diff --git a/android/app/src/main/java/me/kavishdevar/aln/AirPodsSettingsScreen.kt b/android/app/src/main/java/me/kavishdevar/aln/AirPodsSettingsScreen.kt
index f3a901a..f7ab83a 100644
--- a/android/app/src/main/java/me/kavishdevar/aln/AirPodsSettingsScreen.kt
+++ b/android/app/src/main/java/me/kavishdevar/aln/AirPodsSettingsScreen.kt
@@ -2,6 +2,8 @@ package me.kavishdevar.aln
import android.annotation.SuppressLint
import android.bluetooth.BluetoothDevice
+import android.bluetooth.BluetoothManager
+import android.bluetooth.BluetoothProfile
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Context.MODE_PRIVATE
@@ -9,6 +11,8 @@ import android.content.Intent
import android.content.IntentFilter
import android.content.SharedPreferences
import android.os.Build
+import android.os.ParcelUuid
+import android.util.Log
import androidx.annotation.RequiresApi
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.foundation.Image
@@ -37,6 +41,7 @@ import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.KeyboardArrowRight
+import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
@@ -84,6 +89,7 @@ import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import com.primex.core.ExperimentalToolkitApi
import com.primex.core.blur.newBackgroundBlur
+import me.kavishdevar.aln.AirPodsService
import kotlin.math.roundToInt
@@ -157,38 +163,19 @@ fun BatteryView(service: AirPodsService, preview: Boolean = false) {
horizontalArrangement = Arrangement.Center
) {
if (left?.status != BatteryStatus.DISCONNECTED) {
- Row (
- horizontalArrangement = Arrangement.SpaceEvenly,
- modifier = Modifier
- .weight(1f)
- ) {
- Text(
- text = "\uDBC6\uDCE5",
- fontFamily = FontFamily(Font(R.font.sf_pro)),
- )
- BatteryIndicator(
- left?.level ?: 0,
- left?.status == BatteryStatus.CHARGING
- )
- }
+ BatteryIndicator(
+ left?.level ?: 0,
+ left?.status == BatteryStatus.CHARGING
+ )
+ }
+ if (left?.status != BatteryStatus.DISCONNECTED && right?.status != BatteryStatus.DISCONNECTED) {
+ Spacer(modifier = Modifier.width(16.dp))
}
if (right?.status != BatteryStatus.DISCONNECTED) {
- Row (
- horizontalArrangement = Arrangement.Center,
- modifier = Modifier
- .weight(1f)
- ) {
- Text(
- text = "\uDBC6\uDCE8",
- fontFamily = FontFamily(Font(R.font.sf_pro)),
- modifier = Modifier
- .fillMaxWidth(0.5f)
- )
- BatteryIndicator(
- right?.level ?: 0,
- right?.status == BatteryStatus.CHARGING
- )
- }
+ BatteryIndicator(
+ right?.level ?: 0,
+ right?.status == BatteryStatus.CHARGING
+ )
}
}
}
@@ -556,7 +543,41 @@ fun AirPodsSettingsScreen(device: BluetoothDevice?, service: AirPodsService,
},
colors = TopAppBarDefaults.centerAlignedTopAppBarColors(
containerColor = if (MaterialTheme.colorScheme.surface.luminance() < 0.5) Color.Black.copy(0.3f) else Color(0xFFF2F2F7).copy(0.2f),
- )
+ ),
+ actions = {
+ val context = LocalContext.current
+ IconButton(
+ onClick = {
+ val bluetoothAdapter = context.getSystemService(BluetoothManager::class.java).adapter
+ bluetoothAdapter.bondedDevices.forEach { device ->
+ if (device.uuids.contains(ParcelUuid.fromString("74ec2172-0bad-4d01-8f77-997b2be0722a"))) {
+ bluetoothAdapter.getProfileProxy(context, object : BluetoothProfile.ServiceListener {
+ override fun onServiceConnected(profile: Int, proxy: BluetoothProfile) {
+ if (profile == BluetoothProfile.A2DP) {
+ val connectedDevices = proxy.connectedDevices
+ if (connectedDevices.isNotEmpty()) {
+ service.connectToSocket(device)
+ }
+ }
+ bluetoothAdapter.closeProfileProxy(profile, proxy)
+ }
+
+ override fun onServiceDisconnected(profile: Int) { }
+ }, BluetoothProfile.A2DP)
+ }
+ }
+ },
+ colors = IconButtonDefaults.iconButtonColors(
+ containerColor = Color.Transparent,
+ contentColor = if (MaterialTheme.colorScheme.surface.luminance() < 0.5) Color.White else Color.Black
+ )
+ ) {
+ Icon(
+ imageVector = Icons.Default.Refresh,
+ contentDescription = "Settings",
+ )
+ }
+ }
)
}
) { paddingValues ->
@@ -1467,8 +1488,8 @@ fun BatteryIndicator(batteryPercentage: Int, charging: Boolean = false) {
val batteryWidth = 40.dp
val batteryHeight = 15.dp
val batteryCornerRadius = 4.dp
- val tipWidth = 4.dp
- val tipHeight = batteryHeight * 0.3f
+ val tipWidth = 5.dp
+ val tipHeight = batteryHeight * 0.375f
Column(
horizontalAlignment = Alignment.CenterHorizontally
diff --git a/android/app/src/main/java/me/kavishdevar/aln/BootReceiver.kt b/android/app/src/main/java/me/kavishdevar/aln/BootReceiver.kt
index 38c4f34..df514ac 100644
--- a/android/app/src/main/java/me/kavishdevar/aln/BootReceiver.kt
+++ b/android/app/src/main/java/me/kavishdevar/aln/BootReceiver.kt
@@ -1,4 +1,14 @@
package me.kavishdevar.aln
-class BootReceiver {
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+
+class BootReceiver: BroadcastReceiver() {
+ override fun onReceive(context: Context?, intent: Intent?) {
+ when (intent?.action) {
+ Intent.ACTION_MY_PACKAGE_REPLACED -> try { context?.startForegroundService(Intent(context, AirPodsService::class.java)) } catch (e: Exception) { e.printStackTrace() }
+ Intent.ACTION_BOOT_COMPLETED -> try { context?.startForegroundService(Intent(context, AirPodsService::class.java)) } catch (e: Exception) { e.printStackTrace() }
+ }
+ }
}
\ No newline at end of file
diff --git a/android/app/src/main/java/me/kavishdevar/aln/MainActivity.kt b/android/app/src/main/java/me/kavishdevar/aln/MainActivity.kt
index 3d024ea..36fd3fd 100644
--- a/android/app/src/main/java/me/kavishdevar/aln/MainActivity.kt
+++ b/android/app/src/main/java/me/kavishdevar/aln/MainActivity.kt
@@ -70,6 +70,22 @@ class MainActivity : ComponentActivity() {
}
super.onDestroy()
}
+
+ override fun onStop() {
+ try {
+ unbindService(serviceConnection)
+ Log.d("MainActivity", "Unbound service")
+ } catch (e: Exception) {
+ Log.e("MainActivity", "Error while unbinding service: $e")
+ }
+ try {
+ unregisterReceiver(connectionStatusReceiver)
+ Log.d("MainActivity", "Unregistered receiver")
+ } catch (e: Exception) {
+ Log.e("MainActivity", "Error while unregistering receiver: $e")
+ }
+ super.onStop()
+ }
}
@SuppressLint("MissingPermission", "InlinedApi")
@@ -86,7 +102,6 @@ fun Main() {
val airPodsService = remember { mutableStateOf(null) }
if (permissionState.allPermissionsGranted) {
- Log.d("MainActivity", "HIIIIIIIIIIIIIII")
val context = LocalContext.current
val navController = rememberNavController()
diff --git a/android/app/src/main/java/me/kavishdevar/aln/OldAirPodsService.kt b/android/app/src/main/java/me/kavishdevar/aln/OldAirPodsService.kt
index deb8be0..6605f1c 100644
--- a/android/app/src/main/java/me/kavishdevar/aln/OldAirPodsService.kt
+++ b/android/app/src/main/java/me/kavishdevar/aln/OldAirPodsService.kt
@@ -1,463 +1,463 @@
-@file:Suppress("unused")
-
-package me.kavishdevar.aln
-
-import android.annotation.SuppressLint
-import android.app.Notification
-import android.app.NotificationChannel
-import android.app.NotificationManager
-import android.app.Service
-import android.bluetooth.BluetoothDevice
-import android.bluetooth.BluetoothManager
-import android.bluetooth.BluetoothProfile
-import android.bluetooth.BluetoothSocket
-import android.content.BroadcastReceiver
-import android.content.Context
-import android.content.Intent
-import android.content.IntentFilter
-import android.media.AudioManager
-import android.os.Binder
-import android.os.Build
-import android.os.IBinder
-import android.os.ParcelUuid
-import android.util.Log
-import androidx.core.app.NotificationCompat
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
-import org.lsposed.hiddenapibypass.HiddenApiBypass
-
-object ServiceManager {
- private var service: OldAirPodsService? = null
- @Synchronized
- fun getService(): OldAirPodsService? {
- return service
- }
- @Synchronized
- fun setService(service: OldAirPodsService?) {
- this.service = service
- }
-}
-
-class OldAirPodsService : Service() {
- inner class LocalBinder : Binder() {
- fun getService(): OldAirPodsService = this@OldAirPodsService
- }
-
- override fun onBind(intent: Intent?): IBinder {
- return LocalBinder()
- }
-
- var isConnected: Boolean = false
- private var socket: BluetoothSocket? = null
-
- fun sendPacket(packet: String) {
- val fromHex = packet.split(" ").map { it.toInt(16).toByte() }
- socket?.outputStream?.write(fromHex.toByteArray())
- socket?.outputStream?.flush()
- }
-
- fun setANCMode(mode: Int) {
- when (mode) {
- 1 -> {
- socket?.outputStream?.write(Enums.NOISE_CANCELLATION_OFF.value)
- }
- 2 -> {
- socket?.outputStream?.write(Enums.NOISE_CANCELLATION_ON.value)
- }
- 3 -> {
- socket?.outputStream?.write(Enums.NOISE_CANCELLATION_TRANSPARENCY.value)
- }
- 4 -> {
- socket?.outputStream?.write(Enums.NOISE_CANCELLATION_ADAPTIVE.value)
- }
- }
- socket?.outputStream?.flush()
- }
-
- fun setCAEnabled(enabled: Boolean) {
- socket?.outputStream?.write(if (enabled) Enums.SET_CONVERSATION_AWARENESS_ON.value else Enums.SET_CONVERSATION_AWARENESS_OFF.value)
- }
-
- fun setOffListeningMode(enabled: Boolean) {
- socket?.outputStream?.write(byteArrayOf(0x04, 0x00 ,0x04, 0x00, 0x09, 0x00, 0x34, if (enabled) 0x01 else 0x02, 0x00, 0x00, 0x00))
- }
-
- fun setAdaptiveStrength(strength: Int) {
- val bytes = byteArrayOf(0x04, 0x00, 0x04, 0x00, 0x09, 0x00, 0x2E, strength.toByte(), 0x00, 0x00, 0x00)
- socket?.outputStream?.write(bytes)
- socket?.outputStream?.flush()
- }
-
- fun setPressSpeed(speed: Int) {
- val bytes = byteArrayOf(0x04, 0x00, 0x04, 0x00, 0x09, 0x00, 0x17, speed.toByte(), 0x00, 0x00, 0x00)
- socket?.outputStream?.write(bytes)
- socket?.outputStream?.flush()
- }
-
- fun setPressAndHoldDuration(speed: Int) {
- val bytes = byteArrayOf(0x04, 0x00, 0x04, 0x00, 0x09, 0x00, 0x18, speed.toByte(), 0x00, 0x00, 0x00)
- socket?.outputStream?.write(bytes)
- socket?.outputStream?.flush()
- }
-
- fun setNoiseCancellationWithOnePod(enabled: Boolean) {
- val bytes = byteArrayOf(0x04, 0x00, 0x04, 0x00, 0x09, 0x00, 0x1B, if (enabled) 0x01 else 0x02, 0x00, 0x00, 0x00)
- socket?.outputStream?.write(bytes)
- socket?.outputStream?.flush()
- }
-
- fun setVolumeControl(enabled: Boolean) {
- val bytes = byteArrayOf(0x04, 0x00, 0x04, 0x00, 0x09, 0x00, 0x25, if (enabled) 0x01 else 0x02, 0x00, 0x00, 0x00)
- socket?.outputStream?.write(bytes)
- socket?.outputStream?.flush()
- }
-
- fun setVolumeSwipeSpeed(speed: Int) {
- val bytes = byteArrayOf(0x04, 0x00, 0x04, 0x00, 0x09, 0x00, 0x23, speed.toByte(), 0x00, 0x00, 0x00)
- socket?.outputStream?.write(bytes)
- socket?.outputStream?.flush()
- }
-
- fun setToneVolume(volume: Int) {
- val bytes = byteArrayOf(0x04, 0x00, 0x04, 0x00, 0x09, 0x00, 0x1F, volume.toByte(), 0x50, 0x00, 0x00)
- socket?.outputStream?.write(bytes)
- socket?.outputStream?.flush()
- }
-
- val earDetectionNotification = AirPodsNotifications.EarDetection()
- val ancNotification = AirPodsNotifications.ANC()
- val batteryNotification = AirPodsNotifications.BatteryNotification()
- val conversationAwarenessNotification = AirPodsNotifications.ConversationalAwarenessNotification()
-
- var earDetectionEnabled = true
-
- fun setCaseChargingSounds(enabled: Boolean) {
- val bytes = byteArrayOf(0x12, 0x3a, 0x00, 0x01, 0x00, 0x08, if (enabled) 0x00 else 0x01)
- socket?.outputStream?.write(bytes)
- socket?.outputStream?.flush()
- }
-
- fun setEarDetection(enabled: Boolean) {
- earDetectionEnabled = enabled
- }
-
- fun getBattery(): List {
- return batteryNotification.getBattery()
- }
-
- fun getANC(): Int {
- return ancNotification.status
- }
-
- private fun createNotification(): Notification {
- val channelId = "battery"
- val notificationBuilder = NotificationCompat.Builder(this, channelId)
- .setSmallIcon(R.drawable.pro_2_buds)
- .setContentTitle("AirPods Connected")
- .setOngoing(true)
- .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
-
- val channel =
- NotificationChannel(channelId, "Battery Notification", NotificationManager.IMPORTANCE_LOW)
-
- val notificationManager = getSystemService(NotificationManager::class.java)
- notificationManager.createNotificationChannel(channel)
- return notificationBuilder.build()
- }
-
- fun disconnectAudio(context: Context, device: BluetoothDevice?) {
- val bluetoothAdapter = context.getSystemService(BluetoothManager::class.java).adapter
-
- bluetoothAdapter?.getProfileProxy(context, object : BluetoothProfile.ServiceListener {
- override fun onServiceConnected(profile: Int, proxy: BluetoothProfile) {
- if (profile == BluetoothProfile.A2DP) {
- try {
- val method = proxy.javaClass.getMethod("disconnect", BluetoothDevice::class.java)
- method.invoke(proxy, device)
- } catch (e: Exception) {
- e.printStackTrace()
- } finally {
- bluetoothAdapter.closeProfileProxy(BluetoothProfile.A2DP, proxy)
- }
- }
- }
-
- override fun onServiceDisconnected(profile: Int) { }
- }, BluetoothProfile.A2DP)
-
- bluetoothAdapter?.getProfileProxy(context, object : BluetoothProfile.ServiceListener {
- override fun onServiceConnected(profile: Int, proxy: BluetoothProfile) {
- if (profile == BluetoothProfile.HEADSET) {
- try {
- val method = proxy.javaClass.getMethod("disconnect", BluetoothDevice::class.java)
- method.invoke(proxy, device)
- } catch (e: Exception) {
- e.printStackTrace()
- } finally {
- bluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, proxy)
- }
- }
- }
-
- override fun onServiceDisconnected(profile: Int) { }
- }, BluetoothProfile.HEADSET)
- }
-
- fun connectAudio(context: Context, device: BluetoothDevice?) {
- val bluetoothAdapter = context.getSystemService(BluetoothManager::class.java).adapter
-
- bluetoothAdapter?.getProfileProxy(context, object : BluetoothProfile.ServiceListener {
- override fun onServiceConnected(profile: Int, proxy: BluetoothProfile) {
- if (profile == BluetoothProfile.A2DP) {
- try {
- val method = proxy.javaClass.getMethod("connect", BluetoothDevice::class.java)
- method.invoke(proxy, device)
- } catch (e: Exception) {
- e.printStackTrace()
- } finally {
- bluetoothAdapter.closeProfileProxy(BluetoothProfile.A2DP, proxy)
- }
- }
- }
-
- override fun onServiceDisconnected(profile: Int) { }
- }, BluetoothProfile.A2DP)
-
- bluetoothAdapter?.getProfileProxy(context, object : BluetoothProfile.ServiceListener {
- override fun onServiceConnected(profile: Int, proxy: BluetoothProfile) {
- if (profile == BluetoothProfile.HEADSET) {
- try {
- val method = proxy.javaClass.getMethod("connect", BluetoothDevice::class.java)
- method.invoke(proxy, device)
- } catch (e: Exception) {
- e.printStackTrace()
- } finally {
- bluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, proxy)
- }
- }
- }
-
- override fun onServiceDisconnected(profile: Int) { }
- }, BluetoothProfile.HEADSET)
- }
-
- fun setName(name: String) {
- val nameBytes = name.toByteArray()
- val bytes = byteArrayOf(0x04, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x01,
- nameBytes.size.toByte(), 0x00) + nameBytes
- socket?.outputStream?.write(bytes)
- socket?.outputStream?.flush()
- val hex = bytes.joinToString(" ") { "%02X".format(it) }
- Log.d("OldAirPodsService", "setName: $name, sent packet: $hex")
- }
-
- @SuppressLint("MissingPermission", "InlinedApi")
- override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
-
- val notification = createNotification()
- startForeground(1, notification)
-
- ServiceManager.setService(this)
-
- if (isConnected) {
- return START_STICKY
- }
- isConnected = true
-
- @Suppress("DEPRECATION") val device = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) intent?.getParcelableExtra("device", BluetoothDevice::class.java) else intent?.getParcelableExtra("device")
-
- HiddenApiBypass.addHiddenApiExemptions("Landroid/bluetooth/BluetoothSocket;")
- val uuid: ParcelUuid = ParcelUuid.fromString("74ec2172-0bad-4d01-8f77-997b2be0722a")
-
- socket = HiddenApiBypass.newInstance(BluetoothSocket::class.java, 3, true, true, device, 0x1001, uuid) as BluetoothSocket?
- try {
- socket?.connect()
- socket?.let { it ->
- it.outputStream.write(Enums.HANDSHAKE.value)
- it.outputStream.write(Enums.SET_SPECIFIC_FEATURES.value)
- it.outputStream.write(Enums.REQUEST_NOTIFICATIONS.value)
- sendBroadcast(Intent(AirPodsNotifications.AIRPODS_CONNECTED))
- it.outputStream.flush()
-
- CoroutineScope(Dispatchers.IO).launch {
- while (socket?.isConnected == true) {
- socket?.let {
- val audioManager = this@OldAirPodsService.getSystemService(AUDIO_SERVICE) as AudioManager
- MediaController.initialize(audioManager)
- val buffer = ByteArray(1024)
- val bytesRead = it.inputStream.read(buffer)
- var data: ByteArray = byteArrayOf()
- if (bytesRead > 0) {
- data = buffer.copyOfRange(0, bytesRead)
- sendBroadcast(Intent(AirPodsNotifications.AIRPODS_DATA).apply {
- putExtra("data", buffer.copyOfRange(0, bytesRead))
- })
- val bytes = buffer.copyOfRange(0, bytesRead)
- val formattedHex = bytes.joinToString(" ") { "%02X".format(it) }
- Log.d("AirPods Data", "Data received: $formattedHex")
- }
- else if (bytesRead == -1) {
- Log.d("AirPods Service", "Socket closed (bytesRead = -1)")
- this@OldAirPodsService.stopForeground(STOP_FOREGROUND_REMOVE)
- socket?.close()
- sendBroadcast(Intent(AirPodsNotifications.AIRPODS_DISCONNECTED))
- return@launch
- }
- var inEar = false
- var inEarData = listOf()
- if (earDetectionNotification.isEarDetectionData(data)) {
- earDetectionNotification.setStatus(data)
- sendBroadcast(Intent(AirPodsNotifications.EAR_DETECTION_DATA).apply {
- val list = earDetectionNotification.status
- val bytes = ByteArray(2)
- bytes[0] = list[0]
- bytes[1] = list[1]
- putExtra("data", bytes)
- })
- Log.d("AirPods Parser", "Ear Detection: ${earDetectionNotification.status[0]} ${earDetectionNotification.status[1]}")
- var justEnabledA2dp = false
- val earReceiver = object : BroadcastReceiver() {
- override fun onReceive(context: Context, intent: Intent) {
- val data = intent.getByteArrayExtra("data")
- if (data != null && earDetectionEnabled) {
- inEar = if (data.find { it == 0x02.toByte() } != null || data.find { it == 0x03.toByte() } != null) {
- data[0] == 0x00.toByte() || data[1] == 0x00.toByte()
- } else {
- data[0] == 0x00.toByte() && data[1] == 0x00.toByte()
- }
-
- val newInEarData = listOf(data[0] == 0x00.toByte(), data[1] == 0x00.toByte())
- if (newInEarData.contains(true) && inEarData == listOf(false, false)) {
- connectAudio(this@OldAirPodsService, device)
- justEnabledA2dp = true
- val bluetoothAdapter = this@OldAirPodsService.getSystemService(BluetoothManager::class.java).adapter
- bluetoothAdapter.getProfileProxy(
- this@OldAirPodsService, object : BluetoothProfile.ServiceListener {
- override fun onServiceConnected(
- profile: Int,
- proxy: BluetoothProfile
- ) {
- if (profile == BluetoothProfile.A2DP) {
- val connectedDevices =
- proxy.connectedDevices
- if (connectedDevices.isNotEmpty()) {
- MediaController.sendPlay()
- }
- }
- bluetoothAdapter.closeProfileProxy(
- profile,
- proxy
- )
- }
-
- override fun onServiceDisconnected(
- profile: Int
- ) {
- }
- }
- ,BluetoothProfile.A2DP
- )
-
- }
- else if (newInEarData == listOf(false, false)){
- disconnectAudio(this@OldAirPodsService, device)
- }
-
- inEarData = newInEarData
-
- if (inEar == true) {
- if (!justEnabledA2dp) {
- justEnabledA2dp = false
- MediaController.sendPlay()
- }
- } else {
- MediaController.sendPause()
- }
- }
- }
- }
-
- val earIntentFilter = IntentFilter(AirPodsNotifications.EAR_DETECTION_DATA)
- this@OldAirPodsService.registerReceiver(earReceiver, earIntentFilter,
- RECEIVER_EXPORTED
- )
- }
- else if (ancNotification.isANCData(data)) {
- ancNotification.setStatus(data)
- sendBroadcast(Intent(AirPodsNotifications.ANC_DATA).apply {
- putExtra("data", ancNotification.status)
- })
- Log.d("AirPods Parser", "ANC: ${ancNotification.status}")
- }
- else if (batteryNotification.isBatteryData(data)) {
- batteryNotification.setBattery(data)
- sendBroadcast(Intent(AirPodsNotifications.BATTERY_DATA).apply {
- putParcelableArrayListExtra("data", ArrayList(batteryNotification.getBattery()))
- })
- for (battery in batteryNotification.getBattery()) {
- Log.d("AirPods Parser", "${battery.getComponentName()}: ${battery.getStatusName()} at ${battery.level}% ")
- }
-// if both are charging, disconnect audio profiles
- if (batteryNotification.getBattery()[0].status == 1 && batteryNotification.getBattery()[1].status == 1) {
- disconnectAudio(this@OldAirPodsService, device)
- }
- else {
- connectAudio(this@OldAirPodsService, device)
- }
-// updatePodsStatus(device!!, batteryNotification.getBattery())
- }
- else if (conversationAwarenessNotification.isConversationalAwarenessData(data)) {
- conversationAwarenessNotification.setData(data)
- sendBroadcast(Intent(AirPodsNotifications.CA_DATA).apply {
- putExtra("data", conversationAwarenessNotification.status)
- })
-
-
- if (conversationAwarenessNotification.status == 1.toByte() || conversationAwarenessNotification.status == 2.toByte()) {
- MediaController.startSpeaking()
- } else if (conversationAwarenessNotification.status == 8.toByte() || conversationAwarenessNotification.status == 9.toByte()) {
- MediaController.stopSpeaking()
- }
-
- Log.d("AirPods Parser", "Conversation Awareness: ${conversationAwarenessNotification.status}")
- }
- else { }
- }
- }
- Log.d("AirPods Service", "Socket closed")
- isConnected = false
- this@OldAirPodsService.stopForeground(STOP_FOREGROUND_REMOVE)
- socket?.close()
- sendBroadcast(Intent(AirPodsNotifications.AIRPODS_DISCONNECTED))
- }
- }
- }
- catch (e: Exception) {
- Log.e("AirPodsSettingsScreen", "Error connecting to device: ${e.message}")
- }
- return START_STICKY
- }
-
- override fun onDestroy() {
- super.onDestroy()
- socket?.close()
- isConnected = false
- ServiceManager.setService(null)
- }
-
- fun setPVEnabled(enabled: Boolean) {
- var hex = "04 00 04 00 09 00 26 ${if (enabled) "01" else "02"} 00 00 00"
- var bytes = hex.split(" ").map { it.toInt(16).toByte() }.toByteArray()
- socket?.outputStream?.write(bytes)
- hex = "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"
- bytes = hex.split(" ").map { it.toInt(16).toByte() }.toByteArray()
- socket?.outputStream?.write(bytes)
- }
-
- fun setLoudSoundReduction(enabled: Boolean) {
- val hex = "52 1B 00 0${if (enabled) "1" else "0"}"
- val bytes = hex.split(" ").map { it.toInt(16).toByte() }.toByteArray()
- socket?.outputStream?.write(bytes)
- }
-}
\ No newline at end of file
+//@file:Suppress("unused")
+//
+//package me.kavishdevar.aln
+//
+//import android.annotation.SuppressLint
+//import android.app.Notification
+//import android.app.NotificationChannel
+//import android.app.NotificationManager
+//import android.app.Service
+//import android.bluetooth.BluetoothDevice
+//import android.bluetooth.BluetoothManager
+//import android.bluetooth.BluetoothProfile
+//import android.bluetooth.BluetoothSocket
+//import android.content.BroadcastReceiver
+//import android.content.Context
+//import android.content.Intent
+//import android.content.IntentFilter
+//import android.media.AudioManager
+//import android.os.Binder
+//import android.os.Build
+//import android.os.IBinder
+//import android.os.ParcelUuid
+//import android.util.Log
+//import androidx.core.app.NotificationCompat
+//import kotlinx.coroutines.CoroutineScope
+//import kotlinx.coroutines.Dispatchers
+//import kotlinx.coroutines.launch
+//import org.lsposed.hiddenapibypass.HiddenApiBypass
+//
+//object ServiceManager {
+// private var service: OldAirPodsService? = null
+// @Synchronized
+// fun getService(): OldAirPodsService? {
+// return service
+// }
+// @Synchronized
+// fun setService(service: OldAirPodsService?) {
+// this.service = service
+// }
+//}
+//
+//class OldAirPodsService : Service() {
+// inner class LocalBinder : Binder() {
+// fun getService(): OldAirPodsService = this@OldAirPodsService
+// }
+//
+// override fun onBind(intent: Intent?): IBinder {
+// return LocalBinder()
+// }
+//
+// var isConnected: Boolean = false
+// private var socket: BluetoothSocket? = null
+//
+// fun sendPacket(packet: String) {
+// val fromHex = packet.split(" ").map { it.toInt(16).toByte() }
+// socket?.outputStream?.write(fromHex.toByteArray())
+// socket?.outputStream?.flush()
+// }
+//
+// fun setANCMode(mode: Int) {
+// when (mode) {
+// 1 -> {
+// socket?.outputStream?.write(Enums.NOISE_CANCELLATION_OFF.value)
+// }
+// 2 -> {
+// socket?.outputStream?.write(Enums.NOISE_CANCELLATION_ON.value)
+// }
+// 3 -> {
+// socket?.outputStream?.write(Enums.NOISE_CANCELLATION_TRANSPARENCY.value)
+// }
+// 4 -> {
+// socket?.outputStream?.write(Enums.NOISE_CANCELLATION_ADAPTIVE.value)
+// }
+// }
+// socket?.outputStream?.flush()
+// }
+//
+// fun setCAEnabled(enabled: Boolean) {
+// socket?.outputStream?.write(if (enabled) Enums.SET_CONVERSATION_AWARENESS_ON.value else Enums.SET_CONVERSATION_AWARENESS_OFF.value)
+// }
+//
+// fun setOffListeningMode(enabled: Boolean) {
+// socket?.outputStream?.write(byteArrayOf(0x04, 0x00 ,0x04, 0x00, 0x09, 0x00, 0x34, if (enabled) 0x01 else 0x02, 0x00, 0x00, 0x00))
+// }
+//
+// fun setAdaptiveStrength(strength: Int) {
+// val bytes = byteArrayOf(0x04, 0x00, 0x04, 0x00, 0x09, 0x00, 0x2E, strength.toByte(), 0x00, 0x00, 0x00)
+// socket?.outputStream?.write(bytes)
+// socket?.outputStream?.flush()
+// }
+//
+// fun setPressSpeed(speed: Int) {
+// val bytes = byteArrayOf(0x04, 0x00, 0x04, 0x00, 0x09, 0x00, 0x17, speed.toByte(), 0x00, 0x00, 0x00)
+// socket?.outputStream?.write(bytes)
+// socket?.outputStream?.flush()
+// }
+//
+// fun setPressAndHoldDuration(speed: Int) {
+// val bytes = byteArrayOf(0x04, 0x00, 0x04, 0x00, 0x09, 0x00, 0x18, speed.toByte(), 0x00, 0x00, 0x00)
+// socket?.outputStream?.write(bytes)
+// socket?.outputStream?.flush()
+// }
+//
+// fun setNoiseCancellationWithOnePod(enabled: Boolean) {
+// val bytes = byteArrayOf(0x04, 0x00, 0x04, 0x00, 0x09, 0x00, 0x1B, if (enabled) 0x01 else 0x02, 0x00, 0x00, 0x00)
+// socket?.outputStream?.write(bytes)
+// socket?.outputStream?.flush()
+// }
+//
+// fun setVolumeControl(enabled: Boolean) {
+// val bytes = byteArrayOf(0x04, 0x00, 0x04, 0x00, 0x09, 0x00, 0x25, if (enabled) 0x01 else 0x02, 0x00, 0x00, 0x00)
+// socket?.outputStream?.write(bytes)
+// socket?.outputStream?.flush()
+// }
+//
+// fun setVolumeSwipeSpeed(speed: Int) {
+// val bytes = byteArrayOf(0x04, 0x00, 0x04, 0x00, 0x09, 0x00, 0x23, speed.toByte(), 0x00, 0x00, 0x00)
+// socket?.outputStream?.write(bytes)
+// socket?.outputStream?.flush()
+// }
+//
+// fun setToneVolume(volume: Int) {
+// val bytes = byteArrayOf(0x04, 0x00, 0x04, 0x00, 0x09, 0x00, 0x1F, volume.toByte(), 0x50, 0x00, 0x00)
+// socket?.outputStream?.write(bytes)
+// socket?.outputStream?.flush()
+// }
+//
+// val earDetectionNotification = AirPodsNotifications.EarDetection()
+// val ancNotification = AirPodsNotifications.ANC()
+// val batteryNotification = AirPodsNotifications.BatteryNotification()
+// val conversationAwarenessNotification = AirPodsNotifications.ConversationalAwarenessNotification()
+//
+// var earDetectionEnabled = true
+//
+// fun setCaseChargingSounds(enabled: Boolean) {
+// val bytes = byteArrayOf(0x12, 0x3a, 0x00, 0x01, 0x00, 0x08, if (enabled) 0x00 else 0x01)
+// socket?.outputStream?.write(bytes)
+// socket?.outputStream?.flush()
+// }
+//
+// fun setEarDetection(enabled: Boolean) {
+// earDetectionEnabled = enabled
+// }
+//
+// fun getBattery(): List {
+// return batteryNotification.getBattery()
+// }
+//
+// fun getANC(): Int {
+// return ancNotification.status
+// }
+//
+// private fun createNotification(): Notification {
+// val channelId = "battery"
+// val notificationBuilder = NotificationCompat.Builder(this, channelId)
+// .setSmallIcon(R.drawable.pro_2_buds)
+// .setContentTitle("AirPods Connected")
+// .setOngoing(true)
+// .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
+//
+// val channel =
+// NotificationChannel(channelId, "Battery Notification", NotificationManager.IMPORTANCE_LOW)
+//
+// val notificationManager = getSystemService(NotificationManager::class.java)
+// notificationManager.createNotificationChannel(channel)
+// return notificationBuilder.build()
+// }
+//
+// fun disconnectAudio(context: Context, device: BluetoothDevice?) {
+// val bluetoothAdapter = context.getSystemService(BluetoothManager::class.java).adapter
+//
+// bluetoothAdapter?.getProfileProxy(context, object : BluetoothProfile.ServiceListener {
+// override fun onServiceConnected(profile: Int, proxy: BluetoothProfile) {
+// if (profile == BluetoothProfile.A2DP) {
+// try {
+// val method = proxy.javaClass.getMethod("disconnect", BluetoothDevice::class.java)
+// method.invoke(proxy, device)
+// } catch (e: Exception) {
+// e.printStackTrace()
+// } finally {
+// bluetoothAdapter.closeProfileProxy(BluetoothProfile.A2DP, proxy)
+// }
+// }
+// }
+//
+// override fun onServiceDisconnected(profile: Int) { }
+// }, BluetoothProfile.A2DP)
+//
+// bluetoothAdapter?.getProfileProxy(context, object : BluetoothProfile.ServiceListener {
+// override fun onServiceConnected(profile: Int, proxy: BluetoothProfile) {
+// if (profile == BluetoothProfile.HEADSET) {
+// try {
+// val method = proxy.javaClass.getMethod("disconnect", BluetoothDevice::class.java)
+// method.invoke(proxy, device)
+// } catch (e: Exception) {
+// e.printStackTrace()
+// } finally {
+// bluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, proxy)
+// }
+// }
+// }
+//
+// override fun onServiceDisconnected(profile: Int) { }
+// }, BluetoothProfile.HEADSET)
+// }
+//
+// fun connectAudio(context: Context, device: BluetoothDevice?) {
+// val bluetoothAdapter = context.getSystemService(BluetoothManager::class.java).adapter
+//
+// bluetoothAdapter?.getProfileProxy(context, object : BluetoothProfile.ServiceListener {
+// override fun onServiceConnected(profile: Int, proxy: BluetoothProfile) {
+// if (profile == BluetoothProfile.A2DP) {
+// try {
+// val method = proxy.javaClass.getMethod("connect", BluetoothDevice::class.java)
+// method.invoke(proxy, device)
+// } catch (e: Exception) {
+// e.printStackTrace()
+// } finally {
+// bluetoothAdapter.closeProfileProxy(BluetoothProfile.A2DP, proxy)
+// }
+// }
+// }
+//
+// override fun onServiceDisconnected(profile: Int) { }
+// }, BluetoothProfile.A2DP)
+//
+// bluetoothAdapter?.getProfileProxy(context, object : BluetoothProfile.ServiceListener {
+// override fun onServiceConnected(profile: Int, proxy: BluetoothProfile) {
+// if (profile == BluetoothProfile.HEADSET) {
+// try {
+// val method = proxy.javaClass.getMethod("connect", BluetoothDevice::class.java)
+// method.invoke(proxy, device)
+// } catch (e: Exception) {
+// e.printStackTrace()
+// } finally {
+// bluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, proxy)
+// }
+// }
+// }
+//
+// override fun onServiceDisconnected(profile: Int) { }
+// }, BluetoothProfile.HEADSET)
+// }
+//
+// fun setName(name: String) {
+// val nameBytes = name.toByteArray()
+// val bytes = byteArrayOf(0x04, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x01,
+// nameBytes.size.toByte(), 0x00) + nameBytes
+// socket?.outputStream?.write(bytes)
+// socket?.outputStream?.flush()
+// val hex = bytes.joinToString(" ") { "%02X".format(it) }
+// Log.d("OldAirPodsService", "setName: $name, sent packet: $hex")
+// }
+//
+// @SuppressLint("MissingPermission", "InlinedApi")
+// override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
+//
+// val notification = createNotification()
+// startForeground(1, notification)
+//
+// ServiceManager.setService(this)
+//
+// if (isConnected) {
+// return START_STICKY
+// }
+// isConnected = true
+//
+// @Suppress("DEPRECATION") val device = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) intent?.getParcelableExtra("device", BluetoothDevice::class.java) else intent?.getParcelableExtra("device")
+//
+// HiddenApiBypass.addHiddenApiExemptions("Landroid/bluetooth/BluetoothSocket;")
+// val uuid: ParcelUuid = ParcelUuid.fromString("74ec2172-0bad-4d01-8f77-997b2be0722a")
+//
+// socket = HiddenApiBypass.newInstance(BluetoothSocket::class.java, 3, true, true, device, 0x1001, uuid) as BluetoothSocket?
+// try {
+// socket?.connect()
+// socket?.let { it ->
+// it.outputStream.write(Enums.HANDSHAKE.value)
+// it.outputStream.write(Enums.SET_SPECIFIC_FEATURES.value)
+// it.outputStream.write(Enums.REQUEST_NOTIFICATIONS.value)
+// sendBroadcast(Intent(AirPodsNotifications.AIRPODS_CONNECTED))
+// it.outputStream.flush()
+//
+// CoroutineScope(Dispatchers.IO).launch {
+// while (socket?.isConnected == true) {
+// socket?.let {
+// val audioManager = this@OldAirPodsService.getSystemService(AUDIO_SERVICE) as AudioManager
+// MediaController.initialize(audioManager)
+// val buffer = ByteArray(1024)
+// val bytesRead = it.inputStream.read(buffer)
+// var data: ByteArray = byteArrayOf()
+// if (bytesRead > 0) {
+// data = buffer.copyOfRange(0, bytesRead)
+// sendBroadcast(Intent(AirPodsNotifications.AIRPODS_DATA).apply {
+// putExtra("data", buffer.copyOfRange(0, bytesRead))
+// })
+// val bytes = buffer.copyOfRange(0, bytesRead)
+// val formattedHex = bytes.joinToString(" ") { "%02X".format(it) }
+// Log.d("AirPods Data", "Data received: $formattedHex")
+// }
+// else if (bytesRead == -1) {
+// Log.d("AirPods Service", "Socket closed (bytesRead = -1)")
+// this@OldAirPodsService.stopForeground(STOP_FOREGROUND_REMOVE)
+// socket?.close()
+// sendBroadcast(Intent(AirPodsNotifications.AIRPODS_DISCONNECTED))
+// return@launch
+// }
+// var inEar = false
+// var inEarData = listOf()
+// if (earDetectionNotification.isEarDetectionData(data)) {
+// earDetectionNotification.setStatus(data)
+// sendBroadcast(Intent(AirPodsNotifications.EAR_DETECTION_DATA).apply {
+// val list = earDetectionNotification.status
+// val bytes = ByteArray(2)
+// bytes[0] = list[0]
+// bytes[1] = list[1]
+// putExtra("data", bytes)
+// })
+// Log.d("AirPods Parser", "Ear Detection: ${earDetectionNotification.status[0]} ${earDetectionNotification.status[1]}")
+// var justEnabledA2dp = false
+// val earReceiver = object : BroadcastReceiver() {
+// override fun onReceive(context: Context, intent: Intent) {
+// val data = intent.getByteArrayExtra("data")
+// if (data != null && earDetectionEnabled) {
+// inEar = if (data.find { it == 0x02.toByte() } != null || data.find { it == 0x03.toByte() } != null) {
+// data[0] == 0x00.toByte() || data[1] == 0x00.toByte()
+// } else {
+// data[0] == 0x00.toByte() && data[1] == 0x00.toByte()
+// }
+//
+// val newInEarData = listOf(data[0] == 0x00.toByte(), data[1] == 0x00.toByte())
+// if (newInEarData.contains(true) && inEarData == listOf(false, false)) {
+// connectAudio(this@OldAirPodsService, device)
+// justEnabledA2dp = true
+// val bluetoothAdapter = this@OldAirPodsService.getSystemService(BluetoothManager::class.java).adapter
+// bluetoothAdapter.getProfileProxy(
+// this@OldAirPodsService, object : BluetoothProfile.ServiceListener {
+// override fun onServiceConnected(
+// profile: Int,
+// proxy: BluetoothProfile
+// ) {
+// if (profile == BluetoothProfile.A2DP) {
+// val connectedDevices =
+// proxy.connectedDevices
+// if (connectedDevices.isNotEmpty()) {
+// MediaController.sendPlay()
+// }
+// }
+// bluetoothAdapter.closeProfileProxy(
+// profile,
+// proxy
+// )
+// }
+//
+// override fun onServiceDisconnected(
+// profile: Int
+// ) {
+// }
+// }
+// ,BluetoothProfile.A2DP
+// )
+//
+// }
+// else if (newInEarData == listOf(false, false)){
+// disconnectAudio(this@OldAirPodsService, device)
+// }
+//
+// inEarData = newInEarData
+//
+// if (inEar == true) {
+// if (!justEnabledA2dp) {
+// justEnabledA2dp = false
+// MediaController.sendPlay()
+// }
+// } else {
+// MediaController.sendPause()
+// }
+// }
+// }
+// }
+//
+// val earIntentFilter = IntentFilter(AirPodsNotifications.EAR_DETECTION_DATA)
+// this@OldAirPodsService.registerReceiver(earReceiver, earIntentFilter,
+// RECEIVER_EXPORTED
+// )
+// }
+// else if (ancNotification.isANCData(data)) {
+// ancNotification.setStatus(data)
+// sendBroadcast(Intent(AirPodsNotifications.ANC_DATA).apply {
+// putExtra("data", ancNotification.status)
+// })
+// Log.d("AirPods Parser", "ANC: ${ancNotification.status}")
+// }
+// else if (batteryNotification.isBatteryData(data)) {
+// batteryNotification.setBattery(data)
+// sendBroadcast(Intent(AirPodsNotifications.BATTERY_DATA).apply {
+// putParcelableArrayListExtra("data", ArrayList(batteryNotification.getBattery()))
+// })
+// for (battery in batteryNotification.getBattery()) {
+// Log.d("AirPods Parser", "${battery.getComponentName()}: ${battery.getStatusName()} at ${battery.level}% ")
+// }
+//// if both are charging, disconnect audio profiles
+// if (batteryNotification.getBattery()[0].status == 1 && batteryNotification.getBattery()[1].status == 1) {
+// disconnectAudio(this@OldAirPodsService, device)
+// }
+// else {
+// connectAudio(this@OldAirPodsService, device)
+// }
+//// updatePodsStatus(device!!, batteryNotification.getBattery())
+// }
+// else if (conversationAwarenessNotification.isConversationalAwarenessData(data)) {
+// conversationAwarenessNotification.setData(data)
+// sendBroadcast(Intent(AirPodsNotifications.CA_DATA).apply {
+// putExtra("data", conversationAwarenessNotification.status)
+// })
+//
+//
+// if (conversationAwarenessNotification.status == 1.toByte() || conversationAwarenessNotification.status == 2.toByte()) {
+// MediaController.startSpeaking()
+// } else if (conversationAwarenessNotification.status == 8.toByte() || conversationAwarenessNotification.status == 9.toByte()) {
+// MediaController.stopSpeaking()
+// }
+//
+// Log.d("AirPods Parser", "Conversation Awareness: ${conversationAwarenessNotification.status}")
+// }
+// else { }
+// }
+// }
+// Log.d("AirPods Service", "Socket closed")
+// isConnected = false
+// this@OldAirPodsService.stopForeground(STOP_FOREGROUND_REMOVE)
+// socket?.close()
+// sendBroadcast(Intent(AirPodsNotifications.AIRPODS_DISCONNECTED))
+// }
+// }
+// }
+// catch (e: Exception) {
+// Log.e("AirPodsSettingsScreen", "Error connecting to device: ${e.message}")
+// }
+// return START_STICKY
+// }
+//
+// override fun onDestroy() {
+// super.onDestroy()
+// socket?.close()
+// isConnected = false
+// ServiceManager.setService(null)
+// }
+//
+// fun setPVEnabled(enabled: Boolean) {
+// var hex = "04 00 04 00 09 00 26 ${if (enabled) "01" else "02"} 00 00 00"
+// var bytes = hex.split(" ").map { it.toInt(16).toByte() }.toByteArray()
+// socket?.outputStream?.write(bytes)
+// hex = "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"
+// bytes = hex.split(" ").map { it.toInt(16).toByte() }.toByteArray()
+// socket?.outputStream?.write(bytes)
+// }
+//
+// fun setLoudSoundReduction(enabled: Boolean) {
+// val hex = "52 1B 00 0${if (enabled) "1" else "0"}"
+// val bytes = hex.split(" ").map { it.toInt(16).toByte() }.toByteArray()
+// socket?.outputStream?.write(bytes)
+// }
+//}
\ No newline at end of file
diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml
index 3e00038..aa643b1 100644
--- a/android/app/src/main/res/values/strings.xml
+++ b/android/app/src/main/res/values/strings.xml
@@ -1,5 +1,4 @@
ALN
- DebugActivity
- CustomDevice
+ GATT Testing
\ No newline at end of file