android: fix ear detection when none are in use and either or both are worn

Music would start playing when neither are in ear, but even one is worn. This happens even when the music was not playing when they were removed (or, connected first)
This commit is contained in:
Kavish Devar
2025-05-10 20:11:20 +05:30
parent 9b96218fa9
commit 364a6f4b64
2 changed files with 30 additions and 34 deletions

View File

@@ -1468,39 +1468,36 @@ class AirPodsService : Service(), SharedPreferences.OnSharedPreferenceChangeList
) { ) {
connectAudio(this@AirPodsService, device) connectAudio(this@AirPodsService, device)
justEnabledA2dp = true justEnabledA2dp = true
val bluetoothAdapter = val a2dpConnectionStateReceiver = object : BroadcastReceiver() {
this@AirPodsService.getSystemService( override fun onReceive(context: Context, intent: Intent) {
BluetoothManager::class.java if (intent.action == "android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED") {
).adapter val state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_DISCONNECTED)
bluetoothAdapter.getProfileProxy( val previousState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_DISCONNECTED)
this@AirPodsService, val device = intent.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE)
object : BluetoothProfile.ServiceListener {
override fun onServiceConnected( Log.d("MediaController", "A2DP state changed: $previousState -> $state for device: ${device?.address}")
profile: Int,
proxy: BluetoothProfile if (state == BluetoothProfile.STATE_CONNECTED &&
) { previousState != BluetoothProfile.STATE_CONNECTED &&
if (profile == BluetoothProfile.A2DP) { device?.address == this@AirPodsService.device?.address) {
val connectedDevices =
proxy.connectedDevices Log.d("MediaController", "A2DP connected, sending play command")
if (connectedDevices.isNotEmpty()) { MediaController.sendPlay()
MediaController.sendPlay() MediaController.iPausedTheMedia = false
}
context.unregisterReceiver(this)
} }
bluetoothAdapter.closeProfileProxy(
profile,
proxy
)
} }
}
override fun onServiceDisconnected( }
profile: Int val a2dpIntentFilter = IntentFilter("android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED")
) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
} registerReceiver(a2dpConnectionStateReceiver, a2dpIntentFilter, RECEIVER_EXPORTED)
}, } else {
BluetoothProfile.A2DP registerReceiver(a2dpConnectionStateReceiver, a2dpIntentFilter)
) }
} else if (newInEarData == listOf(false, false)) { } else if (newInEarData == listOf(false, false)) {
MediaController.sendPause(force = true)
disconnectAudio(this@AirPodsService, device) disconnectAudio(this@AirPodsService, device)
} }

View File

@@ -82,7 +82,6 @@ object MediaController {
if (configs != null && !iPausedTheMedia) { if (configs != null && !iPausedTheMedia) {
Log.d("MediaController", "Seems like the user changed the state of media themselves, now I won't play until the ear detection pauses it.") Log.d("MediaController", "Seems like the user changed the state of media themselves, now I won't play until the ear detection pauses it.")
handler.postDelayed({ handler.postDelayed({
iPausedTheMedia = !audioManager.isMusicActive
userPlayedTheMedia = audioManager.isMusicActive userPlayedTheMedia = audioManager.isMusicActive
}, 7) // i have no idea why android sends an event a hundred times after the user does something. }, 7) // i have no idea why android sends an event a hundred times after the user does something.
} }
@@ -98,9 +97,9 @@ object MediaController {
@Synchronized @Synchronized
fun sendPause(force: Boolean = false) { fun sendPause(force: Boolean = false) {
Log.d("MediaController", "Sending pause with iPausedTheMedia: $iPausedTheMedia, userPlayedTheMedia: $userPlayedTheMedia") Log.d("MediaController", "Sending pause with iPausedTheMedia: $iPausedTheMedia, userPlayedTheMedia: $userPlayedTheMedia, isMusicActive: ${audioManager.isMusicActive}, force: $force")
if ((audioManager.isMusicActive && !userPlayedTheMedia) || force) { if ((audioManager.isMusicActive) && (!userPlayedTheMedia || force)) {
iPausedTheMedia = true iPausedTheMedia = if (force) audioManager.isMusicActive else true
userPlayedTheMedia = false userPlayedTheMedia = false
audioManager.dispatchMediaKeyEvent( audioManager.dispatchMediaKeyEvent(
KeyEvent( KeyEvent(