MediaRouter: move controlHints into RouteSessionInfo

Since RouteSessionInfo and controlHints are passed
simultaenously, move controlHints into the session info
for simplicity.

Test: atest mediaroutertest

Change-Id: Id99e4d71744ab438e8fcd99101895c28e2585662
diff --git a/media/java/android/media/IMediaRoute2ProviderClient.aidl b/media/java/android/media/IMediaRoute2ProviderClient.aidl
index 8e63c4a..657f703 100644
--- a/media/java/android/media/IMediaRoute2ProviderClient.aidl
+++ b/media/java/android/media/IMediaRoute2ProviderClient.aidl
@@ -28,6 +28,5 @@
     void updateProviderInfo(in MediaRoute2ProviderInfo info);
     void notifyRouteSelected(String packageName, String routeId, in @nullable Bundle controlHints,
             int seq);
-    void notifySessionCreated(in @nullable RouteSessionInfo sessionInfo,
-            in @nullable Bundle controlHints, int requestId);
+    void notifySessionCreated(in @nullable RouteSessionInfo sessionInfo, int requestId);
 }
diff --git a/media/java/android/media/IMediaRouter2Client.aidl b/media/java/android/media/IMediaRouter2Client.aidl
index f4c6b6a..293116c1 100644
--- a/media/java/android/media/IMediaRouter2Client.aidl
+++ b/media/java/android/media/IMediaRouter2Client.aidl
@@ -28,6 +28,5 @@
     void notifyRoutesAdded(in List<MediaRoute2Info> routes);
     void notifyRoutesRemoved(in List<MediaRoute2Info> routes);
     void notifyRoutesChanged(in List<MediaRoute2Info> routes);
-    void notifySessionCreated(in @nullable RouteSessionInfo sessionInfo,
-            in @nullable Bundle controlHints, int requestId);
+    void notifySessionCreated(in @nullable RouteSessionInfo sessionInfo, int requestId);
 }
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index 6e9f3d0..387b042 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -142,23 +142,24 @@
     }
 
     /**
-     * Sets the information of the session with the given id.
-     * If there is no session matched with the given id, it will be ignored.
+     * Updates the information of a session.
+     * If the session is destroyed or not created before, it will be ignored.
      * A session will be destroyed if it has no selected route.
      * Call {@link #updateProviderInfo(MediaRoute2ProviderInfo)} to notify clients of
      * session info changes.
      *
-     * @param sessionId id of the session that should update its information
      * @param sessionInfo new session information
+     * @see #notifySessionCreated(RouteSessionInfo, int)
      */
