@Override
 public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid, Bundle rootHints) {
   LogHelper.d(
       TAG,
       "OnGetRoot: clientPackageName=" + clientPackageName,
       "; clientUid=" + clientUid + " ; rootHints=",
       rootHints);
   // To ensure you are not allowing any arbitrary app to browse your app's contents, you
   // need to check the origin:
   if (!mPackageValidator.isCallerAllowed(this, clientPackageName, clientUid)) {
     // If the request comes from an untrusted package, return null. No further calls will
     // be made to other media browsing methods.
     LogHelper.w(TAG, "OnGetRoot: IGNORING request from untrusted package " + clientPackageName);
     return null;
   }
   //noinspection StatementWithEmptyBody
   if (CarHelper.isValidCarPackage(clientPackageName)) {
     // Optional: if your app needs to adapt the music library to show a different subset
     // when connected to the car, this is where you should handle it.
     // If you want to adapt other runtime behaviors, like tweak ads or change some behavior
     // that should be different on cars, you should instead use the boolean flag
     // set by the BroadcastReceiver mCarConnectionReceiver (mIsConnectedToCar).
   }
   //noinspection StatementWithEmptyBody
   if (WearHelper.isValidWearCompanionPackage(clientPackageName)) {
     // Optional: if your app needs to adapt the music library for when browsing from a
     // Wear device, you should return a different MEDIA ROOT here, and then,
     // on onLoadChildren, handle it accordingly.
   }
   return new BrowserRoot(MEDIA_ID_ROOT, null);
 }
  /*
   * (non-Javadoc)
   * @see android.app.Service#onCreate()
   */
  @Override
  public void onCreate() {
    super.onCreate();
    LogHelper.d(TAG, "onCreate");

    mPlayingQueue = new ArrayList<>();
    mMusicProvider = new MusicProvider();
    mPackageValidator = new PackageValidator(this);

    // Start a new MediaSession
    mSession = new MediaSession(this, "MusicService");
    setSessionToken(mSession.getSessionToken());
    mSession.setCallback(new MediaSessionCallback());
    mSession.setFlags(
        MediaSession.FLAG_HANDLES_MEDIA_BUTTONS | MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);

    mPlayback = new LocalPlayback(this, mMusicProvider);
    mPlayback.setState(PlaybackState.STATE_NONE);
    mPlayback.setCallback(this);
    mPlayback.start();

    Context context = getApplicationContext();
    Intent intent = new Intent(context, NowPlayingActivity.class);
    PendingIntent pi =
        PendingIntent.getActivity(
            context, 99 /*request code*/, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    mSession.setSessionActivity(pi);

    mSessionExtras = new Bundle();
    CarHelper.setSlotReservationFlags(mSessionExtras, true, true, true);
    mSession.setExtras(mSessionExtras);

    updatePlaybackState(null);

    mMediaNotificationManager = new MediaNotificationManager(this);
    mCastManager = ((UAMPApplication) getApplication()).getCastManager(getApplicationContext());

    mCastManager.addVideoCastConsumer(mCastConsumer);
    mMediaRouter = MediaRouter.getInstance(getApplicationContext());
  }
 @Override
 public BrowserRoot onGetRoot(String clientPackageName, int clientUid, Bundle rootHints) {
   LogHelper.d(
       TAG,
       "OnGetRoot: clientPackageName=" + clientPackageName,
       "; clientUid=" + clientUid + " ; rootHints=",
       rootHints);
   // To ensure you are not allowing any arbitrary app to browse your app's contents, you
   // need to check the origin:
   if (!mPackageValidator.isCallerAllowed(this, clientPackageName, clientUid)) {
     // If the request comes from an untrusted package, return null. No further calls will
     // be made to other media browsing methods.
     LogHelper.w(TAG, "OnGetRoot: IGNORING request from untrusted package " + clientPackageName);
     return null;
   }
   //noinspection StatementWithEmptyBody
   if (CarHelper.isValidCarPackage(clientPackageName)) {
     // Optional: if your app needs to adapt ads, music library or anything else that
     // needs to run differently when connected to the car, this is where you should handle
     // it.
   }
   return new BrowserRoot(MEDIA_ID_ROOT, null);
 }
  /*
   * (non-Javadoc)
   * @see android.app.Service#onCreate()
   */
  @Override
  public void onCreate() {
    super.onCreate();
    LogHelper.d(TAG, "onCreate");

    mPlayingQueue = new ArrayList<>();
    mMusicProvider = new MusicProvider();
    mPackageValidator = new PackageValidator(this);

    ComponentName mediaButtonReceiver = new ComponentName(this, RemoteControlReceiver.class);

    Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
    mediaButtonIntent.setComponent(mediaButtonReceiver);
    PendingIntent mediaPendingIntent = PendingIntent.getBroadcast(this, 0, mediaButtonIntent, 0);

    // Start a new MediaSessionCompat
    mSession =
        new MediaSessionCompat(this, "MusicService", mediaButtonReceiver, mediaPendingIntent);

    /*
    final MediaSessionCallback cb = new MediaSessionCallback();

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        // Shouldn't really have to do this but the MediaSessionCompat method uses
        // an internal proxy class, which doesn't forward events such as
        // onPlayFromMediaId when running on Lollipop.
        final MediaSession session = (MediaSession) mSession.getMediaSession();
        session.setCallback(new MediaSessionCallbackProxy(cb));
    } else {
        mSession.setCallback(cb);
    }
    */

    setSessionToken(mSession.getSessionToken());
    mSession.setCallback(new MediaSessionCallback());
    mSession.setFlags(
        MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS
            | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);

    mPlayback = new LocalPlayback(this, mMusicProvider);
    mPlayback.setState(PlaybackStateCompat.STATE_NONE);
    mPlayback.setCallback(this);
    mPlayback.start();

    Context context = getApplicationContext();
    Intent intent = new Intent(context, NowPlayingActivity.class);
    PendingIntent pi =
        PendingIntent.getActivity(
            context, 99 /*request code*/, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    mSession.setSessionActivity(pi);

    mSessionExtras = new Bundle();
    CarHelper.setSlotReservationFlags(mSessionExtras, true, true, true);
    WearHelper.setSlotReservationFlags(mSessionExtras, true, true);
    WearHelper.setUseBackgroundFromTheme(mSessionExtras, true);
    mSession.setExtras(mSessionExtras);

    updatePlaybackState(null);

    mMediaNotificationManager = new MediaNotificationManager(this);
    mCastManager = VideoCastManager.getInstance();
    mCastManager.addVideoCastConsumer(mCastConsumer);
    mMediaRouter = MediaRouter.getInstance(getApplicationContext());

    IntentFilter filter = new IntentFilter(CarHelper.ACTION_MEDIA_STATUS);
    mCarConnectionReceiver =
        new BroadcastReceiver() {
          @Override
          public void onReceive(Context context, Intent intent) {
            String connectionEvent = intent.getStringExtra(CarHelper.MEDIA_CONNECTION_STATUS);
            mIsConnectedToCar = CarHelper.MEDIA_CONNECTED.equals(connectionEvent);
            LogHelper.i(
                TAG,
                "Connection event to Android Auto: ",
                connectionEvent,
                " isConnectedToCar=",
                mIsConnectedToCar);
          }
        };
    registerReceiver(mCarConnectionReceiver, filter);
  }