Merge changes I87f551a7,Icb8dc76c,I66fbf585,I0c9506e7 into lmp-dev

* changes:
  Add context to MediaController constructor
  Add getPackageName to MediaController
  Expose a way to set a PendingIntent for restarting playback
  Finish plumbing for launch intents in sessions
diff --git a/CleanSpec.mk b/CleanSpec.mk
index abec4c8..fff8a85 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -213,6 +213,7 @@
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework.* $(PRODUCT_OUT)/system/framework2.*)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/docs/api-stubs-timestamp)
 
 # ******************************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
diff --git a/api/current.txt b/api/current.txt
index 5b9ea82..b39f200 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -14144,10 +14144,10 @@
     method public void loadSoundEffects();
     method public void playSoundEffect(int);
     method public void playSoundEffect(int, float);
-    method public void registerMediaButtonEventReceiver(android.content.ComponentName);
-    method public void registerMediaButtonEventReceiver(android.app.PendingIntent);
-    method public void registerRemoteControlClient(android.media.RemoteControlClient);
-    method public boolean registerRemoteController(android.media.RemoteController);
+    method public deprecated void registerMediaButtonEventReceiver(android.content.ComponentName);
+    method public deprecated void registerMediaButtonEventReceiver(android.app.PendingIntent);
+    method public deprecated void registerRemoteControlClient(android.media.RemoteControlClient);
+    method public deprecated boolean registerRemoteController(android.media.RemoteController);
     method public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, int, int);
     method public deprecated void setBluetoothA2dpOn(boolean);
     method public void setBluetoothScoOn(boolean);
@@ -14166,10 +14166,10 @@
     method public void startBluetoothSco();
     method public void stopBluetoothSco();
     method public void unloadSoundEffects();
-    method public void unregisterMediaButtonEventReceiver(android.content.ComponentName);
-    method public void unregisterMediaButtonEventReceiver(android.app.PendingIntent);
-    method public void unregisterRemoteControlClient(android.media.RemoteControlClient);
-    method public void unregisterRemoteController(android.media.RemoteController);
+    method public deprecated void unregisterMediaButtonEventReceiver(android.content.ComponentName);
+    method public deprecated void unregisterMediaButtonEventReceiver(android.app.PendingIntent);
+    method public deprecated void unregisterRemoteControlClient(android.media.RemoteControlClient);
+    method public deprecated void unregisterRemoteController(android.media.RemoteController);
     field public static final java.lang.String ACTION_AUDIO_BECOMING_NOISY = "android.media.AUDIO_BECOMING_NOISY";
     field public static final deprecated java.lang.String ACTION_SCO_AUDIO_STATE_CHANGED = "android.media.SCO_AUDIO_STATE_CHANGED";
     field public static final java.lang.String ACTION_SCO_AUDIO_STATE_UPDATED = "android.media.ACTION_SCO_AUDIO_STATE_UPDATED";
@@ -16578,14 +16578,16 @@
 package android.media.session {
 
   public final class MediaController {
-    ctor public MediaController(android.media.session.MediaSession.Token);
+    ctor public MediaController(android.content.Context, android.media.session.MediaSession.Token);
     method public void addCallback(android.media.session.MediaController.Callback);
     method public void addCallback(android.media.session.MediaController.Callback, android.os.Handler);
     method public void adjustVolume(int, int);
     method public android.media.routing.MediaRouter.Delegate createMediaRouterDelegate();
     method public boolean dispatchMediaButtonEvent(android.view.KeyEvent);
     method public long getFlags();
+    method public android.app.PendingIntent getLaunchActivity();
     method public android.media.MediaMetadata getMetadata();
+    method public java.lang.String getPackageName();
     method public android.media.session.PlaybackState getPlaybackState();
     method public java.util.List<android.media.session.MediaSession.Track> getQueue();
     method public int getRatingType();
@@ -16639,6 +16641,7 @@
     method public void addCallback(android.media.session.MediaSession.Callback, android.os.Handler);
     method public void addTransportControlsCallback(android.media.session.MediaSession.TransportControlsCallback);
     method public void addTransportControlsCallback(android.media.session.MediaSession.TransportControlsCallback, android.os.Handler);
+    method public android.media.session.MediaController getController();
     method public android.media.session.MediaSession.Token getSessionToken();
     method public boolean isActive();
     method public void release();
@@ -16648,7 +16651,8 @@
     method public void setActive(boolean);
     method public void setExtras(android.os.Bundle);
     method public void setFlags(int);
-    method public void setLaunchPendingIntent(android.app.PendingIntent);
+    method public void setLaunchActivity(android.app.PendingIntent);
+    method public void setMediaButtonReceiver(android.app.PendingIntent);
     method public void setMediaRouter(android.media.routing.MediaRouter);
     method public void setMetadata(android.media.MediaMetadata);
     method public void setPlaybackState(android.media.session.PlaybackState);
@@ -16711,10 +16715,11 @@
   public final class MediaSessionManager {
     method public void addActiveSessionsListener(android.media.session.MediaSessionManager.SessionListener, android.content.ComponentName);
     method public java.util.List<android.media.session.MediaController> getActiveSessions(android.content.ComponentName);
+    method public void removeActiveSessionsListener(android.media.session.MediaSessionManager.SessionListener);
   }
 
   public static abstract class MediaSessionManager.SessionListener {
-    ctor public MediaSessionManager.SessionListener();
+    ctor public MediaSessionManager.SessionListener(android.content.Context);
     method public abstract void onActiveSessionsChanged(java.util.List<android.media.session.MediaController>);
   }
 
diff --git a/cmds/media/src/com/android/commands/media/Media.java b/cmds/media/src/com/android/commands/media/Media.java
index c771f65..7757b91c 100644
--- a/cmds/media/src/com/android/commands/media/Media.java
+++ b/cmds/media/src/com/android/commands/media/Media.java
@@ -19,16 +19,17 @@
 
 import android.app.ActivityManager;
 import android.content.Context;
+import android.content.pm.ParceledListSlice;
 import android.media.MediaMetadata;
 import android.media.session.ISessionController;
+import android.media.session.ISessionControllerCallback;
 import android.media.session.ISessionManager;
 import android.media.session.MediaController;
-import android.media.session.MediaSessionInfo;
+import android.media.session.ParcelableVolumeInfo;
 import android.media.session.PlaybackState;
 import android.os.Bundle;
 import android.os.HandlerThread;
 import android.os.IBinder;
-import android.os.Looper;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
@@ -62,14 +63,14 @@
                 "usage: media [subcommand] [options]\n" +
                 "       media dispatch KEY\n" +
                 "       media list-sessions\n" +
-                "       media monitor <sessionId>\n" +
+                "       media monitor <tag>\n" +
                 "\n" +
                 "media dispatch: dispatch a media key to the system.\n" +
                 "                KEY may be: play, pause, play-pause, mute, headsethook,\n" +
                 "                stop, next, previous, rewind, record, fast-forword.\n" +
                 "media list-sessions: print a list of the current sessions.\n" +
                         "media monitor: monitor updates to the specified session.\n" +
-                "                       Use the sessionId from list-sessions.\n"
+                "                       Use the tag from list-sessions.\n"
         );
     }
 
