Handling media buttons in Android 5.0 Lollipop
Asked Answered
E

1

13

Pre API 21 I was using a call like audioManager.registerMediaButtonEventReceiver(receiver); to handle media button events when a user pressed a button on his headset. As of API 21, it seems that MediaSession should be used. However, I'm not getting any response whatsoever.

final MediaSession session = new MediaSession(context, "TAG");
session.setCallback(new Callback() {
    @Override
    public boolean onMediaButtonEvent(final Intent mediaButtonIntent) {
        Log.i("TAG", "GOT EVENT");
        return super.onMediaButtonEvent(mediaButtonIntent);
    }
});

session.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS |
        MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);

session.setActive(true);

Above is what I think should work but doesn't. Does anyone know why this isn't working or how I should register?

Eby answered 18/11, 2014 at 16:32 Comment(3)
Have you set the session active? session.setActive(true)Watchman
Please see the code example. The last line is session.setActive(true);Eby
I have exactly the same problem you reported. I also tried using your code snippet with MediaSessionCompat (from support V4), but with no success. I will keep my investigation and if i find some solution, i will post as a answer here.Winonawinonah
D
22

To receive media button events, you need to:

  1. set a MediaSession.Callback and handle the proper events (*)

  2. set MediaSession.FLAG_HANDLES_MEDIA_BUTTONS and MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS flags

  3. set the mediaSession to active

  4. set a playbackstate properly, in special the actions (playback events) that your session handles. For example:

    PlaybackState state = new PlaybackState.Builder()
            .setActions(
                    PlaybackState.ACTION_PLAY | PlaybackState.ACTION_PLAY_PAUSE |
                    PlaybackState.ACTION_PLAY_FROM_MEDIA_ID | PlaybackState.ACTION_PAUSE |
                    PlaybackState.ACTION_SKIP_TO_NEXT | PlaybackState.ACTION_SKIP_TO_PREVIOUS)
            .setState(PlaybackState.STATE_PLAYING, position, speed, SystemClock.elapsedRealtime())
            .build();
    mSession.setPlaybackState(state);
    

My guess is that you are missing #4, because you are doing everything else correctly.

(*) the default implementation of Callback.onMediaButtonEvent handles all common media buttons and calls the proper onXXXX() methods (onPlay, onPause, onSkipToNext, etc). Unless you need to handle uncommon media buttons - or for debugging purposes -, you don't need to override onMediaButtonEvent.

Dealer answered 20/11, 2014 at 17:59 Comment(9)
This worked for me, thanks. It is not working only when receiving a call. I tried a workaround, creating a view to be always on top when a call is active, but it is not working too (on versions before Android L the view works).Winonawinonah
@Luis, I'm confused by what do you mean by receiving a call. You mean using the hardware buttons to answer a call, or pausing the music when a call comes in?Dealer
Actually, in my case, i want to override the default Android actions by my custom actions all the time. So, for example, i want to set one click to increase the system volume. In the current implementation, if the device is playing music or not, i can intercept the headset click and take my action instead of the android default action (play/pause). But when the user is with an ongoing call, the MediaSession cannot intercept the headset click, the Call Application has a higher priority and then takes its own action instead of my custom action.Winonawinonah
I don't think you can do that. android.googlesource.com/platform/packages/services/Telecomm/+/… sets a restricted flag in its MediaSession that gives it the higher priority for intercepting media buttons. I'm not super familiar with this code, though, so don't take this as an authoritative answer.Dealer
In the link that you sent, the flag MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY is used, but that is not available on the MediaSession class for developers. I found this flag value on this link android.googlesource.com/platform/frameworks/base/+/76fca4e%5E! and tried to put on my code, but then i got a crash asking for the MODIFY_PHONE_STATE permission. But even adding this permission on my manifest file, the crash still happens because this permission is only granted to system apps, which is not my case. Anyway, I will try to investigate further. Thanks for the replies.Winonawinonah
That's what I meant by "restricted flag" :-)Dealer
I am able to receive media events properly only when my app is running, but when music player is in background then play key event is being received by music player instead of my app, even though my app is in foreground. So how do we priorities my app to receive media play event.? I am using same MediaSession.Callbacks only for 5.0Slabber
To receive media button events while your activity is in foreground, call setMediaController() on your activity with a MediaController instance connected to your active MediaSession.Dealer
I know this answer is kind of old..I want to make two observations: 1. No need set the FLAG_HANDLES_MEDIA_BUTTONS or FLAG_HANDLES_TRANSPORT_CONTROLS flags on MediaSession...these flags are deprecated 2. Something not mentioned in the docs or in this answer...you must be playing real audio for media button events to be received in your app while it's in the background. See #66133314 2.Pyrometallurgy

© 2022 - 2024 — McMap. All rights reserved.