Add context to MediaController constructor

This also adds a convenience method to MediaSession to allow getting
a controller instead of having to create and cache your own.

bug:16561220
Change-Id: I87f551a7474e71f1cf2f07e0e541c3a4515cd977
diff --git a/api/current.txt b/api/current.txt
index 680ff69..2fbe9be 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -16571,7 +16571,7 @@
 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);
@@ -16634,6 +16634,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();
@@ -16711,7 +16712,7 @@
   }
 
   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 cb9b493..7757b91c 100644
--- a/cmds/media/src/com/android/commands/media/Media.java
+++ b/cmds/media/src/com/android/commands/media/Media.java
@@ -19,10 +19,13 @@
 
 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.ParcelableVolumeInfo;
 import android.media.session.PlaybackState;
 import android.os.Bundle;
 import android.os.HandlerThread;
@@ -112,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 && id.equals(controller.getTag())) {
-                    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) {
@@ -166,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);
         }
 
@@ -189,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.getTag()
-                    + "...  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");
         }
 
@@ -200,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();
@@ -232,7 +266,7 @@
             } finally {
                 cbThread.getLooper().quit();
                 try {
-                    mController.removeCallback(this);
+                    mController.unregisterCallbackListener(this);
                 } catch (Exception e) {
                     // ignoring
                 }
@@ -246,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) {
-                    String pkg = controller.getPackageName();
-                    System.out.println("  tag=" + controller.getTag()
-                            + ", package=" + pkg);
+                    try {
+                        System.out.println("  tag=" + controller.getTag()
+                                + ", package=" + controller.getPackageName());
+                    } catch (RemoteException e) {
+                        // ignore
+                    }
                 }
             }
         } catch (Exception e) {
diff --git a/media/java/android/media/RemoteController.java b/media/java/android/media/RemoteController.java
index f9d3115..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;
@@ -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();
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index cb9fe55..382579c 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -19,6 +19,7 @@
 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;
@@ -66,6 +67,7 @@
     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();
@@ -82,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());
     }
 
     /**
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index ddf3032..cf8e3dd 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -120,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;
 
@@ -169,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);
         }
@@ -409,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.
      *
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index ca41965..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);
             }
@@ -252,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
@@ -270,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 af6314d..d55e738 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1629,7 +1629,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;
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);
         }