@@ -114,13 +115,16 @@
             List<IBinder> sessions = mSessionService
                     .getSessions(null, ActivityManager.getCurrentUser());
             for (IBinder session : sessions) {
-                MediaController controller = new MediaController(ISessionController.Stub
-                        .asInterface(session));
-                if (controller != null && controller.getSessionInfo().getId().equals(id)) {
-                    ControllerMonitor monitor = new ControllerMonitor(controller);
-                    monitor.run();
-                    success = true;
-                    break;
+                ISessionController controller = ISessionController.Stub.asInterface(session);
+                try {
+                    if (controller != null && id.equals(controller.getTag())) {
+                        ControllerMonitor monitor = new ControllerMonitor(controller);
+                        monitor.run();
+                        success = true;
+                        break;
+                    }
+                } catch (RemoteException e) {
+                    // ignore
                 }
             }
         } catch (Exception e) {
@@ -168,14 +172,14 @@
                 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD));
     }
 
-    class ControllerMonitor extends MediaController.Callback {
-        private final MediaController mController;
+    class ControllerMonitor extends ISessionControllerCallback.Stub {
+        private final ISessionController mController;
 
-        public ControllerMonitor(MediaController controller) {
+        public ControllerMonitor(ISessionController controller) {
             mController = controller;
         }
         @Override
-        public void onSessionEvent(String event, Bundle extras) {
+        public void onEvent(String event, Bundle extras) {
             System.out.println("onSessionEvent event=" + event + ", extras=" + extras);
         }
 
@@ -191,9 +195,33 @@
             System.out.println("onMetadataChanged " + mmString);
         }
 
+        @Override
+        public void onQueueChanged(ParceledListSlice queue) throws RemoteException {
+            System.out.println("onQueueChanged, size=" + queue.getList().size());
+        }
+
+        @Override
+        public void onQueueTitleChanged(CharSequence title) throws RemoteException {
+            System.out.println("onQueueTitleChange " + title);
+        }
+
+        @Override
+        public void onExtrasChanged(Bundle extras) throws RemoteException {
+            System.out.println("onExtrasChanged " + extras);
+        }
+
+        @Override
+        public void onVolumeInfoChanged(ParcelableVolumeInfo info) throws RemoteException {
+            System.out.println("onVolumeInfoChanged " + info);
+        }
+
         void printUsageMessage() {
-            System.out.println("V2Monitoring session " + mController.getSessionInfo().getId()
-                    + "...  available commands:");
+            try {
+                System.out.println("V2Monitoring session " + mController.getTag()
+                        + "...  available commands:");
+            } catch (RemoteException e) {
+                System.out.println("Error trying to monitor session!");
+            }
             System.out.println("(q)uit: finish monitoring");
         }
 
@@ -202,7 +230,11 @@
             HandlerThread cbThread = new HandlerThread("MediaCb") {
                 @Override
                 protected void onLooperPrepared() {
-                    mController.addCallback(ControllerMonitor.this);
+                    try {
+                        mController.registerCallbackListener(ControllerMonitor.this);
+                    } catch (RemoteException e) {
+                        System.out.println("Error registering monitor callback");
+                    }
                 }
             };
             cbThread.start();
@@ -234,7 +266,7 @@
             } finally {
                 cbThread.getLooper().quit();
                 try {
-                    mController.removeCallback(this);
+                    mController.unregisterCallbackListener(this);
                 } catch (Exception e) {
                     // ignoring
                 }
@@ -248,12 +280,15 @@
             List<IBinder> sessions = mSessionService
                     .getSessions(null, ActivityManager.getCurrentUser());
             for (IBinder session : sessions) {
-                MediaController controller = new MediaController(ISessionController.Stub
-                        .asInterface(session));
+
+                ISessionController controller = ISessionController.Stub.asInterface(session);
                 if (controller != null) {
-                    MediaSessionInfo info = controller.getSessionInfo();
-                    System.out.println("  id=" + info.getId() + ", package="
-                            + info.getPackageName());
+                    try {
+                        System.out.println("  tag=" + controller.getTag()
+                                + ", package=" + controller.getPackageName());
+                    } catch (RemoteException e) {
+                        // ignore
+                    }
                 }
             }
         } catch (Exception e) {
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 20ac8e9..1116127 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -27,7 +27,10 @@
 import android.media.RemoteController.OnClientUpdateListener;
 import android.media.audiopolicy.AudioPolicy;
 import android.media.audiopolicy.AudioPolicyConfig;
+import android.media.session.MediaController;
+import android.media.session.MediaSession;
 import android.media.session.MediaSessionLegacyHelper;
+import android.media.session.MediaSessionManager;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
@@ -2218,7 +2221,9 @@
      *      that will receive the media button intent. This broadcast receiver must be declared
      *      in the application manifest. The package of the component must match that of
      *      the context you're registering from.
+     * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead.
      */
+    @Deprecated
     public void registerMediaButtonEventReceiver(ComponentName eventReceiver) {
         if (eventReceiver == null) {
             return;
@@ -2244,9 +2249,12 @@
      * you know you will continue running for the full time until unregistering the
      * PendingIntent.
      * @param eventReceiver target that will receive media button intents.  The PendingIntent
-     * will be sent as-is when a media button action occurs, with {@link Intent#EXTRA_KEY_EVENT}
-     * added and holding the key code of the media button that was pressed.
+     * will be sent an {@link Intent#ACTION_MEDIA_BUTTON} event when a media button action
+     * occurs, with {@link Intent#EXTRA_KEY_EVENT} added and holding the key code of the
+     * media button that was pressed.
+     * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead.
      */
+    @Deprecated
     public void registerMediaButtonEventReceiver(PendingIntent eventReceiver) {
         if (eventReceiver == null) {
             return;
@@ -2271,7 +2279,9 @@
      * Unregister the receiver of MEDIA_BUTTON intents.
      * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
      *      that was registered with {@link #registerMediaButtonEventReceiver(ComponentName)}.
+     * @deprecated Use {@link MediaSession} instead.
      */
+    @Deprecated
     public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) {
         if (eventReceiver == null) {
             return;
@@ -2289,7 +2299,9 @@
      * Unregister the receiver of MEDIA_BUTTON intents.
      * @param eventReceiver same PendingIntent that was registed with
      *      {@link #registerMediaButtonEventReceiver(PendingIntent)}.
+     * @deprecated Use {@link MediaSession} instead.
      */
+    @Deprecated
     public void unregisterMediaButtonEventReceiver(PendingIntent eventReceiver) {
         if (eventReceiver == null) {
             return;
@@ -2311,7 +2323,9 @@
      * @param rcClient The remote control client from which remote controls will receive
      *      information to display.
      * @see RemoteControlClient
+     * @deprecated Use {@link MediaSession} instead.
      */
+    @Deprecated
     public void registerRemoteControlClient(RemoteControlClient rcClient) {
         if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
             return;
@@ -2324,7 +2338,9 @@
      * remote controls.
      * @param rcClient The remote control client to unregister.
      * @see #registerRemoteControlClient(RemoteControlClient)
+     * @deprecated Use {@link MediaSession} instead.
      */
+    @Deprecated
     public void unregisterRemoteControlClient(RemoteControlClient rcClient) {
         if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
             return;
@@ -2342,7 +2358,11 @@
      * @param rctlr the object to register.
      * @return true if the {@link RemoteController} was successfully registered, false if an
      *     error occurred, due to an internal system error, or insufficient permissions.
+     * @deprecated Use
+     * {@link MediaSessionManager#addActiveSessionsListener(android.media.session.MediaSessionManager.SessionListener, ComponentName)}
+     * and {@link MediaController} instead.
      */
+    @Deprecated
     public boolean registerRemoteController(RemoteController rctlr) {
         if (rctlr == null) {
             return false;
@@ -2355,7 +2375,11 @@
      * Unregisters a {@link RemoteController}, causing it to no longer receive media metadata and
      * playback state information, and no longer be capable of controlling playback.
      * @param rctlr the object to unregister.
+     * @deprecated Use
+     * {@link MediaSessionManager#removeActiveSessionsListener(android.media.session.MediaSessionManager.SessionListener)}
+     * instead.
      */
+    @Deprecated
     public void unregisterRemoteController(RemoteController rctlr) {
         if (rctlr == null) {
             return;
diff --git a/media/java/android/media/MediaMetadata.java b/media/java/android/media/MediaMetadata.java
index 5d2f3bd..3f7ebce 100644
--- a/media/java/android/media/MediaMetadata.java
+++ b/media/java/android/media/MediaMetadata.java
@@ -19,6 +19,7 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.format.Time;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.SparseArray;
@@ -73,7 +74,8 @@
     public static final String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
 
     /**
-     * The date the media was created or published as TODO determine format.
+     * The date the media was created or published. The format is unspecified
+     * but RFC 3339 is recommended.
      */
     public static final String METADATA_KEY_DATE = "android.media.metadata.DATE";
 
diff --git a/media/java/android/media/RemoteController.java b/media/java/android/media/RemoteController.java
index 75a8952..0aaaf46 100644
--- a/media/java/android/media/RemoteController.java
+++ b/media/java/android/media/RemoteController.java
@@ -74,8 +74,7 @@
     private MetadataEditor mMetadataEditor;
 
     private MediaSessionManager mSessionManager;
-    private MediaSessionManager.SessionListener mSessionListener
-            = new TopTransportSessionListener();
+    private MediaSessionManager.SessionListener mSessionListener;
     private MediaController.Callback mSessionCb = new MediaControllerCallback();
 
     /**
@@ -141,6 +140,7 @@
         mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
         mSessionManager = (MediaSessionManager) context
                 .getSystemService(Context.MEDIA_SESSION_SERVICE);
+        mSessionListener = new TopTransportSessionListener(context);
 
         if (ActivityManager.isLowRamDeviceStatic()) {
             mMaxBitmapDimension = MAX_BITMAP_DIMENSION;
@@ -214,7 +214,7 @@
     public String getRemoteControlClientPackageName() {
         if (USE_SESSIONS) {
             synchronized (mInfoLock) {
-                return mCurrentSession != null ? mCurrentSession.getSessionInfo().getPackageName()
+                return mCurrentSession != null ? mCurrentSession.getPackageName()
                         : null;
             }
         } else {
@@ -711,6 +711,11 @@
      * currently tracked session if it has changed.
      */
     private class TopTransportSessionListener extends MediaSessionManager.SessionListener {
+
+        public TopTransportSessionListener(Context context) {
+            super(context);
+        }
+
         @Override
         public void onActiveSessionsChanged(List<MediaController> controllers) {
             int size = controllers.size();
@@ -980,8 +985,8 @@
                             0 /* genId */, 1 /* clearing */, null /* obj */, 0 /* delay */);
                 }
             } else if (mCurrentSession == null
-                    || !controller.getSessionInfo().getId()
-                            .equals(mCurrentSession.getSessionInfo().getId())) {
+                    || !controller.getSessionToken()
+                            .equals(mCurrentSession.getSessionToken())) {
                 if (mCurrentSession != null) {
                     mCurrentSession.removeCallback(mSessionCb);
                 }
diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl
index 2c190b7..af3b72e 100644
--- a/media/java/android/media/session/ISession.aidl
+++ b/media/java/android/media/session/ISession.aidl
@@ -15,7 +15,7 @@
 
 package android.media.session;
 
-import android.content.ComponentName;
+import android.app.PendingIntent;
 import android.content.pm.ParceledListSlice;
 import android.media.AudioAttributes;
 import android.media.MediaMetadata;
@@ -36,7 +36,8 @@
     void setFlags(int flags);
     void setActive(boolean active);
     void setMediaRouter(in IMediaRouter router);
-    void setMediaButtonReceiver(in ComponentName mbr);
+    void setMediaButtonReceiver(in PendingIntent mbr);
+    void setLaunchPendingIntent(in PendingIntent pi);
     void destroy();
 
     // These commands are for the TransportPerformer
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index d20b0ad5..3518458 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -15,6 +15,7 @@
 
 package android.media.session;
 
+import android.app.PendingIntent;
 import android.content.Intent;
 import android.content.pm.ParceledListSlice;
 import android.media.MediaMetadata;
@@ -22,7 +23,6 @@
 import android.media.routing.IMediaRouterDelegate;
 import android.media.routing.IMediaRouterStateCallback;
 import android.media.session.ISessionControllerCallback;
-import android.media.session.MediaSessionInfo;
 import android.media.session.ParcelableVolumeInfo;
 import android.media.session.PlaybackState;
 import android.media.session.MediaSession;
@@ -43,7 +43,9 @@
     void registerCallbackListener(in ISessionControllerCallback cb);
     void unregisterCallbackListener(in ISessionControllerCallback cb);
     boolean isTransportControlEnabled();
-    MediaSessionInfo getSessionInfo();
+    String getPackageName();
+    String getTag();
+    PendingIntent getLaunchPendingIntent();
     long getFlags();
     ParcelableVolumeInfo getVolumeAttributes();
     void adjustVolume(int direction, int flags);
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 89c61c8..382579c 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -18,6 +18,8 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.PendingIntent;
+import android.content.Context;
 import android.content.pm.ParceledListSlice;
 import android.media.AudioAttributes;
 import android.media.AudioManager;
@@ -65,12 +67,14 @@
     private final ISessionController mSessionBinder;
 
     private final MediaSession.Token mToken;
+    private final Context mContext;
     private final CallbackStub mCbStub = new CallbackStub(this);
     private final ArrayList<MessageHandler> mCallbacks = new ArrayList<MessageHandler>();
     private final Object mLock = new Object();
 
     private boolean mCbRegistered = false;
-    private MediaSessionInfo mInfo;
+    private String mPackageName;
+    private String mTag;
 
     private final TransportControls mTransportControls;
 
@@ -80,22 +84,27 @@
      *
      * @hide
      */
-    public MediaController(ISessionController sessionBinder) {
+    public MediaController(Context context, ISessionController sessionBinder) {
         if (sessionBinder == null) {
             throw new IllegalArgumentException("Session token cannot be null");
         }
+        if (context == null) {
+            throw new IllegalArgumentException("Context cannot be null");
+        }
         mSessionBinder = sessionBinder;
         mTransportControls = new TransportControls();
         mToken = new MediaSession.Token(sessionBinder);
+        mContext = context;
     }
 
     /**
      * Create a new MediaController from a session's token.
      *
+     * @param context The caller's context.
      * @param token The token for the session.
      */
-    public MediaController(@NonNull MediaSession.Token token) {
-        this(token.getBinder());
+    public MediaController(@NonNull Context context, @NonNull MediaSession.Token token) {
+        this(context, token.getBinder());
     }
 
     /**
@@ -241,6 +250,21 @@
     }
 
     /**
+     * Get an intent for launching UI associated with this session if one
+     * exists.
+     *
+     * @return A {@link PendingIntent} to launch UI or null.
+     */
+    public @Nullable PendingIntent getLaunchActivity() {
+        try {
+            return mSessionBinder.getLaunchPendingIntent();
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Error calling getPendingIntent.", e);
+        }
+        return null;
+    }
+
+    /**
      * Get the token for the session this is connected to.
      *
      * @return The token for the connected session.
@@ -355,20 +379,36 @@
     }
 
     /**
-     * Get the info for the session this controller is connected to.
+     * Get the session owner's package name.
      *
-     * @return The session info for the connected session.
-     * @hide
+     * @return The package name of of the session owner.
      */
-    public MediaSessionInfo getSessionInfo() {
-        if (mInfo == null) {
+    public String getPackageName() {
+        if (mPackageName == null) {
             try {
-                mInfo = mSessionBinder.getSessionInfo();
+                mPackageName = mSessionBinder.getPackageName();
             } catch (RemoteException e) {
-                Log.e(TAG, "Error in getSessionInfo.", e);
+                Log.d(TAG, "Dead object in getPackageName.", e);
             }
         }
-        return mInfo;
+        return mPackageName;
+    }
+
+    /**
+     * Get the session's tag for debugging purposes.
+     *
+     * @return The session's tag.
+     * @hide
+     */
+    public String getTag() {
+        if (mTag == null) {
+            try {
+                mTag = mSessionBinder.getTag();
+            } catch (RemoteException e) {
+                Log.d(TAG, "Dead object in getTag.", e);
+            }
+        }
+        return mTag;
     }
 
     /*
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 866910d..cf8e3dd 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
@@ -119,6 +120,7 @@
     private final Object mLock = new Object();
 
     private final MediaSession.Token mSessionToken;
+    private final MediaController mController;
     private final ISession mBinder;
     private final CallbackStub mCbStub;
 
@@ -168,6 +170,7 @@
         try {
             mBinder = manager.createSession(mCbStub, tag, userId);
             mSessionToken = new Token(mBinder.getController());
+            mController = new MediaController(context, mSessionToken);
         } catch (RemoteException e) {
             throw new RuntimeException("Remote error creating session.", e);
         }
@@ -222,12 +225,17 @@
 
     /**
      * Set an intent for launching UI for this Session. This can be used as a
-     * quick link to an ongoing media screen.
+     * quick link to an ongoing media screen. The intent should be for an
+     * activity that may be started using {@link Activity#startActivity(Intent)}.
      *
      * @param pi The intent to launch to show UI for this Session.
      */
-    public void setLaunchPendingIntent(@Nullable PendingIntent pi) {
-        // TODO
+    public void setLaunchActivity(@Nullable PendingIntent pi) {
+        try {
+            mBinder.setLaunchPendingIntent(pi);
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Failure in setLaunchPendingIntent.", e);
+        }
     }
 
     /**
@@ -248,13 +256,14 @@
     }
 
     /**
-     * Set a media button event receiver component to use to restart playback
-     * after an app has been stopped.
+     * Set a pending intent for your media button receiver to allow restarting
+     * playback after the session has been stopped. If your app is started in
+     * this way an {@link Intent#ACTION_MEDIA_BUTTON} intent will be sent via
+     * the pending intent.
      *
-     * @param mbr The receiver component to send the media button event to.
-     * @hide
+     * @param mbr The {@link PendingIntent} to send the media button event to.
      */
-    public void setMediaButtonReceiver(@Nullable ComponentName mbr) {
+    public void setMediaButtonReceiver(@Nullable PendingIntent mbr) {
         try {
             mBinder.setMediaButtonReceiver(mbr);
         } catch (RemoteException e) {
@@ -402,6 +411,16 @@
     }
 
     /**
+     * Get a controller for this session. This is a convenience method to avoid
+     * having to cache your own controller in process.
+     *
+     * @return A controller for this session.
+     */
+    public @NonNull MediaController getController() {
+        return mController;
+    }
+
+    /**
      * Add a callback to receive transport controls on, such as play, rewind, or
      * fast forward.
      *
@@ -708,6 +727,7 @@
      * the session.
      */
     public static final class Token implements Parcelable {
+
         private ISessionController mBinder;
 
         /**
@@ -727,6 +747,31 @@
             dest.writeStrongBinder(mBinder.asBinder());
         }
 
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((mBinder == null) ? 0 : mBinder.asBinder().hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            Token other = (Token) obj;
+            if (mBinder == null) {
+                if (other.mBinder != null)
+                    return false;
+            } else if (!mBinder.asBinder().equals(other.mBinder.asBinder()))
+                return false;
+            return true;
+        }
+
         ISessionController getBinder() {
             return mBinder;
         }
diff --git a/media/java/android/media/session/MediaSessionInfo.aidl b/media/java/android/media/session/MediaSessionInfo.aidl
deleted file mode 100644
index 63dca9a..0000000
--- a/media/java/android/media/session/MediaSessionInfo.aidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/* Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-package android.media.session;
-
-parcelable MediaSessionInfo;
diff --git a/media/java/android/media/session/MediaSessionInfo.java b/media/java/android/media/session/MediaSessionInfo.java
deleted file mode 100644
index 4dc1c09..0000000
--- a/media/java/android/media/session/MediaSessionInfo.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media.session;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Information about a media session, including the owner's package name.
- *
- * @hide
- */
-public final class MediaSessionInfo implements Parcelable {
-    private final String mId;
-    private final String mPackageName;
-    private final int mPid;
-
-    /**
-     * @hide
-     */
-    public MediaSessionInfo(String id, String packageName, int pid) {
-        mId = id;
-        mPackageName = packageName;
-        mPid = pid;
-    }
-
-    private MediaSessionInfo(Parcel in) {
-        mId = in.readString();
-        mPackageName = in.readString();
-        mPid = in.readInt();
-    }
-
-    /**
-     * Get the package name of the owner of this session.
-     *
-     * @return The owner's package name
-     */
-    public String getPackageName() {
-        return mPackageName;
-    }
-
-    /**
-     * Get the unique id for this session.
-     *
-     * @return The id for the session.
-     */
-    public String getId() {
-        return mId;
-    }
-
-    public int getPid() {
-        return mPid;
-    }
-
-    @Override
-    public String toString() {
-        return "SessionInfo {id=" + mId + ", pkg=" + mPackageName + ", pid=" + mPid + "}";
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(mId);
-        dest.writeString(mPackageName);
-        dest.writeInt(mPid);
-    }
-
-    public static final Parcelable.Creator<MediaSessionInfo> CREATOR
-            = new Parcelable.Creator<MediaSessionInfo>() {
-        @Override
-        public MediaSessionInfo createFromParcel(Parcel in) {
-            return new MediaSessionInfo(in);
-        }
-
-        @Override
-        public MediaSessionInfo[] newArray(int size) {
-            return new MediaSessionInfo[size];
-        }
-    };
-}
diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java
index a6963cf..f075ded 100644
--- a/media/java/android/media/session/MediaSessionLegacyHelper.java
+++ b/media/java/android/media/session/MediaSessionLegacyHelper.java
@@ -304,7 +304,7 @@
 
         holder.mMediaButtonReceiver = new MediaButtonReceiver(pi, context);
         holder.mSession.addCallback(holder.mMediaButtonReceiver, mHandler);
-        holder.mSession.setMediaButtonReceiver(mbrComponent);
+        holder.mSession.setMediaButtonReceiver(pi);
         if (DEBUG) {
             Log.d(TAG, "addMediaButtonListener added " + pi);
         }
@@ -369,7 +369,7 @@
         SessionHolder holder = mSessions.get(pi);
         if (holder == null && createIfMissing) {
             MediaSession session;
-            session = new MediaSession(mContext, TAG);
+            session = new MediaSession(mContext, TAG + "-" + pi.getCreatorPackage());
             session.setActive(true);
             holder = new SessionHolder(session, pi);
             mSessions.put(pi, holder);
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 824b397..84983b9 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -116,7 +116,7 @@
             List<IBinder> binders = mService.getSessions(notificationListener, userId);
             int size = binders.size();
             for (int i = 0; i < size; i++) {
-                MediaController controller = new MediaController(ISessionController.Stub
+                MediaController controller = new MediaController(mContext, ISessionController.Stub
                         .asInterface(binders.get(i)));
                 controllers.add(controller);
             }
@@ -175,7 +175,6 @@
      * Stop receiving active sessions updates on the specified listener.
      *
      * @param listener The listener to remove.
-     * @hide
      */
     public void removeActiveSessionsListener(@NonNull SessionListener listener) {
         if (listener == null) {
@@ -253,6 +252,11 @@
      * using {@link #addActiveSessionsListener}.
      */
     public static abstract class SessionListener {
+        private final Context mContext;
+
+        public SessionListener(Context context) {
+            mContext = context;
+        }
         /**
          * Called when the list of active sessions has changed. This can be due
          * to a session being added or removed or the order of sessions
@@ -271,7 +275,7 @@
                 ArrayList<MediaController> controllers = new ArrayList<MediaController>();
                 int size = tokens.size();
                 for (int i = 0; i < size; i++) {
-                    controllers.add(new MediaController(tokens.get(i)));
+                    controllers.add(new MediaController(mContext, tokens.get(i)));
                 }
                 SessionListener.this.onActiveSessionsChanged(controllers);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 2123bd9..044f69c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1634,7 +1634,7 @@
                     final MediaSession.Token token = entry.notification.getNotification().extras
                             .getParcelable(Notification.EXTRA_MEDIA_SESSION);
                     if (token != null) {
-                        controller = new MediaController(token);
+                        controller = new MediaController(mContext, token);
                         if (controller != null) {
                             // we've got a live one, here
                             mediaNotification = entry;
@@ -1664,7 +1664,7 @@
                                 continue;
                             default:
                                 // now to see if we have one like this
-                                final String pkg = aController.getSessionInfo().getPackageName();
+                                final String pkg = aController.getPackageName();
 
                                 for (int i = 0; i < N; i++) {
                                     final Entry entry = mNotificationData.get(i);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
index 9d050f9..cc351f9 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@@ -195,7 +195,7 @@
         @Override
         public void remoteVolumeChanged(ISessionController binder, int flags)
                 throws RemoteException {
-            MediaController controller = new MediaController(binder);
+            MediaController controller = new MediaController(mContext, binder);
             mPanel.postRemoteVolumeChanged(controller, flags);
         }
 
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index e9df507..2f1bd60 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -16,6 +16,7 @@
 
 package com.android.server.media;
 
+import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -33,14 +34,9 @@
 import android.media.session.ISessionControllerCallback;
 import android.media.session.MediaController;
 import android.media.session.MediaSession;
-import android.media.session.MediaSessionInfo;
 import android.media.session.ParcelableVolumeInfo;
 import android.media.session.PlaybackState;
 import android.media.AudioAttributes;
-import android.media.AudioManager;
-import android.media.MediaMetadata;
-import android.media.Rating;
-import android.media.VolumeProvider;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
@@ -85,7 +81,7 @@
     private final int mOwnerPid;
     private final int mOwnerUid;
     private final int mUserId;
-    private final MediaSessionInfo mSessionInfo;
+    private final String mPackageName;
     private final String mTag;
     private final ControllerStub mController;
     private final SessionStub mSession;
@@ -98,7 +94,8 @@
 
     private long mFlags;
     private IMediaRouter mMediaRouter;
-    private ComponentName mMediaButtonReceiver;
+    private PendingIntent mMediaButtonReceiver;
+    private PendingIntent mLaunchIntent;
 
     // TransportPerformer fields
 
@@ -129,8 +126,7 @@
         mOwnerPid = ownerPid;
         mOwnerUid = ownerUid;
         mUserId = userId;
-        mSessionInfo = new MediaSessionInfo(UUID.randomUUID().toString(), ownerPackageName,
-                ownerPid);
+        mPackageName = ownerPackageName;
         mTag = tag;
         mController = new ControllerStub();
         mSession = new SessionStub();
@@ -164,11 +160,25 @@
      *
      * @return Info that identifies this session.
      */
-    public MediaSessionInfo getSessionInfo() {
-        return mSessionInfo;
+    public String getPackageName() {
+        return mPackageName;
     }
 
-    public ComponentName getMediaButtonReceiver() {
+    /**
+     * Get the tag for the session.
+     *
+     * @return The session's tag.
+     */
+    public String getTag() {
+        return mTag;
+    }
+
+    /**
+     * Get the intent the app set for their media button receiver.
+     *
+     * @return The pending intent set by the app or null.
+     */
+    public PendingIntent getMediaButtonReceiver() {
         return mMediaButtonReceiver;
     }
 
@@ -402,9 +412,10 @@
         pw.println(prefix + mTag + " " + this);
 
         final String indent = prefix + "  ";
+        // We print the hashcode for matching with the list in user records
         pw.println(indent + "ownerPid=" + mOwnerPid + ", ownerUid=" + mOwnerUid
                 + ", userId=" + mUserId);
-        pw.println(indent + "info=" + mSessionInfo.toString());
+        pw.println(indent + "package=" + mPackageName);
         pw.println(indent + "active=" + mIsActive);
         pw.println(indent + "flags=" + mFlags);
         pw.println(indent + "rating type=" + mRatingType);
@@ -413,6 +424,11 @@
         pw.println(indent + "metadata:" + getShortMetadataString());
     }
 
+    @Override
+    public String toString() {
+        return mPackageName + "/" + mTag;
+    }
+
     private String getShortMetadataString() {
         int fields = mMetadata == null ? 0 : mMetadata.size();
         String title = mMetadata == null ? null : mMetadata
@@ -646,8 +662,13 @@
         }
 
         @Override
-        public void setMediaButtonReceiver(ComponentName mbr) {
-            mMediaButtonReceiver = mbr;
+        public void setMediaButtonReceiver(PendingIntent pi) {
+            mMediaButtonReceiver = pi;
+        }
+
+        @Override
+        public void setLaunchPendingIntent(PendingIntent pi) {
+            mLaunchIntent = pi;
         }
 
         @Override
@@ -916,8 +937,18 @@
         }
 
         @Override
-        public MediaSessionInfo getSessionInfo() {
-            return mSessionInfo;
+        public String getPackageName() {
+            return mPackageName;
+        }
+
+        @Override
+        public String getTag() {
+            return mTag;
+        }
+
+        @Override
+        public PendingIntent getLaunchPendingIntent() {
+            return mLaunchIntent;
         }
 
         @Override
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index b0ccd62..92644ce 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -20,6 +20,8 @@
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.KeyguardManager;
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -407,16 +409,6 @@
         return user;
     }
 
-    private int findIndexOfSessionForIdLocked(String sessionId) {
-        for (int i = mAllSessions.size() - 1; i >= 0; i--) {
-            MediaSessionRecord session = mAllSessions.get(i);
-            if (TextUtils.equals(session.getSessionInfo().getId(), sessionId)) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
     private int findIndexOfSessionsListenerLocked(IActiveSessionsListener listener) {
         for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
             if (mSessionsListeners.get(i).mListener == listener) {
@@ -436,7 +428,7 @@
             List<MediaSessionRecord> records = mPriorityStack.getActiveSessions(userId);
             int size = records.size();
             if (size > 0) {
-                persistMediaButtonReceiverLocked(records.get(0));
+                rememberMediaButtonReceiverLocked(records.get(0));
             }
             ArrayList<MediaSession.Token> tokens = new ArrayList<MediaSession.Token>();
             for (int i = 0; i < size; i++) {
@@ -469,13 +461,11 @@
         }
     }
 
-    private void persistMediaButtonReceiverLocked(MediaSessionRecord record) {
-        ComponentName receiver = record.getMediaButtonReceiver();
-        if (receiver != null) {
-            Settings.System.putStringForUser(mContentResolver,
-                    Settings.System.MEDIA_BUTTON_RECEIVER,
-                    receiver == null ? "" : receiver.flattenToString(),
-                    UserHandle.USER_CURRENT);
+    private void rememberMediaButtonReceiverLocked(MediaSessionRecord record) {
+        PendingIntent receiver = record.getMediaButtonReceiver();
+        UserRecord user = mUserRecords.get(record.getUserId());
+        if (receiver != null && user != null) {
+            user.mLastMediaButtonReceiver = receiver;
         }
     }
 
@@ -486,6 +476,7 @@
     final class UserRecord {
         private final int mUserId;
         private final ArrayList<MediaSessionRecord> mSessions = new ArrayList<MediaSessionRecord>();
+        private PendingIntent mLastMediaButtonReceiver;
 
         public UserRecord(Context context, int userId) {
             mUserId = userId;
@@ -521,12 +512,13 @@
         public void dumpLocked(PrintWriter pw, String prefix) {
             pw.println(prefix + "Record for user " + mUserId);
             String indent = prefix + "  ";
+            pw.println(indent + "MediaButtonReceiver:" + mLastMediaButtonReceiver);
             int size = mSessions.size();
             pw.println(indent + size + " Sessions:");
             for (int i = 0; i < size; i++) {
-                // Just print the session info, the full session dump will
+                // Just print the short version, the full session dump will
                 // already be in the list of all sessions.
-                pw.println(indent + mSessions.get(i).getSessionInfo());
+                pw.println(indent + mSessions.get(i).toString());
             }
         }
     }
@@ -767,9 +759,9 @@
         private void dispatchAdjustVolumeLocked(int suggestedStream, int direction, int flags,
                 MediaSessionRecord session) {
             if (DEBUG) {
-                String sessionInfo = session == null ? null : session.getSessionInfo().toString();
-                Log.d(TAG, "Adjusting session " + sessionInfo + " by " + direction + ". flags=" + flags
-                        + ", suggestedStream=" + suggestedStream);
+                String description = session == null ? null : session.toString();
+                Log.d(TAG, "Adjusting session " + description + " by " + direction + ". flags="
+                        + flags + ", suggestedStream=" + suggestedStream);
 
             }
             if (session == null) {
@@ -832,7 +824,7 @@
                 MediaSessionRecord session) {
             if (session != null) {
                 if (DEBUG) {
-                    Log.d(TAG, "Sending media key to " + session.getSessionInfo());
+                    Log.d(TAG, "Sending media key to " + session.toString());
                 }
                 if (needWakeLock) {
                     mKeyEventReceiver.aquireWakeLockLocked();
@@ -843,21 +835,43 @@
                         needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
                         mKeyEventReceiver);
             } else {
-                if (needWakeLock) {
-                    mMediaEventWakeLock.acquire();
+                // Launch the last PendingIntent we had with priority
+                int userId = ActivityManager.getCurrentUser();
+                UserRecord user = mUserRecords.get(userId);
+                if (user.mLastMediaButtonReceiver != null) {
+                    if (DEBUG) {
+                        Log.d(TAG, "Sending media key to last known PendingIntent");
+                    }
+                    if (needWakeLock) {
+                        mKeyEventReceiver.aquireWakeLockLocked();
+                    }
+                    Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+                    mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+                    try {
+                        user.mLastMediaButtonReceiver.send(getContext(),
+                                needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
+                                mediaButtonIntent, mKeyEventReceiver, null);
+                    } catch (CanceledException e) {
+                        Log.i(TAG, "Error sending key event to media button receiver "
+                                + user.mLastMediaButtonReceiver, e);
+                    }
+                } else {
+                    if (DEBUG) {
+                        Log.d(TAG, "Sending media key ordered broadcast");
+                    }
+                    if (needWakeLock) {
+                        mMediaEventWakeLock.acquire();
+                    }
+                    // Fallback to legacy behavior
+                    Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
+                    keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+                    if (needWakeLock) {
+                        keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED,
+                                WAKELOCK_RELEASE_ON_FINISHED);
+                    }
+                    getContext().sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL,
+                            null, mKeyEventDone, mHandler, Activity.RESULT_OK, null, null);
                 }
-                if (DEBUG) {
-                    Log.d(TAG, "Sending media key ordered broadcast");
-                }
-                // Fallback to legacy behavior
-                Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
-                keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
-                if (needWakeLock) {
-                    keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED,
-                            WAKELOCK_RELEASE_ON_FINISHED);
-                }
-                getContext().sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL,
-                        null, mKeyEventDone, mHandler, Activity.RESULT_OK, null, null);
             }
         }
 
@@ -904,7 +918,8 @@
 
         private KeyEventWakeLockReceiver mKeyEventReceiver = new KeyEventWakeLockReceiver(mHandler);
 
-        class KeyEventWakeLockReceiver extends ResultReceiver implements Runnable {
+        class KeyEventWakeLockReceiver extends ResultReceiver implements Runnable,
+                PendingIntent.OnFinished {
             private final Handler mHandler;
             private int mRefCount = 0;
             private int mLastTimeoutId = 0;
@@ -963,6 +978,12 @@
                 mMediaEventWakeLock.release();
                 mHandler.removeCallbacks(this);
             }
+
+            @Override
+            public void onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode,
+                    String resultData, Bundle resultExtras) {
+                onReceiveResult(resultCode, null);
+            }
         };
 
         BroadcastReceiver mKeyEventDone = new BroadcastReceiver() {