Search code examples
androidandroid-mediasession

App does not become the preferred MediaButtonReceiver when calling setActive(true) a second time


I have tried to implement media button control per Google's talk

I set the receiver in manifest:

<receiver android:name="android.support.v4.media.session.MediaButtonReceiver">
    <intent-filter>
        <action android:name="android.intent.action.MEDIA_BUTTON" />
    </intent-filter>
</receiver>

<service android:name=".player.PlayFileService">
    <intent-filter>
        <action android:name="android.intent.action.MEDIA_BUTTON" />
    </intent-filter>
</service>

create the MediaSessionCompat in onCreate() of Service:

    mediaSession = new MediaSessionCompat(getApplicationContext(), "SOUNDPROCESS");
    mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
    PlaybackStateCompat ps = new PlaybackStateCompat.Builder()
            .setActions(PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PAUSE | PlaybackStateCompat.ACTION_PLAY_PAUSE)
            .build();
    mediaSession.setPlaybackState(ps);
    mediaSession.setCallback(new MediaSessionCompat.Callback() {
        @Override
        public void onPlay() { ...
           }
    });

and handle the intent in onStartCommand()

MediaButtonReceiver.handleIntent(mediaSession, intent);

I then call setActive(true); when I gain audio focus, and setActive(false); when I stop playback. This works the first time, my app becomes the preferred media button receiver and receives callbacks.

However, if I stop playback in my app, go into another app like Google Play Music and start playback there, then return to my app and call setActive(true) Google Play Music continues to receive the callback and the media buttons don't work in my app.

From my understanding, the last call to setActive(true) should take precedence. I have verified that isActive() returns true. I can also work around the issue by creating a new MediaSessionCompat each time, but this doesn't seem ideal.

How can I make my app become the preferred media button receiver every time I call setActive(true)?

UPDATE: Minimum project to reproduce the problem here: https://github.com/svenoaks/MediaButtonDemo.git

Steps to reproduce:

  1. Run app, press the PLAY button. setActive(true) is called and MediaButtonReceiver is now the preferred media button.
  2. Press play/pause button on wired or wireless headphones or other media button. Toast shows indicating that callback is working.
  3. Start playback on another app such as Google Play Music which supports media buttons. Press pause on this app.
  4. The demo app can no longer be the preferred media button receiver, even if PLAY button is pressed again, calling setActive(true) again. The other app always responds to media buttons.

This was tested on Android 6.0.


Solution

  • The key to making this work correctly is to correctly set the PlaybackState every time your app starts playing or pauses (which it should be doing when another app gains the audio session and activates its own MediaSession. Without this, the problem as above will happen. Also, for Android 4.4 and lower, FLAG_HANDLES_TRANSPORT_CONTROLS must be set or the same problem will happen.