From ad51d0967215effff2d00f59ef75d75318bc2ef2 Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Sun, 27 Mar 2022 21:40:42 +0530 Subject: [PATCH] Use MediaButtonReceiver from androidx.media to handle headset button actions --- app/build.gradle | 1 + app/src/main/AndroidManifest.xml | 9 +- .../service/MediaButtonIntentReceiver.kt | 200 ------------------ .../service/MediaSessionCallback.kt | 5 - .../monkey/retromusic/service/MusicService.kt | 18 +- 5 files changed, 11 insertions(+), 222 deletions(-) delete mode 100644 app/src/main/java/code/name/monkey/retromusic/service/MediaButtonIntentReceiver.kt diff --git a/app/build.gradle b/app/build.gradle index 2aa64fffb..41120fe0a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -172,4 +172,5 @@ dependencies { implementation 'cat.ereza:customactivityoncrash:2.3.0' implementation 'me.tankery.lib:circularSeekBar:1.3.2' debugImplementation 'com.github.amitshekhariitbhu:Android-Debug-Database:1.0.6' + debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.8.1' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 97eee789a..6351206bf 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -38,8 +38,8 @@ + android:launchMode="singleTop" + android:theme="@style/SplashTheme"> @@ -212,7 +212,7 @@ @@ -323,6 +323,9 @@ + + + { - val clickCount = msg.arg1 - - if (DEBUG) Log.v(TAG, "Handling headset click, count = $clickCount") - val command = when (clickCount) { - 1 -> ACTION_TOGGLE_PAUSE - 2 -> ACTION_SKIP - 3 -> ACTION_REWIND - else -> null - } - - if (command != null) { - val context = msg.obj as Context - startService(context, command) - } - } - } - releaseWakeLockIfHandlerIdle() - } - } - - fun handleIntent(context: Context, intent: Intent): Boolean { - val intentAction = intent.action - if (Intent.ACTION_MEDIA_BUTTON == intentAction) { - val event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT) - ?: return false - - val keycode = event.keyCode - val action = event.action - val eventTime = if (event.eventTime != 0L) - event.eventTime - else - System.currentTimeMillis() - - var command: String? = null - when (keycode) { - KeyEvent.KEYCODE_MEDIA_STOP -> command = ACTION_STOP - KeyEvent.KEYCODE_HEADSETHOOK, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE -> command = - ACTION_TOGGLE_PAUSE - KeyEvent.KEYCODE_MEDIA_NEXT -> command = ACTION_SKIP - KeyEvent.KEYCODE_MEDIA_PREVIOUS -> command = ACTION_REWIND - KeyEvent.KEYCODE_MEDIA_PAUSE -> command = ACTION_PAUSE - KeyEvent.KEYCODE_MEDIA_PLAY -> command = ACTION_PLAY - } - if (command != null) { - if (action == KeyEvent.ACTION_DOWN) { - if (event.repeatCount == 0) { - // Only consider the first event in a sequence, not the repeat events, - // so that we don't trigger in cases where the first event went to - // a different app (e.g. when the user ends a phone call by - // long pressing the headset button) - - // The service may or may not be running, but we need to send it - // a command. - if (keycode == KeyEvent.KEYCODE_HEADSETHOOK || keycode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) { - if (eventTime - mLastClickTime >= DOUBLE_CLICK) { - mClickCounter = 0 - } - - mClickCounter++ - if (DEBUG) Log.v(TAG, "Got headset click, count = $mClickCounter") - mHandler.removeMessages(MSG_HEADSET_DOUBLE_CLICK_TIMEOUT) - - val msg = mHandler.obtainMessage( - MSG_HEADSET_DOUBLE_CLICK_TIMEOUT, mClickCounter, 0, context - ) - - val delay = (if (mClickCounter < 3) DOUBLE_CLICK else 0).toLong() - if (mClickCounter >= 3) { - mClickCounter = 0 - } - mLastClickTime = eventTime - acquireWakeLockAndSendMessage(context, msg, delay) - } else { - startService(context, command) - } - return true - } - } - } - } - return false - } - - private fun startService(context: Context, command: String?) { - val intent = Intent(context, MusicService::class.java) - intent.action = command - try { - // IMPORTANT NOTE: (kind of a hack) - // on Android O and above the following crashes when the app is not running - // there is no good way to check whether the app is running so we catch the exception - // we do not always want to use startForegroundService() because then one gets an ANR - // if no notification is displayed via startForeground() - // according to Play analytics this happens a lot, I suppose for example if command = PAUSE - context.startService(intent) - } catch (ignored: IllegalStateException) { - ContextCompat.startForegroundService(context, intent) - } - } - - private fun acquireWakeLockAndSendMessage(context: Context, msg: Message, delay: Long) { - if (wakeLock == null) { - val appContext = context.applicationContext - val pm = appContext.getSystemService() - wakeLock = pm?.newWakeLock( - PowerManager.PARTIAL_WAKE_LOCK, - "RetroMusicApp:Wakelock headset button" - ) - wakeLock!!.setReferenceCounted(false) - } - if (DEBUG) Log.v(TAG, "Acquiring wake lock and sending " + msg.what) - // Make sure we don't indefinitely hold the wake lock under any circumstances - wakeLock!!.acquire(10000) - - mHandler.sendMessageDelayed(msg, delay) - } - - private fun releaseWakeLockIfHandlerIdle() { - if (mHandler.hasMessages(MSG_HEADSET_DOUBLE_CLICK_TIMEOUT)) { - if (DEBUG) Log.v(TAG, "Handler still has messages pending, not releasing wake lock") - return - } - - if (wakeLock != null) { - if (DEBUG) Log.v(TAG, "Releasing wake lock") - wakeLock!!.release() - wakeLock = null - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/service/MediaSessionCallback.kt b/app/src/main/java/code/name/monkey/retromusic/service/MediaSessionCallback.kt index b52752be2..e2a29931f 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/MediaSessionCallback.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/MediaSessionCallback.kt @@ -15,7 +15,6 @@ package code.name.monkey.retromusic.service import android.content.Context -import android.content.Intent import android.os.Bundle import android.provider.MediaStore import android.support.v4.media.session.MediaSessionCompat @@ -179,10 +178,6 @@ class MediaSessionCallback( musicService.seek(pos.toInt()) } - override fun onMediaButtonEvent(mediaButtonIntent: Intent): Boolean { - return MediaButtonIntentReceiver.handleIntent(context, mediaButtonIntent) - } - override fun onCustomAction(action: String, extras: Bundle?) { when (action) { CYCLE_REPEAT -> { diff --git a/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt b/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt index 9d177a101..56e3e70fa 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt @@ -14,7 +14,6 @@ package code.name.monkey.retromusic.service import android.app.NotificationManager -import android.app.PendingIntent import android.appwidget.AppWidgetManager import android.bluetooth.BluetoothDevice import android.content.* @@ -47,8 +46,8 @@ import androidx.media.AudioAttributesCompat.CONTENT_TYPE_MUSIC import androidx.media.AudioFocusRequestCompat import androidx.media.AudioManagerCompat import androidx.media.MediaBrowserServiceCompat +import androidx.media.session.MediaButtonReceiver.handleIntent import androidx.preference.PreferenceManager -import code.name.monkey.appthemehelper.util.VersionUtils.hasMarshmallow import code.name.monkey.appthemehelper.util.VersionUtils.hasQ import code.name.monkey.retromusic.* import code.name.monkey.retromusic.activities.LockScreenActivity @@ -94,6 +93,7 @@ import code.name.monkey.retromusic.volume.OnAudioVolumeChangedListener import com.bumptech.glide.RequestBuilder import com.bumptech.glide.request.target.SimpleTarget import com.bumptech.glide.request.transition.Transition +import com.google.android.gms.cast.framework.media.MediaIntentReceiver import org.koin.java.KoinJavaComponent.get import java.util.* import kotlin.collections.ArrayList @@ -753,6 +753,7 @@ class MusicService : MediaBrowserServiceCompat(), override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { if (intent != null && intent.action != null) { + handleIntent(mediaSession, intent) restoreQueuesAndPositionIfNecessary() when (intent.action) { ACTION_TOGGLE_PAUSE -> if (isPlaying) { @@ -1445,24 +1446,13 @@ class MusicService : MediaBrowserServiceCompat(), } private fun setupMediaSession() { - val mediaButtonReceiverComponentName = - ComponentName(applicationContext, MediaButtonIntentReceiver::class.java) - val mediaButtonIntent = Intent(Intent.ACTION_MEDIA_BUTTON) - mediaButtonIntent.component = mediaButtonReceiverComponentName - val mediaButtonReceiverPendingIntent = PendingIntent.getBroadcast( - applicationContext, 0, mediaButtonIntent, - if (hasMarshmallow()) PendingIntent.FLAG_IMMUTABLE else 0 - ) mediaSession = MediaSessionCompat( this, - "RetroMusicPlayer", - mediaButtonReceiverComponentName, - mediaButtonReceiverPendingIntent + "RetroMusicPlayer" ) val mediasessionCallback = MediaSessionCallback(applicationContext, this) mediaSession?.setCallback(mediasessionCallback) mediaSession?.isActive = true - mediaSession?.setMediaButtonReceiver(mediaButtonReceiverPendingIntent) } inner class MusicBinder : Binder() {