diff --git a/.gitignore b/.gitignore index ed06b8946..6e670aadd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.worktrees/ root-module/radare2-5.9.9-android-aarch64.tar.gz wak.toml log.txt diff --git a/android/app/src/main/java/me/kavishdevar/librepods/MainActivity.kt b/android/app/src/main/java/me/kavishdevar/librepods/MainActivity.kt index 8de1b77d4..a88b24a7c 100644 --- a/android/app/src/main/java/me/kavishdevar/librepods/MainActivity.kt +++ b/android/app/src/main/java/me/kavishdevar/librepods/MainActivity.kt @@ -165,14 +165,18 @@ class MainActivity : ComponentActivity() { override fun onDestroy() { try { - unbindService(serviceConnection) - Log.d("MainActivity", "Unbound service") + if (::serviceConnection.isInitialized) { + 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") + if (::connectionStatusReceiver.isInitialized) { + unregisterReceiver(connectionStatusReceiver) + Log.d("MainActivity", "Unregistered receiver") + } } catch (e: Exception) { Log.e("MainActivity", "Error while unregistering receiver: $e") } @@ -182,14 +186,18 @@ class MainActivity : ComponentActivity() { override fun onStop() { try { - unbindService(serviceConnection) - Log.d("MainActivity", "Unbound service") + if (::serviceConnection.isInitialized) { + 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") + if (::connectionStatusReceiver.isInitialized) { + unregisterReceiver(connectionStatusReceiver) + Log.d("MainActivity", "Unregistered receiver") + } } catch (e: Exception) { Log.e("MainActivity", "Error while unregistering receiver: $e") } @@ -457,7 +465,9 @@ fun Main() { } } - context.bindService(Intent(context, AirPodsService::class.java), serviceConnection, Context.BIND_AUTO_CREATE) + val serviceIntent = Intent(context, AirPodsService::class.java) + context.startForegroundService(serviceIntent) + context.bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE) if (airPodsService.value?.isConnectedLocally == true) { isConnected.value = true diff --git a/android/app/src/main/java/me/kavishdevar/librepods/services/AirPodsService.kt b/android/app/src/main/java/me/kavishdevar/librepods/services/AirPodsService.kt index d890e88f2..b956d4498 100644 --- a/android/app/src/main/java/me/kavishdevar/librepods/services/AirPodsService.kt +++ b/android/app/src/main/java/me/kavishdevar/librepods/services/AirPodsService.kt @@ -1587,6 +1587,7 @@ class AirPodsService : Service(), SharedPreferences.OnSharedPreferenceChangeList } fun setBatteryMetadata() { + if (::sharedPreferences.isInitialized && sharedPreferences.getBoolean("skip_setup", false)) return device?.let { it -> SystemApisUtils.setMetadata( it, @@ -2192,6 +2193,20 @@ class AirPodsService : Service(), SharedPreferences.OnSharedPreferenceChangeList takeOver("music", manualTakeOverAfterReversed = true) } + if (!isConnectedLocally && ::sharedPreferences.isInitialized) { + val savedMac = sharedPreferences.getString("mac_address", "") + if (!savedMac.isNullOrEmpty()) { + Log.d(TAG, "Service restarted, attempting L2CAP reconnect to $savedMac") + val bluetoothManager = getSystemService(BluetoothManager::class.java) + val bluetoothDevice = bluetoothManager?.adapter?.getRemoteDevice(savedMac) + if (bluetoothDevice != null) { + CoroutineScope(Dispatchers.IO).launch { + connectToSocket(bluetoothDevice) + } + } + } + } + return START_STICKY } diff --git a/android/app/src/main/java/me/kavishdevar/librepods/utils/RadareOffsetFinder.kt b/android/app/src/main/java/me/kavishdevar/librepods/utils/RadareOffsetFinder.kt index e5a1e7bdc..ea25abcf5 100644 --- a/android/app/src/main/java/me/kavishdevar/librepods/utils/RadareOffsetFinder.kt +++ b/android/app/src/main/java/me/kavishdevar/librepods/utils/RadareOffsetFinder.kt @@ -28,6 +28,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.withContext import me.kavishdevar.librepods.services.ServiceManager +import android.os.Build import java.io.BufferedReader import java.io.File import java.io.FileOutputStream @@ -60,6 +61,12 @@ class RadareOffsetFinder(context: Context) { "/system_ext/lib64/libbluetooth_qti.so" ) + fun isOxygenOSOrColorOS16OrAbove(): Boolean { + val manufacturer = Build.MANUFACTURER.lowercase() + if (manufacturer != "oneplus" && manufacturer != "oppo" && manufacturer != "realme") return false + return Build.VERSION.SDK_INT >= 36 + } + fun findBluetoothLibraryPath(): String? { for (path in LIBRARY_PATHS) { if (File(path).exists()) { @@ -115,6 +122,10 @@ class RadareOffsetFinder(context: Context) { } fun isSdpOffsetAvailable(): Boolean { + if (isOxygenOSOrColorOS16OrAbove()) { + Log.d(TAG, "OxygenOS/ColorOS 16+ detected, L2CAP works without SDP hook.") + return true + } val sharedPreferences = ServiceManager.getService()?.applicationContext?.getSharedPreferences("settings", Context.MODE_PRIVATE) // ik not good practice- too lazy if (sharedPreferences?.getBoolean("skip_setup", false) == true) { Log.d(TAG, "Setup skipped, returning true for SDP offset.") @@ -160,6 +171,10 @@ class RadareOffsetFinder(context: Context) { fun isHookOffsetAvailable(): Boolean { + if (isOxygenOSOrColorOS16OrAbove()) { + Log.d(TAG, "OxygenOS/ColorOS 16+ detected, L2CAP works without hook.") + return true + } Log.d(TAG, "Setup Skipped? " + ServiceManager.getService()?.applicationContext?.getSharedPreferences("settings", Context.MODE_PRIVATE)?.getBoolean("skip_setup", false).toString()) if (ServiceManager.getService()?.applicationContext?.getSharedPreferences("settings", Context.MODE_PRIVATE)?.getBoolean("skip_setup", false) == true) { Log.d(TAG, "Setup skipped, returning true.")