diff --git a/android/app/src/main/java/me/kavishdevar/aln/services/AirPodsService.kt b/android/app/src/main/java/me/kavishdevar/aln/services/AirPodsService.kt index 0310c76..6ef5f1a 100644 --- a/android/app/src/main/java/me/kavishdevar/aln/services/AirPodsService.kt +++ b/android/app/src/main/java/me/kavishdevar/aln/services/AirPodsService.kt @@ -459,6 +459,7 @@ 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) { @@ -516,15 +517,41 @@ class AirPodsService: Service() { disconnectAudio(this@AirPodsService, device) } + if (inEarData.contains(false) && newInEarData == listOf( + true, + true + ) + ) { + Log.d("AirPods Parser", "User put in both AirPods from just one.") + MediaController.userPlayedTheMedia = false + } + if (newInEarData.contains(false) && inEarData == listOf( + true, + true + ) + ) { + Log.d("AirPods Parser", "User took one of two out.") + MediaController.userPlayedTheMedia = false + } + + if (newInEarData.sorted() == inEarData.sorted()) { + return + } + inEarData = newInEarData if (inEar == true) { if (!justEnabledA2dp) { justEnabledA2dp = false +// if (audioManager.activePlaybackConfigurations.any { it.audioDeviceInfo?.address == device.address }) { MediaController.sendPlay() + MediaController.iPausedTheMedia = false +// } } } else { - MediaController.sendPause() +// if (audioManager.activePlaybackConfigurations.any { it.audioDeviceInfo?.address == device.address }) { + MediaController.sendPause() +// } } } } diff --git a/android/app/src/main/java/me/kavishdevar/aln/utils/MediaController.kt b/android/app/src/main/java/me/kavishdevar/aln/utils/MediaController.kt index 8936506..87b6363 100644 --- a/android/app/src/main/java/me/kavishdevar/aln/utils/MediaController.kt +++ b/android/app/src/main/java/me/kavishdevar/aln/utils/MediaController.kt @@ -20,21 +20,43 @@ package me.kavishdevar.aln.utils import android.media.AudioManager +import android.media.AudioPlaybackConfiguration +import android.os.Handler +import android.os.Looper import android.util.Log import android.view.KeyEvent object MediaController { - private var initialVolume: Int? = null // Nullable to track the unset state - private lateinit var audioManager: AudioManager // Declare AudioManager + private var initialVolume: Int? = null + private lateinit var audioManager: AudioManager + var iPausedTheMedia = false + var userPlayedTheMedia = false - // Initialize the singleton with the AudioManager instance fun initialize(audioManager: AudioManager) { this.audioManager = audioManager + audioManager.registerAudioPlaybackCallback(cb, null) + } + + val cb = object : AudioManager.AudioPlaybackCallback() { + override fun onPlaybackConfigChanged(configs: MutableList?) { + super.onPlaybackConfigChanged(configs) + Log.d("MediaController", "Playback config changed, iPausedTheMedia: $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.") + Handler(Looper.getMainLooper()).postDelayed({ + iPausedTheMedia = !audioManager.isMusicActive + userPlayedTheMedia = audioManager.isMusicActive + }, 7) // i have no idea why, but android sends a pause event a hundred times after the user does something. + } + } } @Synchronized fun sendPause() { - if (audioManager.isMusicActive) { + Log.d("MediaController", "Sending pause with iPausedTheMedia: $iPausedTheMedia, userPlayedTheMedia: $userPlayedTheMedia") + if (audioManager.isMusicActive && !userPlayedTheMedia) { + iPausedTheMedia = true + userPlayedTheMedia = false audioManager.dispatchMediaKeyEvent( KeyEvent( KeyEvent.ACTION_DOWN, @@ -52,7 +74,10 @@ object MediaController { @Synchronized fun sendPlay() { - if (!audioManager.isMusicActive) { + Log.d("MediaController", "Sending play with iPausedTheMedia: $iPausedTheMedia") + if (iPausedTheMedia) { + Log.d("MediaController", "Sending play and setting userPlayedTheMedia to false") + userPlayedTheMedia = false audioManager.dispatchMediaKeyEvent( KeyEvent( KeyEvent.ACTION_DOWN, @@ -76,8 +101,7 @@ object MediaController { Log.d("MediaController", "Initial Volume Set: $initialVolume") audioManager.setStreamVolume( AudioManager.STREAM_MUSIC, - audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) * 1 / 12, // Set to a lower volume when speaking starts - 0 + audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) * 1 / 12, 0 ) } Log.d("MediaController", "Initial Volume: $initialVolume") @@ -91,4 +115,5 @@ object MediaController { initialVolume = null // Reset to null after restoring the volume } } + } \ No newline at end of file diff --git a/android/gradle/libs.versions.toml b/android/gradle/libs.versions.toml index 0eb42fe..b2af026 100644 --- a/android/gradle/libs.versions.toml +++ b/android/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] accompanistPermissions = "0.36.0" -agp = "8.7.2" +agp = "8.7.3" hiddenapibypass = "4.3" kotlin = "2.0.0" coreKtx = "1.15.0" diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index b4dd5bf..4e7f0c7 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Mon Oct 07 22:30:36 IST 2024 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists