Merge "Differentiate MediaController in a process for MediaSession" into pi-dev am: 43688e8f2f
am: a31254bde1

Change-Id: I6b10eb78bf428cd93977d3075ae7a200b53bf92c
diff --git a/cmds/media/src/com/android/commands/media/Media.java b/cmds/media/src/com/android/commands/media/Media.java
index 2fc5808..c6d2bc8 100644
--- a/cmds/media/src/com/android/commands/media/Media.java
+++ b/cmds/media/src/com/android/commands/media/Media.java
@@ -171,7 +171,6 @@
             showError("Error: unknown dispatch code '" + cmd + "'");
             return;
         }
-
         final long now = SystemClock.uptimeMillis();
         sendMediaKey(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keycode, 0, 0,
                 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD));
@@ -189,7 +188,6 @@
         @Override
         public void onSessionDestroyed() {
             System.out.println("onSessionDestroyed. Enter q to quit.");
-
         }
 
         @Override
@@ -246,7 +244,7 @@
                 @Override
                 protected void onLooperPrepared() {
                     try {
-                        mController.registerCallbackListener(ControllerMonitor.this);
+                        mController.registerCallbackListener(PACKAGE_NAME, ControllerMonitor.this);
                     } catch (RemoteException e) {
                         System.out.println("Error registering monitor callback");
                     }
@@ -266,13 +264,13 @@
                     } else if ("q".equals(line) || "quit".equals(line)) {
                         break;
                     } else if ("play".equals(line)) {
-                        mController.play(PACKAGE_NAME);
+                        dispatchKeyCode(KeyEvent.KEYCODE_MEDIA_PLAY);
                     } else if ("pause".equals(line)) {
-                        mController.pause(PACKAGE_NAME);
+                        dispatchKeyCode(KeyEvent.KEYCODE_MEDIA_PAUSE);
                     } else if ("next".equals(line)) {
-                        mController.next(PACKAGE_NAME);
+                        dispatchKeyCode(KeyEvent.KEYCODE_MEDIA_NEXT);
                     } else if ("previous".equals(line)) {
-                        mController.previous(PACKAGE_NAME);
+                        dispatchKeyCode(KeyEvent.KEYCODE_MEDIA_PREVIOUS);
                     } else {
                         System.out.println("Invalid command: " + line);
                     }
@@ -295,6 +293,20 @@
                 }
             }
         }
