androidheadset

Android: Handle headset buttons events and Send information to MainActivity


Here's my effort to make a working code to handle a headset button event the best way. I read the Android developer guide, but it is obviously wrong because they ask to start listening registering a class name.

am.registerMediaButtonEventReceiver(RemoteControlReceiver); // Wrong

So I check out other examples to correct the code. For example many secret suggestions have been published in this question, I also tried other code such as this, and another solution with MediaSession, and cleaning the unneeded I wrote this code:

I implemented the class RemoteControlReceiver. Apparently there is no need for a static inner class, in fact, see this comment:

public class RemoteControlReceiver extends BroadcastReceiver {

        public RemoteControlReceiver() {
            super();
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "EVENT!!", Toast.LENGTH_SHORT).show();
            if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) {
                KeyEvent event = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
                if (KeyEvent.KEYCODE_MEDIA_PLAY == event.getKeyCode()) {
                    Toast.makeText(context, "EVENT!!", Toast.LENGTH_SHORT).show();

                }
            }
        }
    }

Then I registered the intent inside the MainActivity onCreate(){...

    AudioManager am = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
    ComponentName mReceiverComponent = new ComponentName(this, RemoteControlReceiver.class);
    am.registerMediaButtonEventReceiver(mReceiverComponent);

The registerMediaButtonEventReceiver is deprecated by the way...

Inside the manifest I recorder the filter, after the activity tag:

<activity>
...
</activity>

<receiver android:name=".RemoteControlReceiver" android:enabled="true">
    <intent-filter android:priority="2147483647">
        <action android:name="android.intent.action.MEDIA_BUTTON" />
    </intent-filter>
</receiver>

Note: with a static inner class would be, e.g., ".MainActivity$RemoteControlReceiver".

I am working on

compileSdkVersion 24
buildToolsVersion "24.0.0"
...
minSdkVersion 21
targetSdkVersion 24

Here my questions:


Solution

  • API 21 changed the entire media app APIs, now centering entirely around MediaSession. Instead of registering a BroadcastReceiver (as was needed prior to API 18) or a PendingIntent (via registerMediaButtonEventReceiver(PendingIntent)), you can receive callbacks directly in the MediaSession.Callback.

    You can set up a MediaSession via the following code:

    MediaSession.Callback callback = new MediaSession.Callback() {
      @Override
      public void onPlay() {
        // Handle the play button
      }
    };
    MediaSession mediaSession = new MediaSession(context,
      TAG); // Debugging tag, any string
    mediaSession.setFlags(
      MediaSession.FLAG_HANDLES_MEDIA_BUTTONS |
      MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
    mediaSession.setCallback(callback);
    
    // Set up what actions you support and the state of your player
    mediaSession.setState(
      new PlaybackState.Builder()
        .setActions(PlaybackState.ACTION_PLAY |
                    PlaybackState.ACTION_PAUSE |
                    PlaybackState.ACTION_PLAY_PAUSE);
        .setState(PlaybackState.STATE_PLAYING,
          0, // playback position in milliseconds
          1.0); // playback speed
    
    // Call this when you start playback after receiving audio focus
    mediaSession.setActive(true);
    

    If you only want to handle media buttons while your activity is visible, you can just have your MediaSession handled by the Activity itself (this would allow your Callback to just be a variable in your Activity).

    The Best practices in media playback talk from I/O 2016 goes through all of the details and other APIs required to build a great media app, although note that it uses MediaSessionCompat and the other Support Library classes as detailed in the Media playback and the Support Library blog post.