mirror of
https://github.com/kavishdevar/librepods.git
synced 2026-02-03 08:39:12 +00:00
try to add automatic device connection detection; add "Off Listening Mode" toggle
This commit is contained in:
@@ -7,31 +7,44 @@
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED"
|
||||
<uses-permission
|
||||
android:name="android.permission.BLUETOOTH_PRIVILEGED"
|
||||
tools:ignore="ProtectedPermissions" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
|
||||
<uses-permission
|
||||
android:name="android.permission.BLUETOOTH_ADMIN"
|
||||
tools:ignore="ProtectedPermissions" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:enableOnBackInvokedCallback="true"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.ALN"
|
||||
android:enableOnBackInvokedCallback="true"
|
||||
tools:targetApi="31"
|
||||
tools:ignore="UnusedAttribute">
|
||||
tools:ignore="UnusedAttribute"
|
||||
tools:targetApi="31">
|
||||
<activity
|
||||
android:name=".CustomDevice"
|
||||
android:exported="true"
|
||||
android:label="@string/title_activity_custom_device"
|
||||
android:theme="@style/Theme.ALN">
|
||||
<intent-filter>
|
||||
<!-- <action android:name="android.intent.action.MAIN" />-->
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.ALN">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
@@ -42,7 +55,6 @@
|
||||
android:exported="true"
|
||||
android:foregroundServiceType="connectedDevice"
|
||||
android:permission="android.permission.BLUETOOTH_CONNECT" />
|
||||
|
||||
<service
|
||||
android:name=".AirPodsQSService"
|
||||
android:exported="true"
|
||||
@@ -53,18 +65,6 @@
|
||||
<action android:name="android.service.quicksettings.action.QS_TILE" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<!-- <receiver android:name=".StartupReceiver"-->
|
||||
<!-- android:exported="true">-->
|
||||
<!-- <intent-filter>-->
|
||||
<!-- <action android:name="android.bluetooth.device.action.ACL_CONNECTED" />-->
|
||||
<!-- <action android:name="android.bluetooth.device.action.ACL_DISCONNECTED" />-->
|
||||
<!-- <action android:name="android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED" />-->
|
||||
<!-- <action android:name="android.bluetooth.device.action.BOND_STATE_CHANGED" />-->
|
||||
<!-- <action android:name="android.bluetooth.device.action.NAME_CHANGED" />-->
|
||||
<!-- <action android:name="android.intent.action.BOOT_COMPLETED" />-->
|
||||
<!-- <action android:name="android.bluetooth.adapter.action.STATE_CHANGED" />-->
|
||||
<!-- </intent-filter>-->
|
||||
<!-- </receiver>-->
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -10,8 +10,8 @@ import android.service.quicksettings.TileService
|
||||
import android.util.Log
|
||||
|
||||
class AirPodsQSService: TileService() {
|
||||
private val ancModes = listOf(NoiseControlMode.OFF.name, NoiseControlMode.NOISE_CANCELLATION.name, NoiseControlMode.TRANSPARENCY.name, NoiseControlMode.ADAPTIVE.name)
|
||||
private var currentModeIndex = 3
|
||||
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
|
||||
|
||||
@@ -63,8 +63,24 @@ class AirPodsQSService: TileService() {
|
||||
|
||||
override fun onStopListening() {
|
||||
super.onStopListening()
|
||||
unregisterReceiver(ancStatusReceiver)
|
||||
unregisterReceiver(availabilityReceiver)
|
||||
try {
|
||||
unregisterReceiver(ancStatusReceiver)
|
||||
}
|
||||
catch (
|
||||
e: IllegalArgumentException
|
||||
)
|
||||
{
|
||||
Log.e("QuickSettingTileService", "Receiver not registered")
|
||||
}
|
||||
try {
|
||||
unregisterReceiver(availabilityReceiver)
|
||||
}
|
||||
catch (
|
||||
e: IllegalArgumentException
|
||||
)
|
||||
{
|
||||
Log.e("QuickSettingTileService", "Receiver not registered")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onClick() {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
@file:Suppress("unused")
|
||||
|
||||
package me.kavishdevar.aln
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
@@ -90,6 +92,10 @@ class AirPodsService : Service() {
|
||||
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)
|
||||
|
||||
@@ -150,6 +150,33 @@ fun BatteryView() {
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AccessibilitySettings(service: AirPodsService, sharedPreferences: SharedPreferences) {
|
||||
val isDarkTheme = MaterialTheme.colorScheme.surface.luminance() < 0.5
|
||||
val textColor = if (isDarkTheme) Color.White else Color.Black
|
||||
|
||||
Text(
|
||||
text = "ACCESSIBILITY",
|
||||
style = TextStyle(
|
||||
fontSize = 14.sp,
|
||||
fontWeight = FontWeight.Light,
|
||||
color = textColor.copy(alpha = 0.6f)
|
||||
),
|
||||
modifier = Modifier.padding(8.dp, bottom = 2.dp)
|
||||
)
|
||||
|
||||
val backgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(backgroundColor, RoundedCornerShape(14.dp))
|
||||
.padding(top = 2.dp)
|
||||
) {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission", "NewApi")
|
||||
@Composable
|
||||
fun AirPodsSettingsScreen(paddingValues: PaddingValues, device: BluetoothDevice?, service: AirPodsService?,
|
||||
@@ -203,6 +230,11 @@ fun AirPodsSettingsScreen(paddingValues: PaddingValues, device: BluetoothDevice?
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
IndependentToggle(name = "Automatic Ear Detection", service = service, functionName = "setEarDetection", sharedPreferences = sharedPreferences, true)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
IndependentToggle(name = "Off Listening Mode", service = service, functionName = "setOffListeningMode", sharedPreferences = sharedPreferences, false)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
AccessibilitySettings(service = service, sharedPreferences = sharedPreferences)
|
||||
// Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
// val isDarkTheme = MaterialTheme.colorScheme.surface.luminance() < 0.5
|
||||
|
||||
159
android/app/src/main/java/me/kavishdevar/aln/CustomDevice.kt
Normal file
159
android/app/src/main/java/me/kavishdevar/aln/CustomDevice.kt
Normal file
@@ -0,0 +1,159 @@
|
||||
package me.kavishdevar.aln
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.bluetooth.BluetoothDevice
|
||||
import android.bluetooth.BluetoothDevice.TRANSPORT_LE
|
||||
import android.bluetooth.BluetoothGatt
|
||||
import android.bluetooth.BluetoothGattCallback
|
||||
import android.bluetooth.BluetoothGattCharacteristic
|
||||
import android.bluetooth.BluetoothManager
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import me.kavishdevar.aln.ui.theme.ALNTheme
|
||||
import org.lsposed.hiddenapibypass.HiddenApiBypass
|
||||
import java.util.UUID
|
||||
|
||||
class CustomDevice : ComponentActivity() {
|
||||
@SuppressLint("MissingPermission", "CoroutineCreationDuringComposition", "NewApi")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enableEdgeToEdge()
|
||||
setContent {
|
||||
ALNTheme {
|
||||
val connect = remember { mutableStateOf(false) }
|
||||
Scaffold(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
topBar = {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Text("Custom Device", style = MaterialTheme.typography.titleLarge)
|
||||
}
|
||||
}
|
||||
) { innerPadding ->
|
||||
HiddenApiBypass.addHiddenApiExemptions("Landroid/bluetooth/BluetoothSocket;")
|
||||
val manager = getSystemService(BLUETOOTH_SERVICE) as BluetoothManager
|
||||
// val device: BluetoothDevice = manager.adapter.getRemoteDevice("EC:D6:F4:3D:89:B8")
|
||||
val device: BluetoothDevice = manager.adapter.getRemoteDevice("E0:90:8F:D9:94:73")
|
||||
// val socket = device.createInsecureL2capChannel(31)
|
||||
|
||||
// socket.outputStream.write(byteArrayOf(0x12,0x3B,0x00,0x02, 0x00))
|
||||
// socket.outputStream.write(byteArrayOf(0x12, 0x3A, 0x00, 0x01, 0x00, 0x08,0x01))
|
||||
|
||||
val gatt = device.connectGatt(this, true, object: BluetoothGattCallback() {
|
||||
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
// Step 2: Iterate through the services and characteristics
|
||||
gatt.services.forEach { service ->
|
||||
Log.d("GATT", "Service UUID: ${service.uuid}")
|
||||
service.characteristics.forEach { characteristic ->
|
||||
Log.d("GATT", " Characteristic UUID: ${characteristic.uuid}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
|
||||
if (newState == BluetoothGatt.STATE_CONNECTED) {
|
||||
Log.d("GATT", "Connected to GATT server")
|
||||
gatt.discoverServices() // Discover services after connection
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCharacteristicWrite(
|
||||
gatt: BluetoothGatt,
|
||||
characteristic: BluetoothGattCharacteristic,
|
||||
status: Int
|
||||
) {
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
Log.d("BLE", "Write successful for UUID: ${characteristic.uuid}")
|
||||
} else {
|
||||
Log.e("BLE", "Write failed for UUID: ${characteristic.uuid}, status: $status")
|
||||
}
|
||||
}
|
||||
}, TRANSPORT_LE, 1)
|
||||
|
||||
if (connect.value) {
|
||||
try {
|
||||
gatt.connect()
|
||||
}
|
||||
catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
connect.value = false
|
||||
}
|
||||
|
||||
Column (
|
||||
modifier = Modifier.padding(innerPadding),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
)
|
||||
{
|
||||
Button(
|
||||
onClick = { connect.value = true }
|
||||
)
|
||||
{
|
||||
Text("Connect")
|
||||
}
|
||||
|
||||
Button(onClick = {
|
||||
val characteristicUuid = "4f860002-943b-49ef-bed4-2f730304427a"
|
||||
val value = byteArrayOf(0x01, 0x00, 0x02)
|
||||
|
||||
sendWriteRequest(gatt, characteristicUuid, value)
|
||||
}) {
|
||||
Text("Play Sound")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission", "NewApi")
|
||||
fun sendWriteRequest(
|
||||
gatt: BluetoothGatt,
|
||||
characteristicUuid: String,
|
||||
value: ByteArray
|
||||
) {
|
||||
// Retrieve the service containing the characteristic
|
||||
val service = gatt.services.find { service ->
|
||||
service.characteristics.any { it.uuid.toString() == characteristicUuid }
|
||||
}
|
||||
|
||||
if (service == null) {
|
||||
Log.e("GATT", "Service containing characteristic UUID $characteristicUuid not found.")
|
||||
return
|
||||
}
|
||||
|
||||
// Retrieve the characteristic
|
||||
val characteristic = service.getCharacteristic(UUID.fromString(characteristicUuid))
|
||||
if (characteristic == null) {
|
||||
Log.e("GATT", "Characteristic with UUID $characteristicUuid not found.")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// Send the write request
|
||||
val success = gatt.writeCharacteristic(characteristic, value, BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT)
|
||||
Log.d("GATT", "Write request sent $success to UUID: $characteristicUuid")
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package me.kavishdevar.aln
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.bluetooth.BluetoothAdapter
|
||||
import android.bluetooth.BluetoothDevice
|
||||
import android.bluetooth.BluetoothManager
|
||||
import android.bluetooth.BluetoothProfile
|
||||
@@ -43,6 +42,7 @@ import androidx.compose.ui.graphics.luminance
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.ContextCompat.getSystemService
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
@@ -61,6 +61,43 @@ class MainActivity : ComponentActivity() {
|
||||
setContent {
|
||||
val topAppBarTitle = remember { mutableStateOf("AirPods Pro") }
|
||||
ALNTheme {
|
||||
val navController = rememberNavController()
|
||||
registerReceiver(object: BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent) {
|
||||
val bluetoothDevice =
|
||||
intent.getParcelableExtra("android.bluetooth.device.extra.DEVICE", BluetoothDevice::class.java)
|
||||
val action = intent.action
|
||||
|
||||
// Airpods filter
|
||||
if (bluetoothDevice != null && action != null && !action.isEmpty()) {
|
||||
Log.d("BluetoothReceiver", "Received broadcast")
|
||||
// Airpods connected, show notification.
|
||||
if (BluetoothDevice.ACTION_ACL_CONNECTED == action) {
|
||||
val uuid = ParcelUuid.fromString("74ec2172-0bad-4d01-8f77-997b2be0722a")
|
||||
if (bluetoothDevice.uuids.contains(uuid)) {
|
||||
topAppBarTitle.value = bluetoothDevice.name
|
||||
}
|
||||
// start service
|
||||
startService(Intent(context, AirPodsService::class.java).apply {
|
||||
putExtra("device", bluetoothDevice)
|
||||
})
|
||||
Log.d("AirPodsService", "Service started")
|
||||
context?.sendBroadcast(Intent(AirPodsNotifications.AIRPODS_CONNECTED))
|
||||
}
|
||||
|
||||
// Airpods disconnected, remove notification but leave the scanner going.
|
||||
if (BluetoothDevice.ACTION_ACL_DISCONNECTED == action
|
||||
|| BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED == action
|
||||
) {
|
||||
topAppBarTitle.value = "AirPods Pro"
|
||||
// stop service
|
||||
stopService(Intent(context, AirPodsService::class.java))
|
||||
Log.d("AirPodsService", "Service stopped")
|
||||
}
|
||||
}
|
||||
}
|
||||
}, BluetoothReceiver.buildFilter())
|
||||
|
||||
Scaffold (
|
||||
containerColor = if (MaterialTheme.colorScheme.surface.luminance() < 0.5) Color(
|
||||
0xFF000000
|
||||
@@ -109,6 +146,7 @@ fun Main(paddingValues: PaddingValues, topAppBarTitle: MutableState<String>) {
|
||||
val airPodsService = remember { mutableStateOf<AirPodsService?>(null) }
|
||||
val navController = rememberNavController()
|
||||
|
||||
|
||||
val disconnectReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
navController.navigate("notConnected")
|
||||
@@ -165,42 +203,8 @@ fun Main(paddingValues: PaddingValues, topAppBarTitle: MutableState<String>) {
|
||||
}
|
||||
}
|
||||
|
||||
// BroadcastReceiver to listen for connection state changes
|
||||
val bluetoothReceiver = remember {
|
||||
object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
val action = intent?.action
|
||||
val device = intent?.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE)
|
||||
if (action == BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED) {
|
||||
when (intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, -1)) {
|
||||
BluetoothAdapter.STATE_CONNECTED -> {
|
||||
if (device?.uuids?.contains(uuid) == true) {
|
||||
airpodsDevice.value = device
|
||||
checkIfAirPodsConnected()
|
||||
}
|
||||
}
|
||||
BluetoothAdapter.STATE_DISCONNECTED -> {
|
||||
if (device?.uuids?.contains(uuid) == true) {
|
||||
airpodsDevice.value = null
|
||||
// Show not connected screen when AirPods disconnect
|
||||
navController.navigate("notConnected")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Register the receiver in LaunchedEffect
|
||||
LaunchedEffect(Unit) {
|
||||
val filter = IntentFilter().apply {
|
||||
addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
context.registerReceiver(bluetoothReceiver, filter, Context.RECEIVER_NOT_EXPORTED)
|
||||
}
|
||||
|
||||
// Initial check for AirPods connection
|
||||
checkIfAirPodsConnected()
|
||||
}
|
||||
@@ -230,6 +234,21 @@ fun Main(paddingValues: PaddingValues, topAppBarTitle: MutableState<String>) {
|
||||
}
|
||||
}
|
||||
|
||||
ContextCompat.registerReceiver(
|
||||
context,
|
||||
object : BroadcastReceiver() {
|
||||
@SuppressLint("UnspecifiedRegisterReceiverFlag")
|
||||
override fun onReceive(context: Context?, intent: Intent) {
|
||||
Log.d("PLEASE NAVIGATE", "TO SETTINGS")
|
||||
navController.navigate("settings") {
|
||||
popUpTo("notConnected") { inclusive = true }
|
||||
}
|
||||
}
|
||||
},
|
||||
IntentFilter(AirPodsNotifications.AIRPODS_CONNECTED),
|
||||
ContextCompat.RECEIVER_NOT_EXPORTED
|
||||
)
|
||||
|
||||
// Automatically navigate to settings screen if AirPods are connected
|
||||
if (airpodsDevice.value != null) {
|
||||
LaunchedEffect(Unit) {
|
||||
|
||||
62
android/app/src/main/java/me/kavishdevar/aln/receiver.kt
Normal file
62
android/app/src/main/java/me/kavishdevar/aln/receiver.kt
Normal file
@@ -0,0 +1,62 @@
|
||||
package me.kavishdevar.aln
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.bluetooth.BluetoothDevice
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
|
||||
class BluetoothReceiver : BroadcastReceiver() {
|
||||
fun onConnect(bluetoothDevice: BluetoothDevice?) {
|
||||
|
||||
}
|
||||
|
||||
fun onDisconnect(bluetoothDevice: BluetoothDevice?) {
|
||||
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
override fun onReceive(context: Context?, intent: Intent) {
|
||||
val bluetoothDevice =
|
||||
intent.getParcelableExtra("android.bluetooth.device.extra.DEVICE", BluetoothDevice::class.java)
|
||||
val action = intent.action
|
||||
|
||||
// Airpods filter
|
||||
if (bluetoothDevice != null && action != null && !action.isEmpty()) {
|
||||
// Airpods connected, show notification.
|
||||
if (BluetoothDevice.ACTION_ACL_CONNECTED == action) {
|
||||
onConnect(bluetoothDevice)
|
||||
}
|
||||
|
||||
// Airpods disconnected, remove notification but leave the scanner going.
|
||||
if (BluetoothDevice.ACTION_ACL_DISCONNECTED == action
|
||||
|| BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED == action
|
||||
) {
|
||||
onDisconnect(bluetoothDevice)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* When the service is created, we register to get as many bluetooth and airpods related events as possible.
|
||||
* ACL_CONNECTED and ACL_DISCONNECTED should have been enough, but you never know with android these days.
|
||||
*/
|
||||
fun buildFilter(): IntentFilter {
|
||||
val intentFilter = IntentFilter()
|
||||
intentFilter.addAction("android.bluetooth.device.action.ACL_CONNECTED")
|
||||
intentFilter.addAction("android.bluetooth.device.action.ACL_DISCONNECTED")
|
||||
intentFilter.addAction("android.bluetooth.device.action.BOND_STATE_CHANGED")
|
||||
intentFilter.addAction("android.bluetooth.device.action.NAME_CHANGED")
|
||||
intentFilter.addAction("android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED")
|
||||
intentFilter.addAction("android.bluetooth.adapter.action.STATE_CHANGED")
|
||||
intentFilter.addAction("android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED")
|
||||
intentFilter.addAction("android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT")
|
||||
intentFilter.addAction("android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED")
|
||||
intentFilter.addAction("android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED")
|
||||
intentFilter.addCategory("android.bluetooth.headset.intent.category.companyid.76")
|
||||
return intentFilter
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
<resources>
|
||||
<string name="app_name">ALN</string>
|
||||
<string name="title_activity_debug">DebugActivity</string>
|
||||
<string name="title_activity_custom_device">CustomDevice</string>
|
||||
</resources>
|
||||
@@ -1,6 +1,6 @@
|
||||
[versions]
|
||||
accompanistPermissions = "0.36.0"
|
||||
agp = "8.7.0"
|
||||
agp = "8.7.2"
|
||||
hiddenapibypass = "4.3"
|
||||
kotlin = "2.0.0"
|
||||
coreKtx = "1.13.1"
|
||||
|
||||
Reference in New Issue
Block a user