mirror of
https://github.com/kavishdevar/librepods.git
synced 2026-02-01 15:49:10 +00:00
fix for pre-tiramisu android versions
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
|
||||
package me.kavishdevar.aln
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.bluetooth.BluetoothDevice
|
||||
import android.bluetooth.BluetoothDevice.TRANSPORT_LE
|
||||
@@ -25,11 +26,13 @@ import android.bluetooth.BluetoothGatt
|
||||
import android.bluetooth.BluetoothGattCallback
|
||||
import android.bluetooth.BluetoothGattCharacteristic
|
||||
import android.bluetooth.BluetoothManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.annotation.RequiresPermission
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
@@ -49,7 +52,7 @@ import org.lsposed.hiddenapibypass.HiddenApiBypass
|
||||
import java.util.UUID
|
||||
|
||||
class CustomDevice : ComponentActivity() {
|
||||
@SuppressLint("MissingPermission", "CoroutineCreationDuringComposition", "NewApi")
|
||||
@SuppressLint("MissingPermission", "CoroutineCreationDuringComposition")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enableEdgeToEdge()
|
||||
@@ -152,7 +155,7 @@ class CustomDevice : ComponentActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission", "NewApi")
|
||||
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
|
||||
fun sendWriteRequest(
|
||||
gatt: BluetoothGatt,
|
||||
characteristicUuid: String,
|
||||
@@ -177,6 +180,10 @@ fun sendWriteRequest(
|
||||
|
||||
|
||||
// Send the write request
|
||||
val success = gatt.writeCharacteristic(characteristic, value, BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT)
|
||||
val success = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
gatt.writeCharacteristic(characteristic, value, BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT)
|
||||
} else {
|
||||
gatt.writeCharacteristic(characteristic)
|
||||
}
|
||||
Log.d("GATT", "Write request sent $success to UUID: $characteristicUuid")
|
||||
}
|
||||
@@ -22,9 +22,11 @@ import android.annotation.SuppressLint
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Context.RECEIVER_EXPORTED
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.ServiceConnection
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.IBinder
|
||||
import android.util.Log
|
||||
@@ -110,7 +112,7 @@ class MainActivity : ComponentActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission", "InlinedApi")
|
||||
@SuppressLint("MissingPermission", "InlinedApi", "UnspecifiedRegisterReceiverFlag")
|
||||
@OptIn(ExperimentalPermissionsApi::class)
|
||||
@Composable
|
||||
fun Main() {
|
||||
@@ -146,7 +148,12 @@ fun Main() {
|
||||
addAction(AirPodsNotifications.AIRPODS_CONNECTION_DETECTED)
|
||||
}
|
||||
Log.d("MainActivity", "Registering Receiver")
|
||||
context.registerReceiver(connectionStatusReceiver, filter, Context.RECEIVER_EXPORTED)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
context.registerReceiver(connectionStatusReceiver, filter, RECEIVER_EXPORTED)
|
||||
} else {
|
||||
context.registerReceiver(connectionStatusReceiver, filter)
|
||||
}
|
||||
Log.d("MainActivity", "Registered Receiver")
|
||||
|
||||
NavHost(
|
||||
|
||||
@@ -23,20 +23,29 @@ import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Build
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.gestures.Orientation
|
||||
import androidx.compose.foundation.gestures.draggable
|
||||
import androidx.compose.foundation.gestures.rememberDraggableState
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.VerticalDivider
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.mutableFloatStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
@@ -50,19 +59,36 @@ import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import me.kavishdevar.aln.R
|
||||
import me.kavishdevar.aln.services.AirPodsService
|
||||
import me.kavishdevar.aln.utils.AirPodsNotifications
|
||||
import me.kavishdevar.aln.utils.NoiseControlMode
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@SuppressLint("UnspecifiedRegisterReceiverFlag")
|
||||
@Composable
|
||||
fun NoiseControlSettings(service: AirPodsService) {
|
||||
val context = LocalContext.current
|
||||
val sharedPreferences = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
|
||||
val offListeningMode = sharedPreferences.getBoolean("off_listening_mode", true)
|
||||
val offListeningMode = remember { mutableStateOf(sharedPreferences.getBoolean("off_listening_mode", true)) }
|
||||
|
||||
val preferenceChangeListener = remember {
|
||||
SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
|
||||
if (key == "off_listening_mode") {
|
||||
offListeningMode.value = sharedPreferences.getBoolean("off_listening_mode", true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DisposableEffect(Unit) {
|
||||
sharedPreferences.registerOnSharedPreferenceChangeListener(preferenceChangeListener)
|
||||
onDispose {
|
||||
sharedPreferences.unregisterOnSharedPreferenceChangeListener(preferenceChangeListener)
|
||||
}
|
||||
}
|
||||
|
||||
val isDarkTheme = isSystemInDarkTheme()
|
||||
val backgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFE3E3E8)
|
||||
@@ -71,18 +97,28 @@ fun NoiseControlSettings(service: AirPodsService) {
|
||||
val selectedBackground = if (isDarkTheme) Color(0xFF5C5A5F) else Color(0xFFFFFFFF)
|
||||
|
||||
val noiseControlMode = remember { mutableStateOf(NoiseControlMode.OFF) }
|
||||
val selectedOffset = remember { mutableFloatStateOf(0f) }
|
||||
val animatedOffset = animateFloatAsState(targetValue = selectedOffset.floatValue)
|
||||
|
||||
val d1a = remember { mutableFloatStateOf(0f) }
|
||||
val d2a = remember { mutableFloatStateOf(0f) }
|
||||
val d3a = remember { mutableFloatStateOf(0f) }
|
||||
|
||||
val boxWidth = 200.dp.value
|
||||
|
||||
fun onModeSelected(mode: NoiseControlMode, received: Boolean = false) {
|
||||
if (!received && !offListeningMode && mode == NoiseControlMode.OFF) {
|
||||
if (!received && !offListeningMode.value && mode == NoiseControlMode.OFF) {
|
||||
noiseControlMode.value = NoiseControlMode.ADAPTIVE
|
||||
} else {
|
||||
noiseControlMode.value = mode
|
||||
}
|
||||
if (!received) service.setANCMode(mode.ordinal + 1)
|
||||
selectedOffset.floatValue = when (noiseControlMode.value) {
|
||||
NoiseControlMode.NOISE_CANCELLATION -> 3 * boxWidth
|
||||
NoiseControlMode.OFF -> 0f
|
||||
NoiseControlMode.ADAPTIVE -> 2 * boxWidth
|
||||
NoiseControlMode.TRANSPARENCY -> 1 * boxWidth
|
||||
}
|
||||
when (noiseControlMode.value) {
|
||||
NoiseControlMode.NOISE_CANCELLATION -> {
|
||||
d1a.floatValue = 1f
|
||||
@@ -107,6 +143,15 @@ fun NoiseControlSettings(service: AirPodsService) {
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(noiseControlMode.value) {
|
||||
selectedOffset.value = when (noiseControlMode.value) {
|
||||
NoiseControlMode.NOISE_CANCELLATION -> 3 * boxWidth
|
||||
NoiseControlMode.OFF -> 0f
|
||||
NoiseControlMode.ADAPTIVE -> 2 * boxWidth
|
||||
NoiseControlMode.TRANSPARENCY -> 1 * boxWidth
|
||||
}
|
||||
}
|
||||
|
||||
val noiseControlReceiver = remember {
|
||||
object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
@@ -154,13 +199,26 @@ fun NoiseControlSettings(service: AirPodsService) {
|
||||
.fillMaxWidth()
|
||||
.height(75.dp)
|
||||
.padding(8.dp)
|
||||
.draggable(
|
||||
orientation = Orientation.Horizontal,
|
||||
state = rememberDraggableState { delta ->
|
||||
selectedOffset.floatValue = (selectedOffset.floatValue + delta).coerceIn(0f, 3 * boxWidth)
|
||||
}
|
||||
)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(backgroundColor, RoundedCornerShape(14.dp))
|
||||
) {
|
||||
if (offListeningMode) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.offset { IntOffset(animatedOffset.value.roundToInt(), 0) }
|
||||
.width(boxWidth.dp)
|
||||
.height(75.dp)
|
||||
.background(selectedBackground, RoundedCornerShape(14.dp))
|
||||
)
|
||||
if (offListeningMode.value) {
|
||||
NoiseControlButton(
|
||||
icon = ImageBitmap.imageResource(R.drawable.noise_cancellation),
|
||||
onClick = { onModeSelected(NoiseControlMode.OFF) },
|
||||
@@ -219,7 +277,7 @@ fun NoiseControlSettings(service: AirPodsService) {
|
||||
.padding(horizontal = 8.dp)
|
||||
.padding(top = 1.dp)
|
||||
) {
|
||||
if (offListeningMode) {
|
||||
if (offListeningMode.value) {
|
||||
Text(
|
||||
text = "Off",
|
||||
style = TextStyle(fontSize = 12.sp, color = textColor),
|
||||
|
||||
@@ -86,7 +86,7 @@ import me.kavishdevar.aln.ui.theme.ALNTheme
|
||||
import me.kavishdevar.aln.utils.AirPodsNotifications
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalHazeMaterialsApi::class)
|
||||
@SuppressLint("MissingPermission", "NewApi")
|
||||
@SuppressLint("MissingPermission")
|
||||
@Composable
|
||||
fun AirPodsSettingsScreen(dev: BluetoothDevice?, service: AirPodsService,
|
||||
navController: NavController, isConnected: Boolean) {
|
||||
|
||||
@@ -88,7 +88,7 @@ import me.kavishdevar.aln.services.AirPodsService
|
||||
import me.kavishdevar.aln.utils.AirPodsNotifications
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
|
||||
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
|
||||
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter", "UnspecifiedRegisterReceiverFlag")
|
||||
@Composable
|
||||
fun DebugScreen(navController: NavController) {
|
||||
val hazeState = remember { HazeState() }
|
||||
@@ -158,6 +158,8 @@ fun DebugScreen(navController: NavController) {
|
||||
val intentFilter = IntentFilter(AirPodsNotifications.Companion.AIRPODS_DATA)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
context.registerReceiver(receiver, intentFilter, Context.RECEIVER_EXPORTED)
|
||||
} else {
|
||||
context.registerReceiver(receiver, intentFilter)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.os.Build
|
||||
import android.service.quicksettings.Tile
|
||||
import android.service.quicksettings.TileService
|
||||
import android.util.Log
|
||||
@@ -35,7 +36,7 @@ class AirPodsQSService: TileService() {
|
||||
private lateinit var ancStatusReceiver: BroadcastReceiver
|
||||
private lateinit var availabilityReceiver: BroadcastReceiver
|
||||
|
||||
@SuppressLint("InlinedApi")
|
||||
@SuppressLint("InlinedApi", "UnspecifiedRegisterReceiverFlag")
|
||||
override fun onStartListening() {
|
||||
super.onStartListening()
|
||||
currentModeIndex = (ServiceManager.getService()?.getANC()?.minus(1)) ?: -1
|
||||
@@ -77,9 +78,17 @@ class AirPodsQSService: TileService() {
|
||||
}
|
||||
}
|
||||
|
||||
registerReceiver(ancStatusReceiver,
|
||||
IntentFilter(AirPodsNotifications.Companion.ANC_DATA), RECEIVER_EXPORTED)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
registerReceiver(
|
||||
ancStatusReceiver,
|
||||
IntentFilter(AirPodsNotifications.Companion.ANC_DATA), RECEIVER_EXPORTED
|
||||
)
|
||||
} else {
|
||||
registerReceiver(
|
||||
ancStatusReceiver,
|
||||
IntentFilter(AirPodsNotifications.Companion.ANC_DATA)
|
||||
)
|
||||
}
|
||||
qsTile.state = if (ServiceManager.getService()?.isConnected == true) Tile.STATE_ACTIVE else Tile.STATE_UNAVAILABLE
|
||||
val ancIndex = ServiceManager.getService()?.getANC()
|
||||
currentModeIndex = if (ancIndex != null) { if (ancIndex == 2) 0 else if (ancIndex == 3) 1 else if (ancIndex == 4) 2 else 2 } else 0
|
||||
|
||||
@@ -107,10 +107,14 @@ class AirPodsService: Service() {
|
||||
|
||||
@Suppress("ClassName")
|
||||
private object bluetoothReceiver: BroadcastReceiver() {
|
||||
@SuppressLint("NewApi", "MissingPermission")
|
||||
@SuppressLint("MissingPermission")
|
||||
override fun onReceive(context: Context?, intent: Intent) {
|
||||
val bluetoothDevice =
|
||||
intent.getParcelableExtra("android.bluetooth.device.extra.DEVICE", BluetoothDevice::class.java)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
intent.getParcelableExtra("android.bluetooth.device.extra.DEVICE", BluetoothDevice::class.java)
|
||||
} else {
|
||||
intent.getParcelableExtra("android.bluetooth.device.extra.DEVICE") as BluetoothDevice?
|
||||
}
|
||||
val action = intent.action
|
||||
val context = context?.applicationContext
|
||||
val name = context?.getSharedPreferences("settings", MODE_PRIVATE)?.getString("name", bluetoothDevice?.name)
|
||||
@@ -301,7 +305,7 @@ class AirPodsService: Service() {
|
||||
private lateinit var connectionReceiver: BroadcastReceiver
|
||||
private lateinit var disconnectionReceiver: BroadcastReceiver
|
||||
|
||||
@SuppressLint("InlinedApi", "MissingPermission")
|
||||
@SuppressLint("InlinedApi", "MissingPermission", "UnspecifiedRegisterReceiverFlag")
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
Log.d("AirPodsService", "Service started")
|
||||
ServiceManager.setService(this)
|
||||
@@ -319,12 +323,20 @@ class AirPodsService: Service() {
|
||||
addAction("android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED")
|
||||
}
|
||||
|
||||
registerReceiver(bluetoothReceiver, serviceIntentFilter, RECEIVER_EXPORTED)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
registerReceiver(bluetoothReceiver, serviceIntentFilter, RECEIVER_EXPORTED)
|
||||
} else {
|
||||
registerReceiver(bluetoothReceiver, serviceIntentFilter)
|
||||
}
|
||||
|
||||
connectionReceiver = object: BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
if (intent?.action == AirPodsNotifications.Companion.AIRPODS_CONNECTION_DETECTED) {
|
||||
device = intent.getParcelableExtra("device", BluetoothDevice::class.java)!!
|
||||
device = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
intent.getParcelableExtra("device", BluetoothDevice::class.java)!!
|
||||
} else {
|
||||
intent.getParcelableExtra("device") as BluetoothDevice?
|
||||
}
|
||||
val name = this@AirPodsService.getSharedPreferences("settings", MODE_PRIVATE)
|
||||
.getString("name", device?.name)
|
||||
if (this@AirPodsService.getSharedPreferences("settings", MODE_PRIVATE).getString("name", null) == null) {
|
||||
@@ -349,7 +361,11 @@ class AirPodsService: Service() {
|
||||
addAction(AirPodsNotifications.Companion.AIRPODS_CONNECTION_DETECTED)
|
||||
addAction(AirPodsNotifications.Companion.AIRPODS_DISCONNECTED)
|
||||
}
|
||||
registerReceiver(connectionReceiver, deviceIntentFilter, RECEIVER_EXPORTED)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
registerReceiver(connectionReceiver, deviceIntentFilter, RECEIVER_EXPORTED)
|
||||
} else {
|
||||
registerReceiver(connectionReceiver, deviceIntentFilter)
|
||||
}
|
||||
|
||||
val bluetoothAdapter = getSystemService(BluetoothManager::class.java).adapter
|
||||
bluetoothAdapter.bondedDevices.forEach { device ->
|
||||
@@ -500,7 +516,6 @@ class AirPodsService: Service() {
|
||||
)
|
||||
var justEnabledA2dp = false
|
||||
earReceiver = object : BroadcastReceiver() {
|
||||
@SuppressLint("NewApi")
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val data = intent.getByteArrayExtra("data")
|
||||
if (data != null && earDetectionEnabled) {
|
||||
|
||||
@@ -48,7 +48,6 @@ class Window (context: Context) {
|
||||
private val mView: View
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@SuppressLint("NewApi")
|
||||
private val mParams: WindowManager.LayoutParams = WindowManager.LayoutParams().apply {
|
||||
height = WindowManager.LayoutParams.WRAP_CONTENT
|
||||
width = WindowManager.LayoutParams.MATCH_PARENT
|
||||
|
||||
Reference in New Issue
Block a user