title: Receive callback on all Android media button events all the time (even when another app is playing audio)
body: <p><strong>Background Info:</strong> I need to detect whenever a user presses the play/pause button found on most headsets (KEYCODE_MEDIA_PLAY_PAUSE).</p>
  
  <p>I have it all <em>mostly</em> working using MediaSessions, but when another app starts playing audio, I stop getting callbacks.</p>
  
  <p>It seems like this is because the app that's playing audio created its own MediaSession and Android sends KeyEvents only to the newest MediaSession.  To prevent this I create an OnActiveSessionsChangedListener and create a new MediaSession every time it fires.</p>
  
  <p>This does work, but every time I create a new MediaSession, the listener fires again, so I find myself stuck in an inf loop.</p>
  
  <p><strong>My Question:</strong> does anyone know how I can do any of the following??:</p>
  
  <ul>
  <li>Prevent other apps from stealing my media button focus</li>
  <li>Detect when I've lost media button focus to another app, so I can create a new MediaSession only then, rather then whenever the active
  sessions change</li>
  <li>Check if I currently already have media button focus so I needlessly create a new MediaSession</li>
  </ul>
  
  <p><strong>What didn't work:</strong></p>
  
  <ul>
  <li>BroadcastReceiver on
  AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION didn't work
  because apps have to manually trigger that Broadcast, and many apps,
  like NPR One do not</li>
  <li>AudioManager.OnAudioFocusChangeListener didn't work because it requires I have
  audio focus</li>
  <li>BroadcastReceiver with max priority on android.intent.action.MEDIA_BUTTON &amp; calling abortBroadcast(), but when other apps were playing audio, my receiver wasn't triggered.  Also, other apps can set max priority as well.</li>
  </ul>
  
  <p><strong>My Code:</strong></p>
  
  <pre><code>mMediaSessionManager.addOnActiveSessionsChangedListener(controllers -&gt; {
      boolean updateButtonReceiver = false;
  
      // recreate MediaSession if another app handles media buttons
      for (MediaController mediaController : controllers) {
          if (!TextUtils.equals(getPackageName(), mediaController.getPackageName())) {
              if ((mediaController.getFlags() &amp; (MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS)) != 0L) {
                  updateButtonReceiver = true;
              }
          }
  
      }
  
      if (updateButtonReceiver) {
          // using a handler with a delay of about 2 seconds because this listener fires very often.
          mAudioFocusHandler.removeCallbacksAndMessages(null);
          mAudioFocusHandler.sendEmptyMessageDelayed(0, AUDIO_FOCUS_DELAY_MS);
      }
  }, ClickAppNotificationListener.getComponentName(this));
  </code></pre>
  
  <p>Here is the handler that gets triggered:</p>
  
  <pre><code>private final Handler mAudioFocusHandler = new Handler() {
      @Override
      public void handleMessage(Message msg) {
          if (mShouldBeEnabled) {
              updateButtonReceiverEnabled(true);
          }
      }
  };
  </code></pre>
  
  <p>And finally here is the method that the Handler triggers:</p>
  
  <pre><code>private void updateButtonReceiverEnabled(boolean shouldBeEnabled) {
      // clear old session (not sure if this is necessary)
      if (mMediaSession != null) {
          mMediaSession.setActive(false);
          mMediaSession.setFlags(0);
          mMediaSession.setCallback(null);
          mMediaSession.release();
          mMediaSession = null;
      }
  
      mMediaSession = new MediaSessionCompat(this, MEDIA_SESSION_TAG);
      mMediaSession.setCallback(mMediaButtonCallback);
      mMediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
      mMediaSession.setPlaybackToLocal(AudioManager.STREAM_MUSIC);
      mMediaSession.setActive(true);
      mMediaSession.setPlaybackState(new PlaybackStateCompat.Builder()
              .setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE)
              .setState(PlaybackStateCompat.STATE_CONNECTING, 0, 0f)
              .build());
  
      if (shouldBeEnabled != mShouldBeEnabled) {            
          getPackageManager().setComponentEnabledSetting(mMediaButtonComponent,
                  shouldBeEnabled
                          ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
                          : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                  PackageManager.DONT_KILL_APP);
      }
  
      mShouldBeEnabled = shouldBeEnabled;
  }
  </code></pre>
  
  <p>Thanks!</p>