+
+        private void dispatchKeyCode(int keyCode) {
+            final long now = SystemClock.uptimeMillis();
+            KeyEvent down = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0, 0,
+                    KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD);
+            KeyEvent up = new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, 0, 0,
+                    KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD);
+            try {
+                mController.sendMediaButton(PACKAGE_NAME, null, false, down);
+                mController.sendMediaButton(PACKAGE_NAME, null, false, up);
+            } catch (RemoteException e) {
+                System.out.println("Failed to dispatch " + keyCode);
+            }
+        }
     }
 
     private void runListSessions() {
diff --git a/media/java/android/media/session/ISessionCallback.aidl b/media/java/android/media/session/ISessionCallback.aidl
index 9634c7f..626338d 100644
--- a/media/java/android/media/session/ISessionCallback.aidl
+++ b/media/java/android/media/session/ISessionCallback.aidl
@@ -17,6 +17,7 @@
 
 import android.content.Intent;
 import android.media.Rating;
+import android.media.session.ISessionControllerCallback;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.ResultReceiver;
@@ -25,33 +26,46 @@
  * @hide
  */
 oneway interface ISessionCallback {
-    void onCommand(String packageName, int pid, int uid, String command, in Bundle args,
-            in ResultReceiver cb);
+    void onCommand(String packageName, int pid, int uid, ISessionControllerCallback caller,
+            String command, in Bundle args, in ResultReceiver cb);
     void onMediaButton(String packageName, int pid, int uid, in Intent mediaButtonIntent,
             int sequenceNumber, in ResultReceiver cb);
+    void onMediaButtonFromController(String packageName, int pid, int uid,
+            ISessionControllerCallback caller, in Intent mediaButtonIntent);
 
     // These callbacks are for the TransportPerformer
-    void onPrepare(String packageName, int pid, int uid);
-    void onPrepareFromMediaId(String packageName, int pid, int uid, String mediaId,
-            in Bundle extras);
-    void onPrepareFromSearch(String packageName, int pid, int uid, String query, in Bundle extras);
-    void onPrepareFromUri(String packageName, int pid, int uid, in Uri uri, in Bundle extras);
-    void onPlay(String packageName, int pid, int uid);
-    void onPlayFromMediaId(String packageName, int pid, int uid, String mediaId, in Bundle extras);
-    void onPlayFromSearch(String packageName, int pid, int uid, String query, in Bundle extras);
-    void onPlayFromUri(String packageName, int pid, int uid, in Uri uri, in Bundle extras);
-    void onSkipToTrack(String packageName, int pid, int uid, long id);
-    void onPause(String packageName, int pid, int uid);
-    void onStop(String packageName, int pid, int uid);
-    void onNext(String packageName, int pid, int uid);
-    void onPrevious(String packageName, int pid, int uid);
-    void onFastForward(String packageName, int pid, int uid);
-    void onRewind(String packageName, int pid, int uid);
-    void onSeekTo(String packageName, int pid, int uid, long pos);
-    void onRate(String packageName, int pid, int uid, in Rating rating);
-    void onCustomAction(String packageName, int pid, int uid, String action, in Bundle args);
+    void onPrepare(String packageName, int pid, int uid, ISessionControllerCallback caller);
+    void onPrepareFromMediaId(String packageName, int pid, int uid,
+            ISessionControllerCallback caller, String mediaId, in Bundle extras);
+    void onPrepareFromSearch(String packageName, int pid, int uid,
+            ISessionControllerCallback caller, String query, in Bundle extras);
+    void onPrepareFromUri(String packageName, int pid, int uid, ISessionControllerCallback caller,
+            in Uri uri, in Bundle extras);
+    void onPlay(String packageName, int pid, int uid, ISessionControllerCallback caller);
+    void onPlayFromMediaId(String packageName, int pid, int uid, ISessionControllerCallback caller,
+            String mediaId, in Bundle extras);
+    void onPlayFromSearch(String packageName, int pid, int uid, ISessionControllerCallback caller,
+            String query, in Bundle extras);
+    void onPlayFromUri(String packageName, int pid, int uid, ISessionControllerCallback caller,
+            in Uri uri, in Bundle extras);
+    void onSkipToTrack(String packageName, int pid, int uid, ISessionControllerCallback caller,
+            long id);
+    void onPause(String packageName, int pid, int uid, ISessionControllerCallback caller);
+    void onStop(String packageName, int pid, int uid, ISessionControllerCallback caller);
+    void onNext(String packageName, int pid, int uid, ISessionControllerCallback caller);
+    void onPrevious(String packageName, int pid, int uid, ISessionControllerCallback caller);
+    void onFastForward(String packageName, int pid, int uid, ISessionControllerCallback caller);
+    void onRewind(String packageName, int pid, int uid, ISessionControllerCallback caller);
+    void onSeekTo(String packageName, int pid, int uid, ISessionControllerCallback caller,
+            long pos);
+    void onRate(String packageName, int pid, int uid, ISessionControllerCallback caller,
+            in Rating rating);
+    void onCustomAction(String packageName, int pid, int uid, ISessionControllerCallback caller,
+            String action, in Bundle args);
 
     // These callbacks are for volume handling
-    void onAdjustVolume(String packageName, int pid, int uid, int direction);
-    void onSetVolumeTo(String packageName, int pid, int uid, int value);
+    void onAdjustVolume(String packageName, int pid, int uid, ISessionControllerCallback caller,
+            int direction);
+    void onSetVolumeTo(String packageName, int pid, int uid,
+            ISessionControllerCallback caller, int value);
 }
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index b4f52f9..861a8ce 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -32,42 +32,53 @@
 import java.util.List;
 
 /**
- * Interface to a MediaSession in the system.
+ * Interface to MediaSessionRecord in the system.
  * @hide
  */
 interface ISessionController {
-    void sendCommand(String packageName, String command, in Bundle args, in ResultReceiver cb);
-    boolean sendMediaButton(String packageName, boolean asSystemService, in KeyEvent mediaButton);
-    void registerCallbackListener(in ISessionControllerCallback cb);
-    void unregisterCallbackListener(in ISessionControllerCallback cb);
+    void sendCommand(String packageName, ISessionControllerCallback caller,
+            String command, in Bundle args, in ResultReceiver cb);
+    boolean sendMediaButton(String packageName, ISessionControllerCallback caller,
+            boolean asSystemService, in KeyEvent mediaButton);
+    void registerCallbackListener(String packageName, ISessionControllerCallback cb);
+    void unregisterCallbackListener(ISessionControllerCallback cb);
     boolean isTransportControlEnabled();
     String getPackageName();
     String getTag();
     PendingIntent getLaunchPendingIntent();
     long getFlags();
     ParcelableVolumeInfo getVolumeAttributes();
-    void adjustVolume(String packageName, boolean asSystemService, int direction, int flags);
-    void setVolumeTo(String packageName, int value, int flags);
+    void adjustVolume(String packageName, ISessionControllerCallback caller,
+            boolean asSystemService, int direction, int flags);
+    void setVolumeTo(String packageName, ISessionControllerCallback caller,
+            int value, int flags);
 
     // These commands are for the TransportControls
-    void prepare(String packageName);
-    void prepareFromMediaId(String packageName, String mediaId, in Bundle extras);
-    void prepareFromSearch(String packageName, String string, in Bundle extras);
-    void prepareFromUri(String packageName, in Uri uri, in Bundle extras);
-    void play(String packageName);
-    void playFromMediaId(String packageName, String mediaId, in Bundle extras);
-    void playFromSearch(String packageName, String string, in Bundle extras);
-    void playFromUri(String packageName, in Uri uri, in Bundle extras);
-    void skipToQueueItem(String packageName, long id);
-    void pause(String packageName);
-    void stop(String packageName);
-    void next(String packageName);
-    void previous(String packageName);
-    void fastForward(String packageName);
-    void rewind(String packageName);
-    void seekTo(String packageName, long pos);
-    void rate(String packageName, in Rating rating);
-    void sendCustomAction(String packageName, String action, in Bundle args);
+    void prepare(String packageName, ISessionControllerCallback caller);
+    void prepareFromMediaId(String packageName, ISessionControllerCallback caller,
+            String mediaId, in Bundle extras);
+    void prepareFromSearch(String packageName, ISessionControllerCallback caller,
+            String string, in Bundle extras);
+    void prepareFromUri(String packageName, ISessionControllerCallback caller,
+            in Uri uri, in Bundle extras);
+    void play(String packageName, ISessionControllerCallback caller);
+    void playFromMediaId(String packageName, ISessionControllerCallback caller,
+            String mediaId, in Bundle extras);
+    void playFromSearch(String packageName, ISessionControllerCallback caller,
+            String string, in Bundle extras);
+    void playFromUri(String packageName, ISessionControllerCallback caller,
+            in Uri uri, in Bundle extras);
+    void skipToQueueItem(String packageName, ISessionControllerCallback caller, long id);
+    void pause(String packageName, ISessionControllerCallback caller);
+    void stop(String packageName, ISessionControllerCallback caller);
+    void next(String packageName, ISessionControllerCallback caller);
+    void previous(String packageName, ISessionControllerCallback caller);
+    void fastForward(String packageName, ISessionControllerCallback caller);
+    void rewind(String packageName, ISessionControllerCallback caller);
+    void seekTo(String packageName, ISessionControllerCallback caller, long pos);
+    void rate(String packageName, ISessionControllerCallback caller, in Rating rating);
+    void sendCustomAction(String packageName, ISessionControllerCallback caller,
+            String action, in Bundle args);
     MediaMetadata getMetadata();
     PlaybackState getPlaybackState();
     ParceledListSlice getQueue();
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 8c34a31..de22fa3 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -126,7 +126,7 @@
      * @return true if the event was sent to the session, false otherwise.
      */
     public boolean dispatchMediaButtonEvent(@NonNull KeyEvent keyEvent) {
-        return dispatchMediButtonEventInternal(false, keyEvent);
+        return dispatchMediaButtonEventInternal(false, keyEvent);
     }
 
     /**
@@ -142,10 +142,10 @@
      * @hide
      */
     public boolean dispatchMediaButtonEventAsSystemService(@NonNull KeyEvent keyEvent) {
-        return dispatchMediButtonEventInternal(true, keyEvent);
+        return dispatchMediaButtonEventInternal(true, keyEvent);
     }
 
-    private boolean dispatchMediButtonEventInternal(boolean asSystemService,
+    private boolean dispatchMediaButtonEventInternal(boolean asSystemService,
             @NonNull KeyEvent keyEvent) {
         if (keyEvent == null) {
             throw new IllegalArgumentException("KeyEvent may not be null");
@@ -154,8 +154,8 @@
             return false;
         }
         try {
-            return mSessionBinder.sendMediaButton(mContext.getPackageName(), asSystemService,
-                    keyEvent);
+            return mSessionBinder.sendMediaButton(mContext.getPackageName(), mCbStub,
+                    asSystemService, keyEvent);
         } catch (RemoteException e) {
             // System is dead. =(
         }
@@ -189,7 +189,7 @@
                         break;
                 }
                 try {
-                    mSessionBinder.adjustVolume(mContext.getPackageName(), true, direction,
+                    mSessionBinder.adjustVolume(mContext.getPackageName(), mCbStub, true, direction,
                             AudioManager.FLAG_SHOW_UI);
                 } catch (RemoteException e) {
                     Log.wtf(TAG, "Error calling adjustVolumeBy", e);
@@ -200,7 +200,7 @@
                 final int flags = AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE
                         | AudioManager.FLAG_FROM_KEY;
                 try {
-                    mSessionBinder.adjustVolume(mContext.getPackageName(), true, 0, flags);
+                    mSessionBinder.adjustVolume(mContext.getPackageName(), mCbStub, true, 0, flags);
                 } catch (RemoteException e) {
                     Log.wtf(TAG, "Error calling adjustVolumeBy", e);
                 }
@@ -369,7 +369,7 @@
      */
     public void setVolumeTo(int value, int flags) {
         try {
-            mSessionBinder.setVolumeTo(mContext.getPackageName(), value, flags);
+            mSessionBinder.setVolumeTo(mContext.getPackageName(), mCbStub, value, flags);
         } catch (RemoteException e) {
             Log.wtf(TAG, "Error calling setVolumeTo.", e);
         }
@@ -390,7 +390,8 @@
      */
     public void adjustVolume(int direction, int flags) {
         try {
-            mSessionBinder.adjustVolume(mContext.getPackageName(), false, direction, flags);
+            mSessionBinder.adjustVolume(mContext.getPackageName(), mCbStub, false, direction,
+                    flags);
         } catch (RemoteException e) {
             Log.wtf(TAG, "Error calling adjustVolumeBy.", e);
         }
@@ -456,7 +457,7 @@
             throw new IllegalArgumentException("command cannot be null or empty");
         }
         try {
-            mSessionBinder.sendCommand(mContext.getPackageName(), command, args, cb);
+            mSessionBinder.sendCommand(mContext.getPackageName(), mCbStub, command, args, cb);
         } catch (RemoteException e) {
             Log.d(TAG, "Dead object in sendCommand.", e);
         }
@@ -521,7 +522,7 @@
 
         if (!mCbRegistered) {
             try {
-                mSessionBinder.registerCallbackListener(mCbStub);
+                mSessionBinder.registerCallbackListener(mContext.getPackageName(), mCbStub);
                 mCbRegistered = true;
             } catch (RemoteException e) {
                 Log.e(TAG, "Dead object in registerCallback", e);
@@ -668,7 +669,7 @@
          */
         public void prepare() {
             try {
-                mSessionBinder.prepare(mContext.getPackageName());
+                mSessionBinder.prepare(mContext.getPackageName(), mCbStub);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling prepare.", e);
             }
@@ -692,7 +693,8 @@
                         "You must specify a non-empty String for prepareFromMediaId.");
             }
             try {
-                mSessionBinder.prepareFromMediaId(mContext.getPackageName(), mediaId, extras);
+                mSessionBinder.prepareFromMediaId(mContext.getPackageName(), mCbStub, mediaId,
+                        extras);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling prepare(" + mediaId + ").", e);
             }
@@ -718,7 +720,7 @@
                 query = "";
             }
             try {
-                mSessionBinder.prepareFromSearch(mContext.getPackageName(), query, extras);
+                mSessionBinder.prepareFromSearch(mContext.getPackageName(), mCbStub, query, extras);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling prepare(" + query + ").", e);
             }
@@ -742,7 +744,7 @@
                         "You must specify a non-empty Uri for prepareFromUri.");
             }
             try {
-                mSessionBinder.prepareFromUri(mContext.getPackageName(), uri, extras);
+                mSessionBinder.prepareFromUri(mContext.getPackageName(), mCbStub, uri, extras);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling prepare(" + uri + ").", e);
             }
@@ -753,7 +755,7 @@
          */
         public void play() {
             try {
-                mSessionBinder.play(mContext.getPackageName());
+                mSessionBinder.play(mContext.getPackageName(), mCbStub);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling play.", e);
             }
@@ -772,7 +774,7 @@
                         "You must specify a non-empty String for playFromMediaId.");
             }
             try {
-                mSessionBinder.playFromMediaId(mContext.getPackageName(), mediaId, extras);
+                mSessionBinder.playFromMediaId(mContext.getPackageName(), mCbStub, mediaId, extras);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling play(" + mediaId + ").", e);
             }
@@ -794,7 +796,7 @@
                 query = "";
             }
             try {
-                mSessionBinder.playFromSearch(mContext.getPackageName(), query, extras);
+                mSessionBinder.playFromSearch(mContext.getPackageName(), mCbStub, query, extras);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling play(" + query + ").", e);
             }
@@ -813,7 +815,7 @@
                         "You must specify a non-empty Uri for playFromUri.");
             }
             try {
-                mSessionBinder.playFromUri(mContext.getPackageName(), uri, extras);
+                mSessionBinder.playFromUri(mContext.getPackageName(), mCbStub, uri, extras);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling play(" + uri + ").", e);
             }
