title: Catching android media button events
body: <p>I have an app that launches a foreground service to play some media and I want to be able to control it with media buttons on smart watches/headphones and control it from a mediastyle notification etc. </p>
  
  <p>I cannot get the media buttons to work consistently though. In the logs I can see they are often sent to other apps even though I started my MediaSession and playback last.</p>
  
  <p>But I cannot get it to work despite having a media session where I setActive(true) and having the media callback defined?</p>
  
  <p>Manifest:</p>
  
  <pre><code>&lt;service
      android:name=".services.MediaControllerService"
      android:enabled="true"
      android:exported="true"
      android:permission="android.permission.FOREGROUND_SERVICE"&gt;
      &lt;intent-filter android:priority="999"&gt;
          &lt;action android:name="android.intent.action.MEDIA_BUTTON"/&gt;
      &lt;/intent-filter&gt;
  &lt;/service&gt;
  </code></pre>
  
  <p>Code (Note the packages, it was hard in android 10 finding the correct combination of packages that worked together and gave me MediaStyle)...</p>
  
  <pre><code>import android.app.NotificationChannel;
  import android.app.NotificationManager;
  import android.app.PendingIntent;
  import android.app.Service;
  import android.content.Context;
  import android.content.Intent;
  import android.media.AudioAttributes;
  import android.media.AudioFocusRequest;
  import android.media.AudioManager;
  import android.media.MediaMetadata;
  import android.support.v4.media.MediaMetadataCompat;
  import android.support.v4.media.session.MediaControllerCompat;
  import android.support.v4.media.session.MediaSessionCompat;
  import android.support.v4.media.session.PlaybackStateCompat;
  import android.view.KeyEvent;
  import androidx.annotation.Nullable;
  import androidx.core.app.NotificationCompat;
  import androidx.media.session.MediaButtonReceiver;
  
  public class TextToSpeechMediaControllerService extends Service { 
      public static final String START_SERVICE_ACTION_INTENT = "serviceStart";
      private TextToSpeechPlayer player;
      private MediaMetadataCompat mediaMetaData;
      private MediaSessionCompat mediaSession;
      private TextToSpeechMediaControllerService.AudioFocusHelper mAudioFocusHelper;
      private AudioManager mAudioManager;
      private final String NOTIFICATION_CHANNEL_TEXT_TO_SPEECH_CONTROLS = "fp_tts_media_controls";
      public MediaControllerCompat.TransportControls transportControls;
      private String pageTitle;
      private String pageAddress;
      private String pageDomain;
      private SpeechBank currentSpeechBank;
      private MediaButtonReceiver mediaButtonReceiver;
      private AudioFocusRequest audioFocusRequest;
      private AudioAttributes playbackAttributes;
      private Handler handler;
  
      public TextToSpeechMediaControllerService() {
      }
  
      @Override
      public void onCreate() {
          Log.d("TTSMEDIAPLAYER", "---------- STARTING SERVICE ----------");
          player = new TextToSpeechPlayer(this);
          mAudioManager = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
          mAudioFocusHelper = new TextToSpeechMediaControllerService.AudioFocusHelper();
  
          mediaSession = new MediaSessionCompat(this, "fpt2s");
          mediaSession.setCallback(callback);
          mediaSession.setActive(true);
          handler = new Handler(); // something to do with handling delayed focus https://developer.android.com/guide/topics/media-apps/audio-focus#audio-focus-change
          transportControls = mediaSession.getController().getTransportControls();
          NotificationChannel channel = null;
          if (android.os.Build.VERSION.SDK_INT &gt;= android.os.Build.VERSION_CODES.O) {
              channel = new NotificationChannel(NOTIFICATION_CHANNEL_TEXT_TO_SPEECH_CONTROLS,
                      getString(R.string.media_controls_notification_channel_title),
                      NotificationManager.IMPORTANCE_HIGH);
              ((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);
          }
          super.onCreate();
      }
  
      @Override
      public int onStartCommand(Intent intent, int flags, int startId) {
          Log.d("TTSMEDIAPLAYER", "---------- onStartCOmmand ("+intent.getAction()+", startId) ----------");
          MediaButtonReceiver.handleIntent(mediaSession, intent); // Required to catch media button events and send them to mediasession callback
          if (intent !=null &amp;&amp; intent.getExtras()!=null){
              int closeCommand = intent.getExtras().getInt("swipeToClose", 0);
              if(closeCommand==1){
                  Log.d("TTSMEDIAPLAYER", "Close service intent received.");
                  // Pre-lollipop media style close button. Unable to test
                  stopSelf();
                  return super.onStartCommand(intent, flags, startId);
              }
              //Request audio focus
              if (false ) { // mAudioFocusHelper.requestAudioFocus() == false not needed because we request focus onPlay
                  Log.d("TTSMEDIAPLAYER", "Starting and requesting focus...");
                  //Could not gain focus
                  stopSelf();
              }else {
                  Log.d("TTSMEDIAPLAYER", "Focued. Starting...");
                  boolean isPlaying = player.isPlaying();
                  String nodesAsJsonString = intent.getExtras().getString("nodesAsJsonString", "[]");
                  if (nodesAsJsonString != null &amp;&amp; !nodesAsJsonString.equals("[]")) {
                      isPlaying = true;
                      // New TTS playback has been requested
                      pageTitle = intent.getExtras().getString("pageTitle", "");
                      pageAddress = intent.getExtras().getString("pageAddress", "");
                      pageDomain = UrlHelper.getDomain(pageAddress, true, true, true);
                      final Locale languageToSpeak = UrlHelper.getLanguageFromAddress(pageAddress);
  
                      try {
                          currentSpeechBank = new SpeechBank(nodesAsJsonString, languageToSpeak);
                      } catch (JSONException e) {
                          stopSelf();
                          return super.onStartCommand(intent, flags, startId);
                      }
                      mediaMetaData = new MediaMetadataCompat.Builder()
                              // TODO i guessed at these, I think this might be used on things like bluetooth speakers that have a display
                              .putString(MediaMetadata.METADATA_KEY_ARTIST, pageAddress)
                              .putString(MediaMetadata.METADATA_KEY_TITLE, pageTitle)
                              .putString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE, pageTitle)
                              .build();
                      mediaSession.setMetadata(mediaMetaData);
                  }
                  Log.d("TTSMEDIAPLAYER", "isPlaying: " + isPlaying);
                  /*mediaSession.setFlags(
                          MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | // apparently no longer needed
                                  //MediaSession.FLAG_HANDLES_QUEUE_COMMANDS | //
                                  MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS 
                  );*/
  
                  if(intent.getAction()!=null &amp;&amp; intent.getAction().equals(START_SERVICE_ACTION_INTENT)) {
                      Log.d("TTSMEDIAPLAYER", "START_SERVICE_ACTION_INTENT detected, triggering transportcontrols.play");
                      transportControls.play();
                  }
              }
          }
          return super.onStartCommand(intent, flags, startId); //  START_NOT_STICKY;?
      }
  
      private void updateNotificationAndMediaButtons(boolean isPlaying) {
          // ... notification stuff ...
          startForeground(1, notificationBuilder.build());
      }
  
      @Override
      public void onDestroy() {
          mediaSession.release();
          mAudioFocusHelper.abandonAudioFocus();
          player.freeUpResources();
          super.onDestroy();
      }
  
      @Nullable
      @Override
      public IBinder onBind(Intent intent) {
          return null;
      }
  
      private MediaSessionCompat.Callback callback = new MediaSessionCompat.Callback() {
  
          @Override
          public void onSkipToNext() {
              Log.d("TTSMEDIAPLAYER", "SKIP TO NEXT");
              super.onSkipToNext();
              handleFastForward();
          }
  
          @Override
          public void onPlay() {
              Log.d("TTSMEDIAPLAYER", "onPLAY!");
              if(mAudioFocusHelper.requestAudioFocus()) {
                  if(player.isPaused()){
                      Log.d("TTSMEDIAPLAYER", "(resuming)");
                      player.resume();
                  }else{
                      Log.d("TTSMEDIAPLAYER", "(not started? playNew)");
                      player.playNew(currentSpeechBank);
                  }
                  // TODO TTS textToSpeechPlayer.play();
                  PlaybackStateCompat state = new PlaybackStateCompat.Builder()
                          // Supported actions in current state
                          .setActions(
                                  PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_STOP
                                          | PlaybackStateCompat.ACTION_FAST_FORWARD | PlaybackStateCompat.ACTION_REWIND
                          )
                          // Current state
                          .setState(PlaybackStateCompat.STATE_PLAYING, player.getCurrentPosition(), 1, SystemClock.elapsedRealtime())
                          .build();
                  mediaSession.setPlaybackState(state);
                  updateNotificationAndMediaButtons(true);
              }
              super.onPlay();
          }
  
          @Override
          public void onPause() {
              Log.d("TTSMEDIAPLAYER", "onPAUSE!");
              player.pause();
              PlaybackStateCompat state = new PlaybackStateCompat.Builder()
                      // Set supported actions in current state
                      .setActions(
                              PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_STOP |
                                      PlaybackStateCompat.ACTION_FAST_FORWARD | PlaybackStateCompat.ACTION_REWIND)
                      // Set current state
                      .setState(PlaybackStateCompat.STATE_PAUSED, player.getCurrentPosition(), 1, SystemClock.elapsedRealtime())
                      .build();
              mediaSession.setPlaybackState(state);
              updateNotificationAndMediaButtons(false);
              super.onPause();
          }
  
          @Override
          public void onSkipToPrevious() {
              Log.d("TTSMEDIAPLAYER", "SKIP TRACK PREV!");
              player.rewind();
              super.onSkipToPrevious();
          }
  
          @Override
          public void onFastForward() {
              Log.d("TTSMEDIAPLAYER", "FAST FORWARD!");
              super.onFastForward();
              handleFastForward();
          }
  
          @Override
          public void onRewind() {
              Log.d("TTSMEDIAPLAYER", "REWIND!");
              player.rewind();
              PlaybackStateCompat state = new PlaybackStateCompat.Builder()
                      // Set supported actions in current state
                      .setActions(
                              PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_STOP |
                                      PlaybackStateCompat.ACTION_FAST_FORWARD | PlaybackStateCompat.ACTION_REWIND)
                      // Set current state
                      .setState(PlaybackStateCompat.STATE_PLAYING, player.getCurrentPosition(), 1, SystemClock.elapsedRealtime())
                      .build();
              mediaSession.setPlaybackState(state);
              updateNotificationAndMediaButtons(true);
              super.onRewind();
          }
  
          @Override
          public void onStop() {
              Log.d("TTSMEDIAPLAYER", "STOP!");
              player.stop();
              PlaybackStateCompat state = new PlaybackStateCompat.Builder()
                      // Set supported actions in current state
                      //    .setActions(null)
                      // Set current state
                      .setState(PlaybackStateCompat.STATE_STOPPED, player.getCurrentPosition(), 1, SystemClock.elapsedRealtime())
                      .build();
              mediaSession.setPlaybackState(state);
              mAudioFocusHelper.abandonAudioFocus();
              stopSelf();
              //super.onStop();
          }
      };
  
      private void handleFastForward() {
          boolean hasReachedEnd = player.fastForward();
          if(hasReachedEnd){
              transportControls.stop();
          }else{
              PlaybackStateCompat state = new PlaybackStateCompat.Builder()
                      // Set supported actions in current state
                      .setActions(
                              PlaybackStateCompat.ACTION_PAUSE | PlaybackStateCompat.ACTION_STOP |
                                      PlaybackStateCompat.ACTION_FAST_FORWARD | PlaybackStateCompat.ACTION_REWIND)
                      // Set current state
                      .setState(PlaybackStateCompat.STATE_PLAYING, player.getCurrentPosition(), 1, SystemClock.elapsedRealtime())
                      .build();
              mediaSession.setPlaybackState(state);
              updateNotificationAndMediaButtons(true);
          }
      }
  
      /**
       * Helper class for managing audio focus related tasks.
       */
      private final class AudioFocusHelper
              implements AudioManager.OnAudioFocusChangeListener {
  
          private boolean mPlayOnAudioFocus = false;
  
          private boolean requestAudioFocus() {
              Log.d("TTSMEDIAPLAYER", "requestAudioFocus()...");
              playbackAttributes = new AudioAttributes.Builder()
                      .setUsage(AudioAttributes.USAGE_MEDIA)
                      .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
                      .build();
  
              if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.O) {
                  audioFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
                          .setAudioAttributes(playbackAttributes)
                          .setAcceptsDelayedFocusGain(false)
                          .setOnAudioFocusChangeListener(mAudioFocusHelper, handler)
                          .build();
                  int res = mAudioManager.requestAudioFocus(audioFocusRequest);
                  if (res == AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
                      Log.d("TTSMEDIAPLAYER", "audio focus failed...");
                      return false;
                  } else if (res == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
                      Log.d("TTSMEDIAPLAYER", "audio focus granted...");
                      return true;
                  } else if (res == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) {
                      Log.d("TTSMEDIAPLAYER", "audio focus DELAYED...");
                      // use case for this is imagine being in a phone call that has focus,
                      // then the user opens a game. The game
                      // should start playing audio once the call finishes.
                      return false; // todo?
                  }
              }else{
                  final int result = mAudioManager.requestAudioFocus(this,
                          AudioManager.STREAM_MUSIC,
                          AudioManager.AUDIOFOCUS_GAIN);
                  return result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
              }
              Log.d("TTSMEDIAPLAYER", "audio focus returning default!?");
              return false;
          }
  
          private void abandonAudioFocus() {
              Log.d("TTSMEDIAPLAYER", "abandonAudioFocus()");
              mAudioManager.abandonAudioFocus(this);
          }
  
          @Override
          public void onAudioFocusChange(int focusChange) {
              Log.d("TTSMEDIAPLAYER", "Audio focus changed...");
              switch (focusChange) {
                  case AudioManager.AUDIOFOCUS_GAIN:
  
                      Log.d("TTSMEDIAPLAYER", "Audio focus gained!");
                      if (mPlayOnAudioFocus &amp;&amp; player.isPaused()) {
                          player.resume();
                          //} else if (isPlaying()) {
                          //    setVolume(MEDIA_VOLUME_DEFAULT);
                      }
                      mPlayOnAudioFocus = false;
                      break;
  
                  case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
                      Log.d("TTSMEDIAPLAYER", "Something about ducks!?");
                      // this might be for dropping the sound while something else happens (text notifications)
                      //setVolume(MEDIA_VOLUME_DUCK);
                      break;
  
                  case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
                      Log.d("TTSMEDIAPLAYER", "AUDIOFOCUS_LOSS_TRANSIENT!");
                      if (player.isPlaying()) {
                          // I think this is for temporary loss of focus e.g. calls/notificaitons
                          mPlayOnAudioFocus = true;
                          player.pause();
                      }
                      break;
                  case AudioManager.AUDIOFOCUS_LOSS:
                      // Seems to be triggered when you press play in another media app (i.e. they requested focus)
                      Log.d("TTSMEDIAPLAYER", "AUDIOFOCUS_LOSS! abandoning focus, pausing speech");
                      mAudioManager.abandonAudioFocus(this);
                      if (player.isPlaying()) {
                          player.pause();
                          mPlayOnAudioFocus = false;
                      }
                      updateNotificationAndMediaButtons(false);
                      break;
                  default:
                      Log.d("TTSMEDIAPLAYER", "AUDIOFOCUS_???");
              }
          }
      }
  }
  </code></pre>
  
  <p>build.gradle</p>
  
  <pre><code>dependencies {
  implementation fileTree(dir: 'libs', include: ['*.jar'])
  implementation 'androidx.appcompat:appcompat:1.1.0'
  implementation 'com.google.android.material:material:1.0.0'
  implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
  implementation 'androidx.vectordrawable:vectordrawable:1.1.0'
  implementation 'androidx.legacy:legacy-support-v13:1.0.0'
  implementation 'androidx.legacy:legacy-support-v4:1.0.0'
  implementation 'androidx.media:media:1.1.0'
  ...
  </code></pre>
  
  <p>I've been stuck on this for a while so any help would be greatly appreciated.</p>
  
  <p>Logs:</p>
  
  <pre><code>? I/MusicController: [MediaSessionMonitor.java:153:onActiveSessionsChanged()] oooooo 
  ? I/MusicController: [MediaSessionMonitor.java:302:clear()] oooooo 
  ? D/MusicController: [MediaSessionMonitor.java:99:clearMediaContorllersMap()] oooooo Controller is already empty
  ? W/MusicController: [MediaSessionMonitor.java:171:updateMediaControllers()] oooooo Controller is empty
  ? I/MediaFocusControl:  AudioFocus  requestAudioFocus() from uid/pid 10345/8858 clientId=android.media.AudioManagerEx@63b6ee9fishpowered.bar.services.TextToSpeechMediaControllerService$AudioFocusHelper@44f676e req=1 flags=0x0
  ? I/MusicController: [MediaSessionMonitor.java:153:onActiveSessionsChanged()] oooooo 
  ? I/MusicController: [MediaSessionMonitor.java:174:updateMediaControllers()] oooooo List size :1
  ? I/MusicController: [MediaSessionMonitor.java:178:updateMediaControllers()] oooooo MediaController received packageName foo.bar
  ? D/MusicController: [MediaSessionMonitor.java:74:addToMediaContorllersMap()] oooooo Added = android.media.session.MediaSession$Token@986e7dd
  ? I/MusicController: [MediaSessionMonitor.java:78:addToMediaContorllersMap()] oooooo mMediaContorllersMap.size() = 1
  ? I/MusicController: [MediaSessionMonitor.java:222:checkAndUpdateMusicController()] oooooo is MusicController Updated = false
  ? I/MusicController: [MediaSessionMonitor.java:182:updateMediaControllers()] oooooo mMediaContorllersMap size = 1
  ? I/MediaFocusControl:  AudioFocus  requestAudioFocus() from uid/pid 10345/8858 clientId=android.media.AudioManagerEx@63b6ee9fishpowered.bar.services.TextToSpeechMediaControllerService$AudioFocusHelper@44f676e req=1 flags=0x0
  ? I/MusicController: [MediaControllerCallbackWrapper.java:55:onMetadataChanged()] oooooo This callback is from foo.bar
  ? I/MusicController: [MediaControllerCallbackWrapper.java:47:onPlaybackStateChanged()] oooooo This callback is from foo.bar
  ? D/MusicController: [MediaSessionMonitor.java:123:handleMessage()] oooooo MediaSessionMonitor.MsgHandler msg = 2
  ? D/MusicController: [MediaSessionMonitor.java:205:checkAndUpdateMusicController()] oooooo state = 3, action = 585
  ? I/MusicController: [MediaSessionMonitor.java:234:isValidStateToRegister()] oooooo isValidStateToRegister = true
  ? I/MusicController: [MediaSessionMonitor.java:257:isValidMetadataToRegister()] oooooo isValidMetadataToRegister = true
  ? I/MusicController: [MediaSessionMonitor.java:245:isValidActionToRegister()] oooooo isValidActionToRegister = false
  ? I/MusicController: [MediaSessionMonitor.java:222:checkAndUpdateMusicController()] oooooo is MusicController Updated = false
  ? D/MusicController: [MediaSessionMonitor.java:123:handleMessage()] oooooo MediaSessionMonitor.MsgHandler msg = 1
  ? D/MusicController: [MediaSessionMonitor.java:205:checkAndUpdateMusicController()] oooooo state = 3, action = 585
  ? I/MusicController: [MediaSessionMonitor.java:234:isValidStateToRegister()] oooooo isValidStateToRegister = true
  ? I/MusicController: [MediaSessionMonitor.java:257:isValidMetadataToRegister()] oooooo isValidMetadataToRegister = true
  ? I/MusicController: [MediaSessionMonitor.java:245:isValidActionToRegister()] oooooo isValidActionToRegister = false
  ? I/MusicController: [MediaSessionMonitor.java:222:checkAndUpdateMusicController()] oooooo is MusicController Updated = false
  ? I/MusicController: [MediaControllerCallbackWrapper.java:47:onPlaybackStateChanged()] oooooo This callback is from foo.bar
  ? D/MusicController: [MediaSessionMonitor.java:123:handleMessage()] oooooo MediaSessionMonitor.MsgHandler msg = 1
  ? D/MusicController: [MediaSessionMonitor.java:205:checkAndUpdateMusicController()] oooooo state = 3, action = 585
  ? I/MusicController: [MediaSessionMonitor.java:234:isValidStateToRegister()] oooooo isValidStateToRegister = true
  ? I/MusicController: [MediaSessionMonitor.java:257:isValidMetadataToRegister()] oooooo isValidMetadataToRegister = true
  ? I/MusicController: [MediaSessionMonitor.java:245:isValidActionToRegister()] oooooo isValidActionToRegister = false
  ? I/MusicController: [MediaSessionMonitor.java:222:checkAndUpdateMusicController()] oooooo is MusicController Updated = false
  ? V/MediaRouter: Adding route: RouteInfo{ name=Phone, description=null, status=null, category=RouteCategory{ name=System types=ROUTE_TYPE_LIVE_AUDIO ROUTE_TYPE_LIVE_VIDEO  groupable=false }, supportedTypes=ROUTE_TYPE_LIVE_AUDIO ROUTE_TYPE_LIVE_VIDEO , presentationDisplay=null }
  ? V/MediaRouter: Adding route: RouteInfo{ name=DummyDevice, description=Bluetooth audio, status=null, category=RouteCategory{ name=System types=ROUTE_TYPE_LIVE_AUDIO ROUTE_TYPE_LIVE_VIDEO  groupable=false }, supportedTypes=ROUTE_TYPE_LIVE_AUDIO , presentationDisplay=null }
  ? V/MediaRouter: Selecting route: RouteInfo{ name=DummyDevice, description=Bluetooth audio, status=null, category=RouteCategory{ name=System types=ROUTE_TYPE_LIVE_AUDIO ROUTE_TYPE_LIVE_VIDEO  groupable=false }, supportedTypes=ROUTE_TYPE_LIVE_AUDIO , presentationDisplay=null }
  ? V/MediaRouter: Audio routes updated: AudioRoutesInfo{ type=SPEAKER, bluetoothName=DummyDevice }, a2dp=true
  ? W/MediaSessionCompat: Couldn't find a unique registered media button receiver in the given context.
  ? I/MusicController: [MediaSessionMonitor.java:153:onActiveSessionsChanged()] oooooo 
  ? I/MusicController: [MediaSessionMonitor.java:174:updateMediaControllers()] oooooo List size :1
  ? I/MusicController: [MediaSessionMonitor.java:178:updateMediaControllers()] oooooo MediaController received packageName foo.bar
  ? D/MusicController: [MediaSessionMonitor.java:76:addToMediaContorllersMap()] oooooo Already exist = android.media.session.MediaSession$Token@986e7dd
  ? I/MusicController: [MediaSessionMonitor.java:78:addToMediaContorllersMap()] oooooo mMediaContorllersMap.size() = 1
  ? D/MusicController: [MediaSessionMonitor.java:205:checkAndUpdateMusicController()] oooooo state = 3, action = 585
  ? I/MusicController: [MediaSessionMonitor.java:234:isValidStateToRegister()] oooooo isValidStateToRegister = true
  ? I/MusicController: [MediaSessionMonitor.java:257:isValidMetadataToRegister()] oooooo isValidMetadataToRegister = true
  ? I/MusicController: [MediaSessionMonitor.java:245:isValidActionToRegister()] oooooo isValidActionToRegister = false
  ? I/MusicController: [MediaSessionMonitor.java:222:checkAndUpdateMusicController()] oooooo is MusicController Updated = false
  ? I/MusicController: [MediaSessionMonitor.java:182:updateMediaControllers()] oooooo mMediaContorllersMap size = 1
  ? V/MediaRouter: Selecting route: RouteInfo{ name=DummyDevice, description=Bluetooth audio, status=null, category=RouteCategory{ name=System types=ROUTE_TYPE_LIVE_AUDIO ROUTE_TYPE_LIVE_VIDEO  groupable=false }, supportedTypes=ROUTE_TYPE_LIVE_AUDIO , presentationDisplay=null }
  ? V/MediaRouter: Adding route: RouteInfo{ name=Phone, description=null, status=null, category=RouteCategory{ name=System types=ROUTE_TYPE_LIVE_AUDIO ROUTE_TYPE_LIVE_VIDEO  groupable=false }, supportedTypes=ROUTE_TYPE_LIVE_AUDIO ROUTE_TYPE_LIVE_VIDEO , presentationDisplay=null }
  ? V/MediaRouter: Adding route: RouteInfo{ name=DummyDevice, description=Bluetooth audio, status=null, category=RouteCategory{ name=System types=ROUTE_TYPE_LIVE_AUDIO ROUTE_TYPE_LIVE_VIDEO  groupable=false }, supportedTypes=ROUTE_TYPE_LIVE_AUDIO , presentationDisplay=null }
  ? V/MediaRouter: Selecting route: RouteInfo{ name=DummyDevice, description=Bluetooth audio, status=null, category=RouteCategory{ name=System types=ROUTE_TYPE_LIVE_AUDIO ROUTE_TYPE_LIVE_VIDEO  groupable=false }, supportedTypes=ROUTE_TYPE_LIVE_AUDIO , presentationDisplay=null }
  ? V/MediaRouter: Audio routes updated: AudioRoutesInfo{ type=SPEAKER, bluetoothName=DummyDevice }, a2dp=true
  ? V/MediaRouter: Selecting route: RouteInfo{ name=DummyDevice, description=Bluetooth audio, status=null, category=RouteCategory{ name=System types=ROUTE_TYPE_LIVE_AUDIO ROUTE_TYPE_LIVE_VIDEO  groupable=false }, supportedTypes=ROUTE_TYPE_LIVE_AUDIO , presentationDisplay=null }
  </code></pre>
  
  <p>Also I'm seeing an audio permission error but I'm not sure if this is related:</p>
  
  <pre><code>W/MediaListnrAuthObsrvr: registration failed - not an approved notification listener yet?
      java.lang.SecurityException: Missing permission to control media.
          at android.os.Parcel.readException(Parcel.java:1951)
          at android.os.Parcel.readException(Parcel.java:1897)
          at android.media.session.ISessionManager$Stub$Proxy.addSessionsListener(ISessionManager.java:342)
          at android.media.session.MediaSessionManager.addOnActiveSessionsChangedListener(MediaSessionManager.java:226)
          at android.media.session.MediaSessionManager.addOnActiveSessionsChangedListener(MediaSessionManager.java:189)
          at com.google.android.clockwork.common.media.DefaultMediaSessionManagerWrapper.addOnActiveSessionsChangedListener(AW771527612:8)
          at com.google.android.clockwork.companion.mediacontrols.api21.MediaSessionListenerAuthorizationObserver.register(AW771527612:12)
          at com.google.android.clockwork.companion.mediacontrols.api21.MediaSessionListenerAuthorizationObserver.&lt;init&gt;(AW771527612:5)
          at com.google.android.clockwork.companion.mediacontrols.api21.MediaRemoteControllerApi21.start(AW771527612:13)
  </code></pre>