Edit May 8, 2016
I found the reason for my troubles receiving media button events in my app. See the answer below. I editid the title of this question to make finding the issue easier. The original title was "What can possibly block media buttons on Android Lollipop".
Original question, April 2015:
Scratching my head and staring at all the code for 2 days to no avail... My Android app is supposed to react to media buttons (e.g. from a headset, test it with a Bluetooth headset), like play/pause, next, rewind. Works fine on KitKat and below. I swear it even worked on Lollipop as well up until a few days ago. Now nothing, no trace that it hears media button presses. Would anyone have a quick suggestion where to look for the trouble? Tested with two Lollipop phones, same Bluetooth headset, and the same headset works fine for lower versions of Android. Also the same headset works fine, media buttons presses heard in other apps. What possibly could I break???
I now tested both old and new ways of listening to media buttons. In AndroidManifest.xml:
<receiver android:name=".MediaButtonIntentReceiver" android:enabled="false">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
The fact that it says enabled="false" is OK - I enable and disable the receiver as needed, and the MediaButtonIntentReceiver.java gets the events fine on KitKat and lower, complete silence on Lollipop.
I next switched to the latest appcompat (v22.1) and tried using MediaSessionCompat object and related code as follows. This worked great in a small test app, just one activity that I wrote - got my Logcat messages confirming that it hears media keys pressed on Lollipop. But when inserted into my app, again does not work on Lollipop. What the heck???
private MediaSessionCompat _mediaSession;
final String MEDIA_SESSION_TAG = "some_tag";
void initMediaSessions(Context context) {
// Start a new MediaSession
if (context == null)
return;
Lt.d("initMediaSession()...");
ComponentName eventReceiver = new ComponentName(context.getPackageName(), MediaButtonIntentReceiver.class.getName());
PendingIntent buttonReceiverIntent = PendingIntent.getBroadcast(
context,
0,
new Intent(Intent.ACTION_MEDIA_BUTTON),
PendingIntent.FLAG_UPDATE_CURRENT
);
// Parameters for new MediaSessionCompat():
// context The context.
// tag A short name for debugging purposes.
// mediaButtonEventReceiver The component name for your receiver. This must be non-null to support platform
// versions earlier than LOLLIPOP. May not be null below Lollipop.
// mbrIntent The PendingIntent for your receiver component that handles media button events. This is optional
// and will be used on JELLY_BEAN_MR2 and later instead of the component name.
_mediaSession = new MediaSessionCompat(context, MEDIA_SESSION_TAG, eventReceiver, buttonReceiverIntent);
_mediaSession.setCallback(new MediaSessionCallback());
_mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
_mediaSession.setActive(true);
PlaybackStateCompat state = new PlaybackStateCompat.Builder()
.setActions(
PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PLAY_PAUSE |
PlaybackStateCompat.ACTION_PAUSE |
PlaybackStateCompat.ACTION_SKIP_TO_NEXT | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS)
.setState(PlaybackStateCompat.STATE_STOPPED, 0, 1, SystemClock.elapsedRealtime())
.build();
_mediaSession.setPlaybackState(state);
}
final class MediaSessionCallback extends MediaSessionCompat.Callback {
@Override
public void onPlay() {
Lt.d("play");
}
@Override
public void onPause() {
Lt.d("pause");
}
@Override
public void onStop() {
Lt.d("stop.");
}
@Override
public void onSkipToNext() {
Lt.d("skipToNext");
}
@Override
public void onSkipToPrevious() {
Lt.d("skipToPrevious");
}
@Override
public boolean onMediaButtonEvent(final Intent mediaButtonIntent) {
Lt.d("GOT MediaButton EVENT");
KeyEvent keyEvent = (KeyEvent) mediaButtonIntent.getExtras().get(Intent.EXTRA_KEY_EVENT);
// ...do something with keyEvent, super... does nothing.
return super.onMediaButtonEvent(mediaButtonIntent);
}
}