@@ -825,7 +827,7 @@
          */
         public void skipToQueueItem(long id) {
             try {
-                mSessionBinder.skipToQueueItem(mContext.getPackageName(), id);
+                mSessionBinder.skipToQueueItem(mContext.getPackageName(), mCbStub, id);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling skipToItem(" + id + ").", e);
             }
@@ -837,7 +839,7 @@
          */
         public void pause() {
             try {
-                mSessionBinder.pause(mContext.getPackageName());
+                mSessionBinder.pause(mContext.getPackageName(), mCbStub);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling pause.", e);
             }
@@ -849,7 +851,7 @@
          */
         public void stop() {
             try {
-                mSessionBinder.stop(mContext.getPackageName());
+                mSessionBinder.stop(mContext.getPackageName(), mCbStub);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling stop.", e);
             }
@@ -862,7 +864,7 @@
          */
         public void seekTo(long pos) {
             try {
-                mSessionBinder.seekTo(mContext.getPackageName(), pos);
+                mSessionBinder.seekTo(mContext.getPackageName(), mCbStub, pos);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling seekTo.", e);
             }
@@ -874,7 +876,7 @@
          */
         public void fastForward() {
             try {
-                mSessionBinder.fastForward(mContext.getPackageName());
+                mSessionBinder.fastForward(mContext.getPackageName(), mCbStub);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling fastForward.", e);
             }
@@ -885,7 +887,7 @@
          */
         public void skipToNext() {
             try {
-                mSessionBinder.next(mContext.getPackageName());
+                mSessionBinder.next(mContext.getPackageName(), mCbStub);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling next.", e);
             }
@@ -897,7 +899,7 @@
          */
         public void rewind() {
             try {
-                mSessionBinder.rewind(mContext.getPackageName());
+                mSessionBinder.rewind(mContext.getPackageName(), mCbStub);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling rewind.", e);
             }
@@ -908,7 +910,7 @@
          */
         public void skipToPrevious() {
             try {
-                mSessionBinder.previous(mContext.getPackageName());
+                mSessionBinder.previous(mContext.getPackageName(), mCbStub);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling previous.", e);
             }
@@ -923,7 +925,7 @@
          */
         public void setRating(Rating rating) {
             try {
-                mSessionBinder.rate(mContext.getPackageName(), rating);
+                mSessionBinder.rate(mContext.getPackageName(), mCbStub, rating);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling rate.", e);
             }
@@ -937,7 +939,7 @@
          *             custom action.
          */
         public void sendCustomAction(@NonNull PlaybackState.CustomAction customAction,
-                    @Nullable Bundle args) {
+                @Nullable Bundle args) {
             if (customAction == null) {
                 throw new IllegalArgumentException("CustomAction cannot be null.");
             }
@@ -958,7 +960,7 @@
                 throw new IllegalArgumentException("CustomAction cannot be null.");
             }
             try {
-                mSessionBinder.sendCustomAction(mContext.getPackageName(), action, args);
+                mSessionBinder.sendCustomAction(mContext.getPackageName(), mCbStub, action, args);
             } catch (RemoteException e) {
                 Log.d(TAG, "Dead object in sendCustomAction.", e);
             }
@@ -1124,8 +1126,8 @@
         public void onVolumeInfoChanged(ParcelableVolumeInfo pvi) {
             MediaController controller = mController.get();
             if (controller != null) {
-                PlaybackInfo info = new PlaybackInfo(pvi.volumeType, pvi.audioAttrs, pvi.controlType,
-                        pvi.maxVolume, pvi.currentVolume);
+                PlaybackInfo info = new PlaybackInfo(pvi.volumeType, pvi.audioAttrs,
+                        pvi.controlType, pvi.maxVolume, pvi.currentVolume);
                 controller.postMessage(MSG_UPDATE_VOLUME, info, null);
             }
         }
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 6f4f20e..fad7e3f 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -43,6 +43,7 @@
 import android.service.media.MediaBrowserService;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.Pair;
 import android.view.KeyEvent;
 import android.view.ViewConfiguration;
 
@@ -122,15 +123,6 @@
             FLAG_EXCLUSIVE_GLOBAL_PRIORITY })
     public @interface SessionFlags { }
 
-    private static final String EXTRA_KEY_CALLING_PACKAGE =
-            "android.media.session.extra.CALLING_PACKAGE";
-    private static final String EXTRA_KEY_CALLING_PID =
-            "android.media.session.extra.CALLING_PID";
-    private static final String EXTRA_KEY_CALLING_UID =
-            "android.media.session.extra.CALLING_UID";
-    private static final String EXTRA_KEY_ORIGINAL_BUNDLE =
-            "android.media.session.extra.ORIGINAL_BUNDLE";
-
     private final Object mLock = new Object();
     private final int mMaxBitmapSize;
 
@@ -529,15 +521,11 @@
      * @see MediaSessionManager#isTrustedForMediaControl(RemoteUserInfo)
      */
     public final @NonNull RemoteUserInfo getCurrentControllerInfo() {
-        return createRemoteUserInfo(getCurrentData());
-    }
-
-    private @NonNull Bundle getCurrentData() {
-        if (mCallback == null || mCallback.mCurrentData == null) {
+        if (mCallback == null || mCallback.mCurrentControllerInfo == null) {
             throw new IllegalStateException(
                     "This should be called inside of MediaSession.Callback methods");
         }
-        return mCallback.mCurrentData;
+        return mCallback.mCurrentControllerInfo;
     }
 
     /**
@@ -568,161 +556,122 @@
      * @hide
      */
     public String getCallingPackage() {
-        if (mCallback != null) {
-            return createRemoteUserInfo(mCallback.mCurrentData).getPackageName();
+        if (mCallback != null && mCallback.mCurrentControllerInfo != null) {
+            return mCallback.mCurrentControllerInfo.getPackageName();
         }
         return null;
     }
 
-    private void dispatchPrepare(Bundle extras) {
-        postToCallback(CallbackMessageHandler.MSG_PREPARE, null, extras);
+    private void dispatchPrepare(RemoteUserInfo caller) {
+        postToCallback(caller, CallbackMessageHandler.MSG_PREPARE, null, null);
     }
 
-    private void dispatchPrepareFromMediaId(String mediaId, Bundle extras) {
-        postToCallback(CallbackMessageHandler.MSG_PREPARE_MEDIA_ID, mediaId, extras);
+    private void dispatchPrepareFromMediaId(RemoteUserInfo caller, String mediaId, Bundle extras) {
+        postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_MEDIA_ID, mediaId, extras);
     }
 
-    private void dispatchPrepareFromSearch(String query, Bundle extras) {
-        postToCallback(CallbackMessageHandler.MSG_PREPARE_SEARCH, query, extras);
+    private void dispatchPrepareFromSearch(RemoteUserInfo caller, String query, Bundle extras) {
+        postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_SEARCH, query, extras);
     }
 
-    private void dispatchPrepareFromUri(Uri uri, Bundle extras) {
-        postToCallback(CallbackMessageHandler.MSG_PREPARE_URI, uri, extras);
+    private void dispatchPrepareFromUri(RemoteUserInfo caller, Uri uri, Bundle extras) {
+        postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_URI, uri, extras);
     }
 
-    private void dispatchPlay(Bundle extras) {
-        postToCallback(CallbackMessageHandler.MSG_PLAY, null, extras);
+    private void dispatchPlay(RemoteUserInfo caller) {
+        postToCallback(caller, CallbackMessageHandler.MSG_PLAY, null, null);
     }
 
-    private void dispatchPlayFromMediaId(String mediaId, Bundle extras) {
-        postToCallback(CallbackMessageHandler.MSG_PLAY_MEDIA_ID, mediaId, extras);
+    private void dispatchPlayFromMediaId(RemoteUserInfo caller, String mediaId, Bundle extras) {
+        postToCallback(caller, CallbackMessageHandler.MSG_PLAY_MEDIA_ID, mediaId, extras);
     }
 
-    private void dispatchPlayFromSearch(String query, Bundle extras) {
-        postToCallback(CallbackMessageHandler.MSG_PLAY_SEARCH, query, extras);
+    private void dispatchPlayFromSearch(RemoteUserInfo caller, String query, Bundle extras) {
+        postToCallback(caller, CallbackMessageHandler.MSG_PLAY_SEARCH, query, extras);
     }
 
-    private void dispatchPlayFromUri(Uri uri, Bundle extras) {
-        postToCallback(CallbackMessageHandler.MSG_PLAY_URI, uri, extras);
+    private void dispatchPlayFromUri(RemoteUserInfo caller, Uri uri, Bundle extras) {
+        postToCallback(caller, CallbackMessageHandler.MSG_PLAY_URI, uri, extras);
     }
 
-    private void dispatchSkipToItem(long id, Bundle extras) {
-        postToCallback(CallbackMessageHandler.MSG_SKIP_TO_ITEM, id, extras);
+    private void dispatchSkipToItem(RemoteUserInfo caller, long id) {
+        postToCallback(caller, CallbackMessageHandler.MSG_SKIP_TO_ITEM, id, null);
     }
 
-    private void dispatchPause(Bundle extras) {
-        postToCallback(CallbackMessageHandler.MSG_PAUSE, null, extras);
+    private void dispatchPause(RemoteUserInfo caller) {
+        postToCallback(caller, CallbackMessageHandler.MSG_PAUSE, null, null);
     }
 
-    private void dispatchStop(Bundle extras) {
-        postToCallback(CallbackMessageHandler.MSG_STOP, null, extras);
+    private void dispatchStop(RemoteUserInfo caller) {
+        postToCallback(caller, CallbackMessageHandler.MSG_STOP, null, null);
     }
 
-    private void dispatchNext(Bundle extras) {
-        postToCallback(CallbackMessageHandler.MSG_NEXT, null, extras);
+    private void dispatchNext(RemoteUserInfo caller) {
+        postToCallback(caller, CallbackMessageHandler.MSG_NEXT, null, null);
     }
 
-    private void dispatchPrevious(Bundle extras) {
-        postToCallback(CallbackMessageHandler.MSG_PREVIOUS, null, extras);
+    private void dispatchPrevious(RemoteUserInfo caller) {
+        postToCallback(caller, CallbackMessageHandler.MSG_PREVIOUS, null, null);
     }
 
-    private void dispatchFastForward(Bundle extras) {
-        postToCallback(CallbackMessageHandler.MSG_FAST_FORWARD, null, extras);
+    private void dispatchFastForward(RemoteUserInfo caller) {
+        postToCallback(caller, CallbackMessageHandler.MSG_FAST_FORWARD, null, null);
     }
 
-    private void dispatchRewind(Bundle extras) {
-        postToCallback(CallbackMessageHandler.MSG_REWIND, null, extras);
+    private void dispatchRewind(RemoteUserInfo caller) {
+        postToCallback(caller, CallbackMessageHandler.MSG_REWIND, null, null);
     }
 
-    private void dispatchSeekTo(long pos, Bundle extras) {
-        postToCallback(CallbackMessageHandler.MSG_SEEK_TO, pos, extras);
+    private void dispatchSeekTo(RemoteUserInfo caller, long pos) {
+        postToCallback(caller, CallbackMessageHandler.MSG_SEEK_TO, pos, null);
     }
 
-    private void dispatchRate(Rating rating, Bundle extras) {
-        postToCallback(CallbackMessageHandler.MSG_RATE, rating, extras);
+    private void dispatchRate(RemoteUserInfo caller, Rating rating) {
+        postToCallback(caller, CallbackMessageHandler.MSG_RATE, rating, null);
     }
 
-    private void dispatchCustomAction(String action, Bundle extras) {
-        postToCallback(CallbackMessageHandler.MSG_CUSTOM_ACTION, action, extras);
+    private void dispatchCustomAction(RemoteUserInfo caller, String action, Bundle args) {
+        postToCallback(caller, CallbackMessageHandler.MSG_CUSTOM_ACTION, action, args);
     }
 
-    private void dispatchMediaButton(Intent mediaButtonIntent, Bundle extras) {
-        postToCallback(CallbackMessageHandler.MSG_MEDIA_BUTTON, mediaButtonIntent, extras);
+    private void dispatchMediaButton(RemoteUserInfo caller, Intent mediaButtonIntent) {
+        postToCallback(caller, CallbackMessageHandler.MSG_MEDIA_BUTTON, mediaButtonIntent, null);
     }
 
-    private void dispatchAdjustVolume(int direction, Bundle extras) {
-        postToCallback(CallbackMessageHandler.MSG_ADJUST_VOLUME, direction, extras);
+    private void dispatchMediaButtonDelayed(RemoteUserInfo info, Intent mediaButtonIntent,
+            long delay) {
+        postToCallbackDelayed(info, CallbackMessageHandler.MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT,
+                mediaButtonIntent, null, delay);
     }
 
-    private void dispatchSetVolumeTo(int volume, Bundle extras) {
-        postToCallback(CallbackMessageHandler.MSG_SET_VOLUME, volume, extras);
+    private void dispatchAdjustVolume(RemoteUserInfo caller, int direction) {
+        postToCallback(caller, CallbackMessageHandler.MSG_ADJUST_VOLUME, direction, null);
     }
 
-    private void postCommand(String command, Bundle args, ResultReceiver resultCb, Bundle extras) {
+    private void dispatchSetVolumeTo(RemoteUserInfo caller, int volume) {
+        postToCallback(caller, CallbackMessageHandler.MSG_SET_VOLUME, volume, null);
+    }
+
+    private void dispatchCommand(RemoteUserInfo caller, String command, Bundle args,
+            ResultReceiver resultCb) {
         Command cmd = new Command(command, args, resultCb);
-        postToCallback(CallbackMessageHandler.MSG_COMMAND, cmd, extras);
+        postToCallback(caller, CallbackMessageHandler.MSG_COMMAND, cmd, null);
     }
 
-    private void postToCallback(int what, Object obj, Bundle extras) {
+    private void postToCallback(RemoteUserInfo caller, int what, Object obj, Bundle data) {
+        postToCallbackDelayed(caller, what, obj, data, 0);
+    }
+
+    private void postToCallbackDelayed(RemoteUserInfo caller, int what, Object obj, Bundle data,
+            long delay) {
         synchronized (mLock) {
             if (mCallback != null) {
-                mCallback.post(what, obj, extras);
+                mCallback.post(caller, what, obj, data, delay);
             }
         }
     }
 
     /**
-     * Creates the extra bundle that includes the caller information.
-     *
-     * @return An extraBundle that contains caller information
-     */
-    private static Bundle createExtraBundle(String packageName, int pid, int uid) {
-        return createExtraBundle(packageName, pid, uid, null);
-    }
-
-    /**
-     * Creates the extra bundle that includes the caller information.
-     *
-     * @param originalBundle bundle
-     * @return An extraBundle that contains caller information
-     */
-    private static Bundle createExtraBundle(String packageName, int pid, int uid,
-            Bundle originalBundle) {
-        Bundle bundle = new Bundle();
-        bundle.putString(EXTRA_KEY_CALLING_PACKAGE, packageName);
-        bundle.putInt(EXTRA_KEY_CALLING_PID, pid);
-        bundle.putInt(EXTRA_KEY_CALLING_UID, uid);
-        if (originalBundle != null) {
-            bundle.putBundle(EXTRA_KEY_ORIGINAL_BUNDLE, originalBundle);
-        }
-        return bundle;
-    }
-
-    /**
-     * Creates the {@link RemoteUserInfo} from the extra bundle created by
-     * {@link #createExtraBundle}.
-     *
-     * @param extraBundle that previously created by createExtraBundle()
-     * @return a RemoteUserInfo
-     */
-    private static RemoteUserInfo createRemoteUserInfo(Bundle extraBundle) {
-        return new RemoteUserInfo(
-                extraBundle.getString(EXTRA_KEY_CALLING_PACKAGE),
-                extraBundle.getInt(EXTRA_KEY_CALLING_PID, INVALID_PID),
-                extraBundle.getInt(EXTRA_KEY_CALLING_UID, INVALID_UID));
-    }
-
-    /**
-     * Gets the original bundle from the extra bundle created by {@link #createExtraBundle}.
-     *
-     * @param extraBundle that previously created by createExtraBundle()
-     * @return a Bundle
-     */
-    private static Bundle getOriginalBundle(Bundle extraBundle) {
-        return extraBundle.getBundle(EXTRA_KEY_ORIGINAL_BUNDLE);
-    }
-
-    /**
      * Return true if this is considered an active playback state.
      *
      * @hide
@@ -872,10 +821,9 @@
                                 }
                             } else {
                                 mMediaPlayPauseKeyPending = true;
-                                mHandler.postDelayed(CallbackMessageHandler
-                                                .MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT,
-                                        mSession.getCurrentData(),
-                                        ViewConfiguration.getDoubleTapTimeout());
+                                mSession.dispatchMediaButtonDelayed(
+                                        mSession.getCurrentControllerInfo(),
+                                        mediaButtonIntent, ViewConfiguration.getDoubleTapTimeout());
                             }
                             return true;
                         default:
@@ -1109,12 +1057,19 @@
             mMediaSession = new WeakReference<>(session);
         }
 
+        private static RemoteUserInfo createRemoteUserInfo(String packageName, int pid, int uid,
+                ISessionControllerCallback caller) {
+            return new RemoteUserInfo(packageName, pid, uid,
+                    caller != null ? caller.asBinder() : null);
+        }
+
         @Override
-        public void onCommand(String packageName, int pid, int uid, String command, Bundle args,
-                ResultReceiver cb) {
+        public void onCommand(String packageName, int pid, int uid,
+                ISessionControllerCallback caller, String command, Bundle args, ResultReceiver cb) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.postCommand(command, args, cb, createExtraBundle(packageName, pid, uid));
+                session.dispatchCommand(createRemoteUserInfo(packageName, pid, uid, caller),
+                        command, args, cb);
             }
         }
 
@@ -1124,8 +1079,8 @@
             MediaSession session = mMediaSession.get();
             try {
                 if (session != null) {
-                    session.dispatchMediaButton(
-                            mediaButtonIntent, createExtraBundle(packageName, pid, uid));
+                    session.dispatchMediaButton(createRemoteUserInfo(packageName, pid, uid, null),
+                            mediaButtonIntent);
                 }
             } finally {
                 if (cb != null) {
@@ -1135,173 +1090,205 @@
         }
 
         @Override
-        public void onPrepare(String packageName, int pid, int uid) {
+        public void onMediaButtonFromController(String packageName, int pid, int uid,
+                ISessionControllerCallback caller, Intent mediaButtonIntent) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchPrepare(createExtraBundle(packageName, pid, uid));
+                session.dispatchMediaButton(createRemoteUserInfo(packageName, pid, uid, caller),
+                        mediaButtonIntent);
             }
         }
 
         @Override
-        public void onPrepareFromMediaId(String packageName, int pid, int uid, String mediaId,
+        public void onPrepare(String packageName, int pid, int uid,
+                ISessionControllerCallback caller) {
+            MediaSession session = mMediaSession.get();
+            if (session != null) {
+                session.dispatchPrepare(createRemoteUserInfo(packageName, pid, uid, caller));
+            }
+        }
+
+        @Override
+        public void onPrepareFromMediaId(String packageName, int pid, int uid,
+                ISessionControllerCallback caller, String mediaId,
                 Bundle extras) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
                 session.dispatchPrepareFromMediaId(
-                        mediaId, createExtraBundle(packageName, pid, uid, extras));
+                        createRemoteUserInfo(packageName, pid, uid, caller), mediaId, extras);
             }
         }
 
         @Override
-        public void onPrepareFromSearch(String packageName, int pid, int uid, String query,
+        public void onPrepareFromSearch(String packageName, int pid, int uid,
+                ISessionControllerCallback caller, String query,
                 Bundle extras) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
                 session.dispatchPrepareFromSearch(
-                        query, createExtraBundle(packageName, pid, uid, extras));
+                        createRemoteUserInfo(packageName, pid, uid, caller), query, extras);
             }
         }
 
         @Override
-        public void onPrepareFromUri(String packageName, int pid, int uid, Uri uri, Bundle extras) {
+        public void onPrepareFromUri(String packageName, int pid, int uid,
+                ISessionControllerCallback caller, Uri uri, Bundle extras) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchPrepareFromUri(uri,
-                        createExtraBundle(packageName, pid, uid, extras));
+                session.dispatchPrepareFromUri(createRemoteUserInfo(packageName, pid, uid, caller),
+                        uri, extras);
             }
         }
 
         @Override
-        public void onPlay(String packageName, int pid, int uid) {
+        public void onPlay(String packageName, int pid, int uid,
+                ISessionControllerCallback caller) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchPlay(createExtraBundle(packageName, pid, uid));
+                session.dispatchPlay(createRemoteUserInfo(packageName, pid, uid, caller));
             }
         }
 
         @Override
-        public void onPlayFromMediaId(String packageName, int pid, int uid, String mediaId,
+        public void onPlayFromMediaId(String packageName, int pid, int uid,
+                ISessionControllerCallback caller, String mediaId,
                 Bundle extras) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchPlayFromMediaId(
-                        mediaId, createExtraBundle(packageName, pid, uid, extras));
+                session.dispatchPlayFromMediaId(createRemoteUserInfo(packageName, pid, uid, caller),
+                        mediaId, extras);
             }
         }
 
         @Override
-        public void onPlayFromSearch(String packageName, int pid, int uid, String query,
+        public void onPlayFromSearch(String packageName, int pid, int uid,
+                ISessionControllerCallback caller, String query,
                 Bundle extras) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchPlayFromSearch(query, createExtraBundle(packageName, pid, uid,
-                        extras));
+                session.dispatchPlayFromSearch(createRemoteUserInfo(packageName, pid, uid, caller),
+                        query, extras);
             }
         }
 
         @Override
-        public void onPlayFromUri(String packageName, int pid, int uid, Uri uri, Bundle extras) {
+        public void onPlayFromUri(String packageName, int pid, int uid,
+                ISessionControllerCallback caller, Uri uri, Bundle extras) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchPlayFromUri(uri, createExtraBundle(packageName, pid, uid, extras));
+                session.dispatchPlayFromUri(createRemoteUserInfo(packageName, pid, uid, caller),
+                        uri, extras);
             }
         }
 
         @Override
-        public void onSkipToTrack(String packageName, int pid, int uid, long id) {
+        public void onSkipToTrack(String packageName, int pid, int uid,
+                ISessionControllerCallback caller, long id) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchSkipToItem(id, createExtraBundle(packageName, pid, uid));
+                session.dispatchSkipToItem(createRemoteUserInfo(packageName, pid, uid, caller), id);
             }
         }
 
         @Override
-        public void onPause(String packageName, int pid, int uid) {
+        public void onPause(String packageName, int pid, int uid,
+                ISessionControllerCallback caller) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchPause(createExtraBundle(packageName, pid, uid));
+                session.dispatchPause(createRemoteUserInfo(packageName, pid, uid, caller));
             }
         }
 
         @Override
-        public void onStop(String packageName, int pid, int uid) {
+        public void onStop(String packageName, int pid, int uid,
+                ISessionControllerCallback caller) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchStop(createExtraBundle(packageName, pid, uid));
+                session.dispatchStop(createRemoteUserInfo(packageName, pid, uid, caller));
             }
         }
 
         @Override
-        public void onNext(String packageName, int pid, int uid) {
+        public void onNext(String packageName, int pid, int uid,
+                ISessionControllerCallback caller) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchNext(createExtraBundle(packageName, pid, uid));
+                session.dispatchNext(createRemoteUserInfo(packageName, pid, uid, caller));
             }
         }
 
         @Override
-        public void onPrevious(String packageName, int pid, int uid) {
+        public void onPrevious(String packageName, int pid, int uid,
+                ISessionControllerCallback caller) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchPrevious(createExtraBundle(packageName, pid, uid));
+                session.dispatchPrevious(createRemoteUserInfo(packageName, pid, uid, caller));
             }
         }
 
         @Override
-        public void onFastForward(String packageName, int pid, int uid) {
+        public void onFastForward(String packageName, int pid, int uid,
+                ISessionControllerCallback caller) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchFastForward(createExtraBundle(packageName, pid, uid));
+                session.dispatchFastForward(createRemoteUserInfo(packageName, pid, uid, caller));
             }
         }
 
         @Override
-        public void onRewind(String packageName, int pid, int uid) {
+        public void onRewind(String packageName, int pid, int uid,
+                ISessionControllerCallback caller) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchRewind(createExtraBundle(packageName, pid, uid));
+                session.dispatchRewind(createRemoteUserInfo(packageName, pid, uid, caller));
             }
         }
 
         @Override
-        public void onSeekTo(String packageName, int pid, int uid, long pos) {
+        public void onSeekTo(String packageName, int pid, int uid,
+                ISessionControllerCallback caller, long pos) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchSeekTo(pos, createExtraBundle(packageName, pid, uid));
+                session.dispatchSeekTo(createRemoteUserInfo(packageName, pid, uid, caller), pos);
             }
         }
 
         @Override
-        public void onRate(String packageName, int pid, int uid, Rating rating) {
+        public void onRate(String packageName, int pid, int uid, ISessionControllerCallback caller,
+                Rating rating) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchRate(rating, createExtraBundle(packageName, pid, uid));
+                session.dispatchRate(createRemoteUserInfo(packageName, pid, uid, caller), rating);
             }
         }
 
         @Override
-        public void onCustomAction(String packageName, int pid, int uid, String action,
-                Bundle args) {
+        public void onCustomAction(String packageName, int pid, int uid,
+                ISessionControllerCallback caller, String action, Bundle args) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchCustomAction(
-                        action, createExtraBundle(packageName, pid, uid, args));
+                session.dispatchCustomAction(createRemoteUserInfo(packageName, pid, uid, caller),
+                        action, args);
             }
         }
 
         @Override
-        public void onAdjustVolume(String packageName, int pid, int uid, int direction) {
+        public void onAdjustVolume(String packageName, int pid, int uid,
+                ISessionControllerCallback caller, int direction) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchAdjustVolume(direction, createExtraBundle(packageName, pid, uid));
+                session.dispatchAdjustVolume(createRemoteUserInfo(packageName, pid, uid, caller),
+                        direction);
             }
         }
 
         @Override
-        public void onSetVolumeTo(String packageName, int pid, int uid, int value) {
+        public void onSetVolumeTo(String packageName, int pid, int uid,
+                ISessionControllerCallback caller, int value) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchSetVolumeTo(value, createExtraBundle(packageName, pid, uid));
+                session.dispatchSetVolumeTo(createRemoteUserInfo(packageName, pid, uid, caller),
+                        value);
             }
         }
     }
@@ -1424,7 +1411,6 @@
     }
 
     private class CallbackMessageHandler extends Handler {
-
         private static final int MSG_COMMAND = 1;
         private static final int MSG_MEDIA_BUTTON = 2;
         private static final int MSG_PREPARE = 3;
@@ -1450,7 +1436,7 @@
         private static final int MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT = 23;
 
         private MediaSession.Callback mCallback;
-        private Bundle mCurrentData;
+        private RemoteUserInfo mCurrentControllerInfo;
 
         public CallbackMessageHandler(Looper looper, MediaSession.Callback callback) {
             super(looper, null, true);
@@ -1458,60 +1444,58 @@
             mCallback.mHandler = this;
         }
 
-        public void post(int what, Object obj, Bundle data) {
-            Message msg = obtainMessage(what, obj);
+        public void post(RemoteUserInfo caller, int what, Object obj, Bundle data, long delayMs) {
+            Pair<RemoteUserInfo, Object> objWithCaller = Pair.create(caller, obj);
+            Message msg = obtainMessage(what, objWithCaller);
             msg.setData(data);
-            msg.sendToTarget();
-        }
-
-        public void postDelayed(int what, Bundle data, long delayMs) {
-            Message msg = obtainMessage(what);
-            msg.setData(data);
-            sendMessageDelayed(msg, delayMs);
+            if (delayMs > 0) {
+                sendMessageDelayed(msg, delayMs);
+            } else {
+                sendMessage(msg);
+            }
         }
 
         @Override
         public void handleMessage(Message msg) {
-            VolumeProvider vp;
-            Bundle data = msg.getData();
-            Bundle originalBundle = getOriginalBundle(data);
+            mCurrentControllerInfo = ((Pair<RemoteUserInfo, Object>) msg.obj).first;
 
-            mCurrentData = data;
+            VolumeProvider vp;
+            Object obj = ((Pair<RemoteUserInfo, Object>) msg.obj).second;
 
             switch (msg.what) {
                 case MSG_COMMAND:
-                    Command cmd = (Command) msg.obj;
+                    Command cmd = (Command) obj;
                     mCallback.onCommand(cmd.command, cmd.extras, cmd.stub);
                     break;
                 case MSG_MEDIA_BUTTON:
-                    mCallback.onMediaButtonEvent((Intent) msg.obj);
+                    mCallback.onMediaButtonEvent((Intent) obj);
                     break;
                 case MSG_PREPARE:
                     mCallback.onPrepare();
                     break;
                 case MSG_PREPARE_MEDIA_ID:
-                    mCallback.onPrepareFromMediaId((String) msg.obj, originalBundle);
+                    mCallback.onPrepareFromMediaId((String) obj, msg.getData());
                     break;
                 case MSG_PREPARE_SEARCH:
-                    mCallback.onPrepareFromSearch((String) msg.obj, originalBundle);
+                    mCallback.onPrepareFromSearch((String) obj, msg.getData());
                     break;
                 case MSG_PREPARE_URI:
-                    mCallback.onPrepareFromUri((Uri) msg.obj, originalBundle);
+                    mCallback.onPrepareFromUri((Uri) obj, msg.getData());
                     break;
                 case MSG_PLAY:
                     mCallback.onPlay();
                     break;
                 case MSG_PLAY_MEDIA_ID:
-                    mCallback.onPlayFromMediaId((String) msg.obj, originalBundle);
+                    mCallback.onPlayFromMediaId((String) obj, msg.getData());
                     break;
                 case MSG_PLAY_SEARCH:
-                    mCallback.onPlayFromSearch((String) msg.obj, originalBundle);
+                    mCallback.onPlayFromSearch((String) obj, msg.getData());
                     break;
                 case MSG_PLAY_URI:
-                    mCallback.onPlayFromUri((Uri) msg.obj, originalBundle);
+                    mCallback.onPlayFromUri((Uri) obj, msg.getData());
                     break;
                 case MSG_SKIP_TO_ITEM:
-                    mCallback.onSkipToQueueItem((Long) msg.obj);
+                    mCallback.onSkipToQueueItem((Long) obj);
                     break;
                 case MSG_PAUSE:
                     mCallback.onPause();
@@ -1532,20 +1516,20 @@
                     mCallback.onRewind();
                     break;
                 case MSG_SEEK_TO:
-                    mCallback.onSeekTo((Long) msg.obj);
+                    mCallback.onSeekTo((Long) obj);
                     break;
                 case MSG_RATE:
-                    mCallback.onSetRating((Rating) msg.obj);
+                    mCallback.onSetRating((Rating) obj);
                     break;
                 case MSG_CUSTOM_ACTION:
-                    mCallback.onCustomAction((String) msg.obj, originalBundle);
+                    mCallback.onCustomAction((String) obj, msg.getData());
                     break;
                 case MSG_ADJUST_VOLUME:
                     synchronized (mLock) {
                         vp = mVolumeProvider;
                     }
                     if (vp != null) {
-                        vp.onAdjustVolume((int) msg.obj);
+                        vp.onAdjustVolume((int) obj);
                     }
                     break;
                 case MSG_SET_VOLUME:
@@ -1553,14 +1537,14 @@
                         vp = mVolumeProvider;
                     }
                     if (vp != null) {
-                        vp.onSetVolumeTo((int) msg.obj);
+                        vp.onSetVolumeTo((int) obj);
                     }
                     break;
                 case MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT:
                     mCallback.handleMediaPlayPauseKeySingleTapIfPending();
                     break;
             }
-            mCurrentData = null;
+            mCurrentControllerInfo = null;
         }
     }
 }
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index f54bfc1..3f0b6c5 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -30,6 +30,7 @@
 import android.media.MediaSession2;
 import android.media.MediaSessionService2;
 import android.media.SessionToken2;
+import android.media.browse.MediaBrowser;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -818,19 +819,31 @@
 
     /**
      * Information of a remote user of {@link MediaSession} or {@link MediaBrowserService}.
-     * This can be used to decide whether the remote user is trusted app.
+     * This can be used to decide whether the remote user is trusted app, and also differentiate
+     * caller of {@link MediaSession} and {@link MediaBrowserService} callbacks.
+     * <p>
+     * See {@link #equals(Object)} to take a look at how it differentiate media controller.
      *
      * @see #isTrustedForMediaControl(RemoteUserInfo)
      */
     public static final class RemoteUserInfo {
-        private String mPackageName;
-        private int mPid;
-        private int mUid;
+        private final String mPackageName;
+        private final int mPid;
+        private final int mUid;
+        private final IBinder mCallerBinder;
 
-        public RemoteUserInfo(String packageName, int pid, int uid) {
+        public RemoteUserInfo(@NonNull String packageName, int pid, int uid) {
+            this(packageName, pid, uid, null);
+        }
+
+        /**
+         * @hide
+         */
+        public RemoteUserInfo(String packageName, int pid, int uid, IBinder callerBinder) {
             mPackageName = packageName;
             mPid = pid;
             mUid = uid;
+            mCallerBinder = callerBinder;
         }
 
         /**
@@ -854,15 +867,29 @@
             return mUid;
         }
 
+        /**
+         * Returns equality of two RemoteUserInfo. Two RemoteUserInfos are the same only if they're
+         * sent to the same controller (either {@link MediaController} or
+         * {@link MediaBrowser}. If it's not nor one of them is triggered by the key presses, they
+         * would be considered as different one.
+         * <p>
+         * If you only want to compare the caller's package, compare them with the
+         * {@link #getPackageName()}, {@link #getPid()}, and/or {@link #getUid()} directly.
+         *
+         * @param obj the reference object with which to compare.
+         * @return {@code true} if equals, {@code false} otherwise
+         */
         @Override
         public boolean equals(Object obj) {
             if (!(obj instanceof RemoteUserInfo)) {
                 return false;
             }
+            if (this == obj) {
+                return true;
+            }
             RemoteUserInfo otherUserInfo = (RemoteUserInfo) obj;
-            return TextUtils.equals(mPackageName, otherUserInfo.mPackageName)
-                    && mPid == otherUserInfo.mPid
-                    && mUid == otherUserInfo.mUid;
+            return (mCallerBinder == null || otherUserInfo.mCallerBinder == null) ? false
+                    : mCallerBinder.equals(otherUserInfo.mCallerBinder);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index b3aa0bf..442354b 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -235,6 +235,7 @@
      * @param packageName The package that made the original volume request.
      * @param pid The pid that made the original volume request.
      * @param uid The uid that made the original volume request.
+     * @param caller caller binder. can be {@code null} if it's from the volume key.
      * @param asSystemService {@code true} if the event sent to the session as if it was come from
      *          the system service instead of the app process. This helps sessions to distinguish
      *          between the key injection by the app and key events from the hardware devices.
@@ -244,8 +245,9 @@
      * @param flags Any of the flags from {@link AudioManager}.
      * @param useSuggested True to use adjustSuggestedStreamVolume instead of
      */
-    public void adjustVolume(String packageName, int pid, int uid, boolean asSystemService,
-            int direction, int flags, boolean useSuggested) {
+    public void adjustVolume(String packageName, int pid, int uid,
+            ISessionControllerCallback caller, boolean asSystemService, int direction, int flags,
+            boolean useSuggested) {
         int previousFlagPlaySound = flags & AudioManager.FLAG_PLAY_SOUND;
         if (isPlaybackActive() || hasFlag(MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY)) {
             flags &= ~AudioManager.FLAG_PLAY_SOUND;
@@ -266,7 +268,7 @@
                 Log.w(TAG, "Muting remote playback is not supported");
                 return;
             }
-            mSessionCb.adjustVolume(packageName, pid, uid, asSystemService, direction);
+            mSessionCb.adjustVolume(packageName, pid, uid, caller, asSystemService, direction);
 
             int volumeBefore = (mOptimisticVolume < 0 ? mCurrentVolume : mOptimisticVolume);
             mOptimisticVolume = volumeBefore + direction;
@@ -285,7 +287,8 @@
         }
     }
 
-    public void setVolumeTo(String packageName, int pid, int uid, int value, int flags) {
+    private void setVolumeTo(String packageName, int pid, int uid,
+            ISessionControllerCallback caller, int value, int flags) {
         if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
             int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs);
             mAudioManagerInternal.setStreamVolumeForUid(stream, value, flags, packageName, uid);
@@ -295,7 +298,7 @@
                 return;
             }
             value = Math.max(0, Math.min(value, mMaxVolume));
-            mSessionCb.setVolumeTo(packageName, pid, uid, value);
+            mSessionCb.setVolumeTo(packageName, pid, uid, caller, value);
 
             int volumeBefore = (mOptimisticVolume < 0 ? mCurrentVolume : mOptimisticVolume);
             mOptimisticVolume = Math.max(0, Math.min(value, mMaxVolume));
@@ -611,6 +614,7 @@
                 try {
                     holder.mCallback.onVolumeInfoChanged(info);
                 } catch (DeadObjectException e) {
+                    mControllerCallbackHolders.remove(i);
                     logCallbackException("Removing dead callback in pushVolumeUpdate", holder, e);
                 } catch (RemoteException e) {
                     logCallbackException("Unexpected exception in pushVolumeUpdate", holder, e);
@@ -629,8 +633,8 @@
                 try {
                     holder.mCallback.onEvent(event, data);
                 } catch (DeadObjectException e) {
-                    logCallbackException("Removing dead callback in pushEvent", holder, e);
                     mControllerCallbackHolders.remove(i);
+                    logCallbackException("Removing dead callback in pushEvent", holder, e);
                 } catch (RemoteException e) {
                     logCallbackException("unexpected exception in pushEvent", holder, e);
                 }
@@ -705,14 +709,6 @@
         return -1;
     }
 
-    private String getPackageName(int uid) {
-        String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
-        if (packages != null && packages.length > 0) {
-            return packages[0];
-        }
-        return null;
-    }
-
     private final Runnable mClearOptimisticVolumeRunnable = new Runnable() {
         @Override
         public void run() {
@@ -913,14 +909,13 @@
 
         public boolean sendMediaButton(String packageName, int pid, int uid,
                 boolean asSystemService, KeyEvent keyEvent, int sequenceId, ResultReceiver cb) {
-            Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
-            mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
             try {
                 if (asSystemService) {
                     mCb.onMediaButton(mContext.getPackageName(), Process.myPid(),
-                            Process.SYSTEM_UID, mediaButtonIntent, sequenceId, cb);
+                            Process.SYSTEM_UID, createMediaButtonIntent(keyEvent), sequenceId, cb);
                 } else {
-                    mCb.onMediaButton(packageName, pid, uid, mediaButtonIntent, sequenceId, cb);
+                    mCb.onMediaButton(packageName, pid, uid,
+                            createMediaButtonIntent(keyEvent), sequenceId, cb);
                 }
                 return true;
             } catch (RemoteException e) {
@@ -929,205 +924,239 @@
             return false;
         }
 
-        public void sendCommand(String packageName, int pid, int uid, String command, Bundle args,
-                ResultReceiver cb) {
+        public boolean sendMediaButton(String packageName, int pid, int uid,
+                ISessionControllerCallback caller, boolean asSystemService,
+                KeyEvent keyEvent) {
             try {
-                mCb.onCommand(packageName, pid, uid, command, args, cb);
+                if (asSystemService) {
+                    mCb.onMediaButton(mContext.getPackageName(), Process.myPid(),
+                            Process.SYSTEM_UID, createMediaButtonIntent(keyEvent), 0, null);
+                } else {
+                    mCb.onMediaButtonFromController(packageName, pid, uid, caller,
+                            createMediaButtonIntent(keyEvent));
+                }
+                return true;
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Remote failure in sendMediaRequest.", e);
+            }
+            return false;
+        }
+
+        public void sendCommand(String packageName, int pid, int uid,
+                ISessionControllerCallback caller, String command, Bundle args, ResultReceiver cb) {
+            try {
+                mCb.onCommand(packageName, pid, uid, caller, command, args, cb);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in sendCommand.", e);
             }
         }
 
-        public void sendCustomAction(String packageName, int pid, int uid, String action,
+        public void sendCustomAction(String packageName, int pid, int uid,
+                ISessionControllerCallback caller, String action,
                 Bundle args) {
             try {
-                mCb.onCustomAction(packageName, pid, uid, action, args);
+                mCb.onCustomAction(packageName, pid, uid, caller, action, args);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in sendCustomAction.", e);
             }
         }
 
-        public void prepare(String packageName, int pid, int uid) {
+        public void prepare(String packageName, int pid, int uid,
+                ISessionControllerCallback caller) {
             try {
-                mCb.onPrepare(packageName, pid, uid);
+                mCb.onPrepare(packageName, pid, uid, caller);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in prepare.", e);
             }
         }
 
-        public void prepareFromMediaId(String packageName, int pid, int uid, String mediaId,
-                Bundle extras) {
+        public void prepareFromMediaId(String packageName, int pid, int uid,
+                ISessionControllerCallback caller, String mediaId, Bundle extras) {
             try {
-                mCb.onPrepareFromMediaId(packageName, pid, uid, mediaId, extras);
+                mCb.onPrepareFromMediaId(packageName, pid, uid, caller, mediaId, extras);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in prepareFromMediaId.", e);
             }
         }
 
-        public void prepareFromSearch(String packageName, int pid, int uid, String query,
-                Bundle extras) {
+        public void prepareFromSearch(String packageName, int pid, int uid,
+                ISessionControllerCallback caller, String query, Bundle extras) {
             try {
-                mCb.onPrepareFromSearch(packageName, pid, uid, query, extras);
+                mCb.onPrepareFromSearch(packageName, pid, uid, caller, query, extras);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in prepareFromSearch.", e);
             }
         }
 
-        public void prepareFromUri(String packageName, int pid, int uid, Uri uri,
-                Bundle extras) {
+        public void prepareFromUri(String packageName, int pid, int uid,
+                ISessionControllerCallback caller, Uri uri, Bundle extras) {
             try {
-                mCb.onPrepareFromUri(packageName, pid, uid, uri, extras);
+                mCb.onPrepareFromUri(packageName, pid, uid, caller, uri, extras);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in prepareFromUri.", e);
             }
         }
 
-        public void play(String packageName, int pid, int uid) {
+        public void play(String packageName, int pid, int uid, ISessionControllerCallback caller) {
             try {
-                mCb.onPlay(packageName, pid, uid);
+                mCb.onPlay(packageName, pid, uid, caller);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in play.", e);
             }
         }
 
-        public void playFromMediaId(String packageName, int pid, int uid, String mediaId,
-                Bundle extras) {
+        public void playFromMediaId(String packageName, int pid, int uid,
+                ISessionControllerCallback caller, String mediaId, Bundle extras) {
             try {
-                mCb.onPlayFromMediaId(packageName, pid, uid, mediaId, extras);
+                mCb.onPlayFromMediaId(packageName, pid, uid, caller, mediaId, extras);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in playFromMediaId.", e);
             }
         }
 
-        public void playFromSearch(String packageName, int pid, int uid, String query,
-                Bundle extras) {
+        public void playFromSearch(String packageName, int pid, int uid,
+                ISessionControllerCallback caller, String query, Bundle extras) {
             try {
-                mCb.onPlayFromSearch(packageName, pid, uid, query, extras);
+                mCb.onPlayFromSearch(packageName, pid, uid, caller, query, extras);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in playFromSearch.", e);
             }
         }
 
-        public void playFromUri(String packageName, int pid, int uid, Uri uri, Bundle extras) {
+        public void playFromUri(String packageName, int pid, int uid,
+                ISessionControllerCallback caller, Uri uri, Bundle extras) {
             try {
-                mCb.onPlayFromUri(packageName, pid, uid, uri, extras);
+                mCb.onPlayFromUri(packageName, pid, uid, caller, uri, extras);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in playFromUri.", e);
             }
         }
 
-        public void skipToTrack(String packageName, int pid, int uid, long id) {
+        public void skipToTrack(String packageName, int pid, int uid,
+                ISessionControllerCallback caller, long id) {
             try {
-                mCb.onSkipToTrack(packageName, pid, uid, id);
+                mCb.onSkipToTrack(packageName, pid, uid, caller, id);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in skipToTrack", e);
             }
         }
 
-        public void pause(String packageName, int pid, int uid) {
+        public void pause(String packageName, int pid, int uid, ISessionControllerCallback caller) {
             try {
-                mCb.onPause(packageName, pid, uid);
+                mCb.onPause(packageName, pid, uid, caller);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in pause.", e);
             }
         }
 
-        public void stop(String packageName, int pid, int uid) {
+        public void stop(String packageName, int pid, int uid, ISessionControllerCallback caller) {
             try {
-                mCb.onStop(packageName, pid, uid);
+                mCb.onStop(packageName, pid, uid, caller);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in stop.", e);
             }
         }
 
-        public void next(String packageName, int pid, int uid) {
+        public void next(String packageName, int pid, int uid, ISessionControllerCallback caller) {
             try {
-                mCb.onNext(packageName, pid, uid);
+                mCb.onNext(packageName, pid, uid, caller);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in next.", e);
             }
         }
 
-        public void previous(String packageName, int pid, int uid) {
+        public void previous(String packageName, int pid, int uid,
+                ISessionControllerCallback caller) {
             try {
-                mCb.onPrevious(packageName, pid, uid);
+                mCb.onPrevious(packageName, pid, uid, caller);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in previous.", e);
             }
         }
 
-        public void fastForward(String packageName, int pid, int uid) {
+        public void fastForward(String packageName, int pid, int uid,
+                ISessionControllerCallback caller) {
             try {
-                mCb.onFastForward(packageName, pid, uid);
+                mCb.onFastForward(packageName, pid, uid, caller);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in fastForward.", e);
             }
         }
 
-        public void rewind(String packageName, int pid, int uid) {
+        public void rewind(String packageName, int pid, int uid,
+                ISessionControllerCallback caller) {
             try {
-                mCb.onRewind(packageName, pid, uid);
+                mCb.onRewind(packageName, pid, uid, caller);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in rewind.", e);
             }
         }
 
-        public void seekTo(String packageName, int pid, int uid, long pos) {
+        public void seekTo(String packageName, int pid, int uid, ISessionControllerCallback caller,
+                long pos) {
             try {
-                mCb.onSeekTo(packageName, pid, uid, pos);
+                mCb.onSeekTo(packageName, pid, uid, caller, pos);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in seekTo.", e);
             }
         }
 
-        public void rate(String packageName, int pid, int uid, Rating rating) {
+        public void rate(String packageName, int pid, int uid, ISessionControllerCallback caller,
+                Rating rating) {
             try {
-                mCb.onRate(packageName, pid, uid, rating);
+                mCb.onRate(packageName, pid, uid, caller, rating);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in rate.", e);
             }
         }
 
-        public void adjustVolume(String packageName, int pid, int uid, boolean asSystemService,
-                int direction) {
+        public void adjustVolume(String packageName, int pid, int uid,
+                ISessionControllerCallback caller, boolean asSystemService, int direction) {
             try {
                 if (asSystemService) {
                     mCb.onAdjustVolume(mContext.getPackageName(), Process.myPid(),
-                            Process.SYSTEM_UID, direction);
+                            Process.SYSTEM_UID, null, direction);
                 } else {
-                    mCb.onAdjustVolume(packageName, pid, uid, direction);
+                    mCb.onAdjustVolume(packageName, pid, uid, caller, direction);
                 }
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in adjustVolume.", e);
             }
         }
 
-        public void setVolumeTo(String packageName, int pid, int uid, int value) {
+        public void setVolumeTo(String packageName, int pid, int uid,
+                ISessionControllerCallback caller, int value) {
             try {
-                mCb.onSetVolumeTo(packageName, pid, uid, value);
+                mCb.onSetVolumeTo(packageName, pid, uid, caller, value);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in setVolumeTo.", e);
             }
         }
+
+        private Intent createMediaButtonIntent(KeyEvent keyEvent) {
+            Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+            mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+            return mediaButtonIntent;
+        }
     }
 
     class ControllerStub extends ISessionController.Stub {
         @Override
-        public void sendCommand(String packageName, String command, Bundle args,
-                ResultReceiver cb) {
+        public void sendCommand(String packageName, ISessionControllerCallback caller,
+                String command, Bundle args, ResultReceiver cb) {
             mSessionCb.sendCommand(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
-                    command, args, cb);
+                    caller, command, args, cb);
         }
 
         @Override
-        public boolean sendMediaButton(String packageName, boolean asSystemService,
-                KeyEvent mediaButtonIntent) {
+        public boolean sendMediaButton(String packageName, ISessionControllerCallback cb,
+                boolean asSystemService, KeyEvent keyEvent) {
             return mSessionCb.sendMediaButton(packageName, Binder.getCallingPid(),
-                    Binder.getCallingUid(), asSystemService, mediaButtonIntent, 0, null);
+                    Binder.getCallingUid(), cb, asSystemService, keyEvent);
         }
 
         @Override
-        public void registerCallbackListener(ISessionControllerCallback cb) {
+        public void registerCallbackListener(String packageName, ISessionControllerCallback cb) {
             synchronized (mLock) {
                 // If this session is already destroyed tell the caller and
                 // don't add them.
@@ -1141,24 +1170,24 @@
                 }
                 if (getControllerHolderIndexForCb(cb) < 0) {
                     mControllerCallbackHolders.add(new ISessionControllerCallbackHolder(cb,
-                          Binder.getCallingUid()));
+                            packageName, Binder.getCallingUid()));
                     if (DEBUG) {
-                        Log.d(TAG, "registering controller callback " + cb);
+                        Log.d(TAG, "registering controller callback " + cb + " from controller"
+                                + packageName);
                     }
                 }
             }
         }
 
         @Override
-        public void unregisterCallbackListener(ISessionControllerCallback cb)
-                throws RemoteException {
+        public void unregisterCallbackListener(ISessionControllerCallback cb) {
             synchronized (mLock) {
                 int index = getControllerHolderIndexForCb(cb);
                 if (index != -1) {
                     mControllerCallbackHolders.remove(index);
                 }
                 if (DEBUG) {
-                    Log.d(TAG, "unregistering callback " + cb + ". index=" + index);
+                    Log.d(TAG, "unregistering callback " + cb.asBinder());
                 }
             }
         }
@@ -1204,13 +1233,13 @@
         }
 
         @Override
-        public void adjustVolume(String packageName, boolean asSystemService, int direction,
-                int flags) {
+        public void adjustVolume(String packageName, ISessionControllerCallback caller,
+                boolean asSystemService, int direction, int flags) {
             int pid = Binder.getCallingPid();
             int uid = Binder.getCallingUid();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionRecord.this.adjustVolume(packageName, pid, uid, asSystemService,
+                MediaSessionRecord.this.adjustVolume(packageName, pid, uid, caller, asSystemService,
                         direction, flags, false /* useSuggested */);
             } finally {
                 Binder.restoreCallingIdentity(token);
@@ -1218,115 +1247,128 @@
         }
 
         @Override
-        public void setVolumeTo(String packageName, int value, int flags) {
+        public void setVolumeTo(String packageName, ISessionControllerCallback caller,
+                int value, int flags) {
             int pid = Binder.getCallingPid();
             int uid = Binder.getCallingUid();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionRecord.this.setVolumeTo(packageName, pid, uid, value, flags);
+                MediaSessionRecord.this.setVolumeTo(packageName, pid, uid, caller, value, flags);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
         }
 
         @Override
-        public void prepare(String packageName) {
-            mSessionCb.prepare(packageName, Binder.getCallingPid(), Binder.getCallingUid());
+        public void prepare(String packageName, ISessionControllerCallback caller) {
+            mSessionCb.prepare(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller);
         }
 
         @Override
-        public void prepareFromMediaId(String packageName, String mediaId, Bundle extras) {
+        public void prepareFromMediaId(String packageName, ISessionControllerCallback caller,
+                String mediaId, Bundle extras) {
             mSessionCb.prepareFromMediaId(packageName, Binder.getCallingPid(),
-                    Binder.getCallingUid(), mediaId, extras);
+                    Binder.getCallingUid(), caller, mediaId, extras);
         }
 
         @Override
-        public void prepareFromSearch(String packageName, String query, Bundle extras) {
+        public void prepareFromSearch(String packageName, ISessionControllerCallback caller,
+                String query, Bundle extras) {
             mSessionCb.prepareFromSearch(packageName, Binder.getCallingPid(),
-                    Binder.getCallingUid(), query, extras);
+                    Binder.getCallingUid(), caller, query, extras);
         }
 
         @Override
-        public void prepareFromUri(String packageName, Uri uri, Bundle extras) {
+        public void prepareFromUri(String packageName, ISessionControllerCallback caller,
+                Uri uri, Bundle extras) {
             mSessionCb.prepareFromUri(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
-                    uri, extras);
+                    caller, uri, extras);
         }
 
         @Override
-        public void play(String packageName) {
-            mSessionCb.play(packageName, Binder.getCallingPid(), Binder.getCallingUid());
+        public void play(String packageName, ISessionControllerCallback caller) {
+            mSessionCb.play(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller);
         }
 
         @Override
-        public void playFromMediaId(String packageName, String mediaId, Bundle extras) {
+        public void playFromMediaId(String packageName, ISessionControllerCallback caller,
+                String mediaId, Bundle extras) {
             mSessionCb.playFromMediaId(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
-                    mediaId, extras);
+                    caller, mediaId, extras);
         }
 
         @Override
-        public void playFromSearch(String packageName, String query, Bundle extras) {
+        public void playFromSearch(String packageName, ISessionControllerCallback caller,
+                String query, Bundle extras) {
             mSessionCb.playFromSearch(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
-                    query, extras);
+                    caller, query, extras);
         }
 
         @Override
-        public void playFromUri(String packageName, Uri uri, Bundle extras) {
+        public void playFromUri(String packageName, ISessionControllerCallback caller,
+                Uri uri, Bundle extras) {
             mSessionCb.playFromUri(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
-                    uri, extras);
+                    caller, uri, extras);
         }
 
         @Override
-        public void skipToQueueItem(String packageName, long id) {
-            mSessionCb.skipToTrack(packageName, Binder.getCallingPid(), Binder.getCallingUid(), id);
+        public void skipToQueueItem(String packageName, ISessionControllerCallback caller,
+                long id) {
+            mSessionCb.skipToTrack(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
+                    caller, id);
         }
 
         @Override
-        public void pause(String packageName) {
-            mSessionCb.pause(packageName, Binder.getCallingPid(), Binder.getCallingUid());
+        public void pause(String packageName, ISessionControllerCallback caller) {
+            mSessionCb.pause(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller);
         }
 
         @Override
-        public void stop(String packageName) {
-            mSessionCb.stop(packageName, Binder.getCallingPid(), Binder.getCallingUid());
+        public void stop(String packageName, ISessionControllerCallback caller) {
+            mSessionCb.stop(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller);
         }
 
         @Override
-        public void next(String packageName) {
-            mSessionCb.next(packageName, Binder.getCallingPid(), Binder.getCallingUid());
+        public void next(String packageName, ISessionControllerCallback caller) {
+            mSessionCb.next(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller);
         }
 
         @Override
-        public void previous(String packageName) {
-            mSessionCb.previous(packageName, Binder.getCallingPid(), Binder.getCallingUid());
+        public void previous(String packageName, ISessionControllerCallback caller) {
+            mSessionCb.previous(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
+                    caller);
         }
 
         @Override
-        public void fastForward(String packageName) {
-            mSessionCb.fastForward(packageName, Binder.getCallingPid(), Binder.getCallingUid());
+        public void fastForward(String packageName, ISessionControllerCallback caller) {
+            mSessionCb.fastForward(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
+                    caller);
         }
 
         @Override
-        public void rewind(String packageName) {
-            mSessionCb.rewind(packageName, Binder.getCallingPid(), Binder.getCallingUid());
+        public void rewind(String packageName, ISessionControllerCallback caller) {
+            mSessionCb.rewind(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller);
         }
 
         @Override
-        public void seekTo(String packageName, long pos) {
-            mSessionCb.seekTo(packageName, Binder.getCallingPid(), Binder.getCallingUid(), pos);
+        public void seekTo(String packageName, ISessionControllerCallback caller, long pos) {
+            mSessionCb.seekTo(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller,
+                    pos);
         }
 
         @Override
-        public void rate(String packageName, Rating rating) {
-            mSessionCb.rate(packageName, Binder.getCallingPid(), Binder.getCallingUid(), rating);
+        public void rate(String packageName, ISessionControllerCallback caller, Rating rating) {
+            mSessionCb.rate(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller,
+                    rating);
         }
 
         @Override
-        public void sendCustomAction(String packageName, String action, Bundle args) {
+        public void sendCustomAction(String packageName, ISessionControllerCallback caller,
+                String action, Bundle args) {
             mSessionCb.sendCustomAction(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
-                    action, args);
+                    caller, action, args);
         }
 
-
         @Override
         public MediaMetadata getMetadata() {
             synchronized (mLock) {
@@ -1372,10 +1414,13 @@
     private class ISessionControllerCallbackHolder {
         private final ISessionControllerCallback mCallback;
         private final String mPackageName;
+        private final int mUid;
 
-        ISessionControllerCallbackHolder(ISessionControllerCallback callback, int uid) {
+        ISessionControllerCallbackHolder(ISessionControllerCallback callback, String packageName,
+                int uid) {
             mCallback = callback;
-            mPackageName = getPackageName(uid);
+            mPackageName = packageName;
+            mUid = uid;
         }
     }
 
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index a6e9389..6fff367 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -1851,7 +1851,7 @@
                     }
                 });
             } else {
-                session.adjustVolume(packageName, pid, uid, asSystemService,
+                session.adjustVolume(packageName, pid, uid, null, asSystemService,
                         direction, flags, true);
             }
         }