-    public final void setSessionInfo(int sessionId, @NonNull RouteSessionInfo sessionInfo) {
+    public final void updateSessionInfo(@NonNull RouteSessionInfo sessionInfo) {
         Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
+        int sessionId = sessionInfo.getSessionId();
 
         synchronized (mSessionLock) {
             if (mSessionInfo.containsKey(sessionId)) {
                 mSessionInfo.put(sessionId, sessionInfo);
             } else {
-                Log.w(TAG, "Ignoring session info update.");
+                Log.w(TAG, "Ignoring unknown session info.");
             }
         }
     }
@@ -170,12 +171,10 @@
      * @param sessionInfo information of the new session.
      *                    Pass {@code null} to reject the request or inform clients that
      *                    session creation has failed.
-     * @param controlHints a {@link Bundle} that contains how to control the session.
      * @param requestId id of the previous request to create this session
      */
     //TODO: fail reason?
-    public final void notifySessionCreated(@Nullable RouteSessionInfo sessionInfo,
-            @Nullable Bundle controlHints, int requestId) {
+    public final void notifySessionCreated(@Nullable RouteSessionInfo sessionInfo, int requestId) {
         //TODO: validate sessionInfo.getSessionId() (it must be in "waiting list")
         if (sessionInfo != null) {
             synchronized (mSessionLock) {
@@ -187,7 +186,7 @@
             return;
         }
         try {
-            mClient.notifySessionCreated(sessionInfo, controlHints, requestId);
+            mClient.notifySessionCreated(sessionInfo, requestId);
         } catch (RemoteException ex) {
             Log.w(TAG, "Failed to notify session created.");
         }
@@ -214,10 +213,10 @@
     /**
      * Called when a session should be created.
      * You should create and maintain your own session and notifies the client of
-     * session info. Call {@link #notifySessionCreated(RouteSessionInfo, Bundle, int)}
+     * session info. Call {@link #notifySessionCreated(RouteSessionInfo, int)}
      * with the given {@code requestId} to notify the information of a new session.
      * If you can't create the session or want to reject the request, pass {@code null}
-     * as session info in {@link #notifySessionCreated(RouteSessionInfo, Bundle, int)}
+     * as session info in {@link #notifySessionCreated(RouteSessionInfo, int)}
      * with the given {@code requestId}.
      *
      * @param packageName the package name of the application that selected the route
@@ -242,20 +241,20 @@
     //TODO: make a way to reject the request
     /**
      * Called when a client requests adding a route to a session.
-     * After the route is added, call {@link #setSessionInfo(int, RouteSessionInfo)} to update
+     * After the route is added, call {@link #updateSessionInfo(RouteSessionInfo)} to update
      * session info and call {@link #updateProviderInfo(MediaRoute2ProviderInfo)} to notify
      * clients of updated session info.
      *
      * @param sessionId id of the session
      * @param routeId id of the route
-     * @see #setSessionInfo(int, RouteSessionInfo)
+     * @see #updateSessionInfo(RouteSessionInfo)
      */
     public abstract void onAddRoute(int sessionId, @NonNull String routeId);
 
     //TODO: make a way to reject the request
     /**
      * Called when a client requests removing a route from a session.
-     * After the route is removed, call {@link #setSessionInfo(int, RouteSessionInfo)} to update
+     * After the route is removed, call {@link #updateSessionInfo(RouteSessionInfo)} to update
      * session info and call {@link #updateProviderInfo(MediaRoute2ProviderInfo)} to notify
      * clients of updated session info.
      *
@@ -267,7 +266,7 @@
     //TODO: make a way to reject the request
     /**
      * Called when a client requests transferring a session to a route.
-     * After the transfer is finished, call {@link #setSessionInfo(int, RouteSessionInfo)} to update
+     * After the transfer is finished, call {@link #updateSessionInfo(RouteSessionInfo)} to update
      * session info and call {@link #updateProviderInfo(MediaRoute2ProviderInfo)} to notify
      * clients of updated session info.
      *
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 161a75a..d58a105 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -328,7 +328,7 @@
             } catch (RemoteException ex) {
                 Log.e(TAG, "Unable to request to create session.", ex);
                 mHandler.sendMessage(obtainMessage(MediaRouter2::createControllerOnHandler,
-                        MediaRouter2.this, null, null, requestId));
+                        MediaRouter2.this, null, requestId));
             }
         }
     }
@@ -494,8 +494,7 @@
      * <p>
      * Pass {@code null} to sessionInfo for the failure case.
      */
-    void createControllerOnHandler(@Nullable RouteSessionInfo sessionInfo,
-            @Nullable Bundle controlHints, int requestId) {
+    void createControllerOnHandler(@Nullable RouteSessionInfo sessionInfo, int requestId) {
         SessionCreationRequest matchingRequest = null;
         for (SessionCreationRequest request : mSessionCreationRequests) {
             if (request.mRequestId == requestId) {
@@ -523,7 +522,7 @@
             // TODO: RouteSessionController should be created with full info (e.g. routes)
             //       from RouteSessionInfo.
             RouteSessionController controller = new RouteSessionController(sessionInfo);
-            executor.execute(() -> callback.onSessionCreated(controller, controlHints));
+            executor.execute(() -> callback.onSessionCreated(controller));
         }
     }
 
@@ -589,7 +588,7 @@
          *
          * @param controller the controller to control the created session
          */
-        public void onSessionCreated(RouteSessionController controller, Bundle controlHints) {}
+        public void onSessionCreated(RouteSessionController controller) {}
 
         /**
          * Called when the session creation request failed.
@@ -669,10 +668,9 @@
         }
 
         @Override
-        public void notifySessionCreated(@Nullable RouteSessionInfo sessionInfo,
-                @Nullable Bundle controlHints, int requestId) {
+        public void notifySessionCreated(@Nullable RouteSessionInfo sessionInfo, int requestId) {
             mHandler.sendMessage(obtainMessage(MediaRouter2::createControllerOnHandler,
-                    MediaRouter2.this, sessionInfo, controlHints, requestId));
+                    MediaRouter2.this, sessionInfo, requestId));
         }
     }
 }
diff --git a/media/java/android/media/RouteSessionController.java b/media/java/android/media/RouteSessionController.java
index b6e8bb5..95fcdc6 100644
--- a/media/java/android/media/RouteSessionController.java
+++ b/media/java/android/media/RouteSessionController.java
@@ -17,6 +17,9 @@
 package android.media;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Bundle;
+
 
 import com.android.internal.annotations.GuardedBy;
 
@@ -39,6 +42,7 @@
     private final int mSessionId;
     private final String mCategory;
     private final Object mLock = new Object();
+    private final Bundle mControlHints;
 
     private List<String> mSelectedRoutes;
 
@@ -55,6 +59,7 @@
         mSessionId = sessionInfo.getSessionId();
         mCategory = sessionInfo.getControlCategory();
         mSelectedRoutes = sessionInfo.getSelectedRoutes();
+        mControlHints = sessionInfo.getControlHints();
         // TODO: Create getters for all other types of routes
     }
 
@@ -74,6 +79,14 @@
     }
 
     /**
+     * @return the control hints used to control route session if available.
+     */
+    @Nullable
+    public Bundle getControlHints() {
+        return mControlHints;
+    }
+
+    /**
      * @return the list of currently selected routes
      */
     @NonNull
diff --git a/media/java/android/media/RouteSessionInfo.java b/media/java/android/media/RouteSessionInfo.java
index 53c8eec..c22fc40 100644
--- a/media/java/android/media/RouteSessionInfo.java
+++ b/media/java/android/media/RouteSessionInfo.java
@@ -17,6 +17,8 @@
 package android.media;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -51,6 +53,7 @@
     final List<String> mDeselectableRoutes;
     final List<String> mGroupableRoutes;
     final List<String> mTransferrableRoutes;
+    final Bundle mControlHints;
 
     RouteSessionInfo(@NonNull Builder builder) {
         Objects.requireNonNull(builder, "builder must not be null.");
@@ -63,6 +66,8 @@
         mDeselectableRoutes = Collections.unmodifiableList(builder.mDeselectableRoutes);
         mGroupableRoutes = Collections.unmodifiableList(builder.mGroupableRoutes);
         mTransferrableRoutes = Collections.unmodifiableList(builder.mTransferrableRoutes);
+
+        mControlHints = builder.mControlHints;
     }
 
     RouteSessionInfo(@NonNull Parcel src) {
@@ -76,6 +81,8 @@
         mDeselectableRoutes = ensureList(src.createStringArrayList());
         mGroupableRoutes = ensureList(src.createStringArrayList());
         mTransferrableRoutes = ensureList(src.createStringArrayList());
+
+        mControlHints = src.readBundle();
     }
 
     private static String ensureString(String str) {
@@ -150,6 +157,14 @@
         return mTransferrableRoutes;
     }
 
+    /**
+     * Gets the control hints
+     */
+    @Nullable
+    public Bundle getControlHints() {
+        return mControlHints;
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -164,6 +179,7 @@
         dest.writeStringList(mDeselectableRoutes);
         dest.writeStringList(mGroupableRoutes);
         dest.writeStringList(mTransferrableRoutes);
+        dest.writeBundle(mControlHints);
     }
 
     @Override
@@ -192,6 +208,7 @@
         final List<String> mDeselectableRoutes;
         final List<String> mGroupableRoutes;
         final List<String> mTransferrableRoutes;
+        Bundle mControlHints;
 
         public Builder(int sessionId, @NonNull String packageName,
                 @NonNull String controlCategory) {
@@ -215,6 +232,8 @@
             mDeselectableRoutes = new ArrayList<>(sessionInfo.mDeselectableRoutes);
             mGroupableRoutes = new ArrayList<>(sessionInfo.mGroupableRoutes);
             mTransferrableRoutes = new ArrayList<>(sessionInfo.mTransferrableRoutes);
+
+            mControlHints = sessionInfo.mControlHints;
         }
 
         /**
@@ -327,6 +346,15 @@
         }
 
         /**
+         * Sets control hints.
+         */
+        @NonNull
+        public Builder setControlHints(@Nullable Bundle controlHints) {
+            mControlHints = controlHints;
+            return this;
+        }
+
+        /**
          * Builds a route session info.
          */
         @NonNull
diff --git a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
index 98efeb8..d04c9b2 100644
--- a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
+++ b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
@@ -182,7 +182,7 @@
             int requestId) {
         if (TextUtils.equals(ROUTE_ID3_SESSION_CREATION_FAILED, routeId)) {
             // Tell the router that session cannot be created by passing null as sessionInfo.
-            notifySessionCreated(null /* sessionInfo */, null /* controlHitns */, requestId);
+            notifySessionCreated(/* sessionInfo= */ null, requestId);
             return;
         }
 
@@ -190,7 +190,7 @@
                 SESSION_ID_1, packageName, controlCategory)
                 .addSelectedRoute(routeId)
                 .build();
-        notifySessionCreated(sessionInfo, null /* controlHints */, requestId);
+        notifySessionCreated(sessionInfo,  requestId);
     }
 
     @Override
@@ -203,7 +203,7 @@
         RouteSessionInfo newSessionInfo = new RouteSessionInfo.Builder(sessionInfo)
                 .addSelectedRoute(routeId)
                 .build();
-        setSessionInfo(sessionId, newSessionInfo);
+        updateSessionInfo(newSessionInfo);
         publishRoutes();
     }
 
@@ -213,7 +213,7 @@
         RouteSessionInfo newSessionInfo = new RouteSessionInfo.Builder(sessionInfo)
                 .removeSelectedRoute(routeId)
                 .build();
-        setSessionInfo(sessionId, newSessionInfo);
+        updateSessionInfo(newSessionInfo);
         publishRoutes();
     }
 
@@ -224,7 +224,7 @@
                 .clearSelectedRoutes()
                 .addSelectedRoute(routeId)
                 .build();
-        setSessionInfo(sessionId, newSessionInfo);
+        updateSessionInfo(newSessionInfo);
         publishRoutes();
     }
 
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java
index e093599..8fe28d9 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java
@@ -46,7 +46,6 @@
 import android.media.MediaRouter2.SessionCreationCallback;
 import android.media.RouteSessionController;
 import android.net.Uri;
-import android.os.Bundle;
 import android.os.Parcel;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
@@ -246,7 +245,7 @@
         // Create session with this route
         SessionCreationCallback callback = new SessionCreationCallback() {
             @Override
-            public void onSessionCreated(RouteSessionController controller, Bundle controlHints) {
+            public void onSessionCreated(RouteSessionController controller) {
                 assertNotNull(controller);
                 assertTrue(controller.getSelectedRoutes().contains(ROUTE_ID1));
                 assertTrue(TextUtils.equals(CATEGORY_SAMPLE, controller.getCategory()));
@@ -284,7 +283,7 @@
         // Create session with this route
         SessionCreationCallback callback = new SessionCreationCallback() {
             @Override
-            public void onSessionCreated(RouteSessionController controller, Bundle controlHints) {
+            public void onSessionCreated(RouteSessionController controller) {
                 successLatch.countDown();
             }
 
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
index 4b3dc0d..9761e6d 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
@@ -352,8 +352,7 @@
         CountDownLatch latch = new CountDownLatch(2);
 
         // A dummy callback is required to send control category info.
-        RouteCallback
-                routeCallback = new RouteCallback();
+        RouteCallback routeCallback = new RouteCallback();
         MediaRouter2Manager.Callback managerCallback = new MediaRouter2Manager.Callback() {
             @Override
             public void onRoutesAdded(List<MediaRoute2Info> routes) {
@@ -368,7 +367,8 @@
 
             @Override
             public void onControlCategoriesChanged(String packageName, List<String> categories) {
-                if (TextUtils.equals(mPackageName, packageName)) {
+                if (TextUtils.equals(mPackageName, packageName)
+                        && controlCategories.equals(categories)) {
                     latch.countDown();
                 }
             }
diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java
index 85509f7..0483431 100644
--- a/services/core/java/com/android/server/media/MediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java
@@ -86,7 +86,6 @@
                 @NonNull String clientPackageName, @NonNull MediaRoute2Info route,
                 @Nullable Bundle controlHints, int seq);
         void onSessionCreated(@NonNull MediaRoute2Provider provider,
-                @Nullable RouteSessionInfo sessionInfo, @Nullable Bundle controlHints,
-                int requestId);
+                @Nullable RouteSessionInfo sessionInfo, int requestId);
     }
 }
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
index 5685ce9..893747b 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
@@ -281,11 +281,11 @@
     }
 
     private void onSessionCreated(Connection connection, @Nullable RouteSessionInfo sessionInfo,
-            @Nullable Bundle controlHints, int requestId) {
+            int requestId) {
         if (mActiveConnection != connection) {
             return;
         }
-        mCallback.onSessionCreated(this, sessionInfo, controlHints, requestId);
+        mCallback.onSessionCreated(this, sessionInfo, requestId);
     }
 
     private void disconnect() {
@@ -391,9 +391,8 @@
                     packageName, routeId, controlHints, seq));
         }
 
-        void postSessionCreated(@Nullable RouteSessionInfo sessionInfo,
-                @Nullable Bundle controlHints, int requestId) {
-            mHandler.post(() -> onSessionCreated(Connection.this, sessionInfo, controlHints,
+        void postSessionCreated(@Nullable RouteSessionInfo sessionInfo, int requestId) {
+            mHandler.post(() -> onSessionCreated(Connection.this, sessionInfo,
                     requestId));
         }
     }
@@ -427,11 +426,10 @@
         }
 
         @Override
-        public void notifySessionCreated(@Nullable RouteSessionInfo sessionInfo,
-                @Nullable Bundle controlHints, int requestId) {
+        public void notifySessionCreated(@Nullable RouteSessionInfo sessionInfo, int requestId) {
             Connection connection = mConnectionRef.get();
             if (connection != null) {
-                connection.postSessionCreated(sessionInfo, controlHints, requestId);
+                connection.postSessionCreated(sessionInfo, requestId);
             }
         }
     }
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 8ee5f66..a711863 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -747,10 +747,9 @@
 
         @Override
         public void onSessionCreated(@NonNull MediaRoute2Provider provider,
-                @Nullable RouteSessionInfo sessionInfo, @Nullable Bundle controlHints,
-                int requestId) {
+                @Nullable RouteSessionInfo sessionInfo, int requestId) {
             sendMessage(PooledLambda.obtainMessage(UserHandler::handleCreateSessionResultOnHandler,
-                    this, provider, sessionInfo, controlHints, requestId));
+                    this, provider, sessionInfo, requestId));
         }
 
         private void updateProvider(MediaRoute2Provider provider) {
@@ -864,7 +863,7 @@
 
         private void handleCreateSessionResultOnHandler(
                 @NonNull MediaRoute2Provider provider, @Nullable RouteSessionInfo sessionInfo,
-                @Nullable Bundle controlHints, int requestId) {
+                int requestId) {
             SessionCreationRequest matchingRequest = null;
             for (SessionCreationRequest request : mSessionCreationRequests) {
                 if (request.mRequestId == requestId
@@ -900,15 +899,14 @@
             }
 
             // Succeeded
-            notifySessionCreated(matchingRequest.mClientRecord, sessionInfo, controlHints,
-                    requestId);
+            notifySessionCreated(matchingRequest.mClientRecord, sessionInfo, requestId);
             // TODO: Tell managers for the session creation
         }
 
         private void notifySessionCreated(Client2Record clientRecord, RouteSessionInfo sessionInfo,
-                Bundle controlHints, int requestId) {
+                int requestId) {
             try {
-                clientRecord.mClient.notifySessionCreated(sessionInfo, controlHints, requestId);
+                clientRecord.mClient.notifySessionCreated(sessionInfo, requestId);
             } catch (RemoteException ex) {
                 Slog.w(TAG, "Failed to notify client of the session creation."
                         + " Client probably died.", ex);
@@ -917,8 +915,7 @@
 
         private void notifySessionCreationFailed(Client2Record clientRecord, int requestId) {
             try {
-                clientRecord.mClient.notifySessionCreated(
-                        null /* sessionInfo */, null /* controlHints */, requestId);
+                clientRecord.mClient.notifySessionCreated(/* sessionInfo= */ null, requestId);
             } catch (RemoteException ex) {
                 Slog.w(TAG, "Failed to notify client of the session creation failure."
                         + " Client probably died.", ex);