Make MediaRouter2Manager provide correct system routes info

System route info could be changed per different apps. For example,
when a BT headset is connected, if a media app call
MediaRouter.selectRoute(defaultRoute) via Jetpack lib, the app will use
the phone speaker while the other media apps use the BT headset.

System UI should be changed depends on this CL.

Bug: 156549746
Test: atest mediaroutertest
      atest CtsMediaTestCases:android.media.cts.SystemMediaRouter2Test
Ignore-AOSP-First: AOSP doesn't have SystemMediaRouter2Test
Change-Id: Ie24f97023b7113a2b59f0b55ab7b4230b394e9bd
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 4c1cc87..38812f9 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4319,6 +4319,9 @@
          doesn't support the work profile. [CHAR LIMIT=100] -->
     <string name="activity_resolver_work_profiles_support">%1$s doesn\'t support work profile</string>
 
+    <!-- DO NOT TRANSLATE -->
+    <string name="default_audio_route_id">default_audio_route</string>
+
     <!-- Name of the default audio route for tablets when nothing
          is connected to a headphone or other wired audio output jack. [CHAR LIMIT=50] -->
     <string name="default_audio_route_name" product="tablet">Tablet</string>
@@ -4347,6 +4350,9 @@
     <!-- Name of the default audio route category. [CHAR LIMIT=50] -->
     <string name="default_audio_route_category_name">System</string>
 
+    <!-- DO NOT TRANSLATE -->
+    <string name="bluetooth_a2dp_audio_route_id">bluetooth_a2dp_audio_route</string>
+
     <!-- Description of the bluetooth a2dp audio route. [CHAR LIMIT=50] -->
     <string name="bluetooth_a2dp_audio_route_name">Bluetooth audio</string>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 58e9cda..7d8cc26 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1082,6 +1082,7 @@
   <java-symbol type="string" name="granularity_label_word" />
   <java-symbol type="string" name="granularity_label_link" />
   <java-symbol type="string" name="granularity_label_line" />
+  <java-symbol type="string" name="default_audio_route_id" />
   <java-symbol type="string" name="default_audio_route_name" />
   <java-symbol type="string" name="default_audio_route_name_dock_speakers" />
   <java-symbol type="string" name="default_audio_route_name_hdmi" />
@@ -1663,6 +1664,7 @@
   <java-symbol type="string" name="media_route_chooser_title" />
   <java-symbol type="string" name="media_route_chooser_title_for_remote_display" />
   <java-symbol type="string" name="media_route_controller_disconnect" />
+  <java-symbol type="string" name="bluetooth_a2dp_audio_route_id" />
   <java-symbol type="string" name="bluetooth_a2dp_audio_route_name" />
 
   <java-symbol type="dimen" name="config_minScalingSpan" />
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 07389b2..55c200d 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -486,6 +486,7 @@
         <permission name="android.permission.SCHEDULE_PRIORITIZED_ALARM" />
         <!-- Permission required for CTS test - SystemMediaRouter2Test -->
         <permission name="android.permission.MEDIA_CONTENT_CONTROL"/>
+        <permission name="android.permission.MODIFY_AUDIO_ROUTING"/>
         <!-- Permission required for CTS test - CtsPermission5TestCases -->
         <permission name="android.permission.RENOUNCE_PERMISSIONS" />
         <permission name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS" />
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index 48289ec..b59c71f 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -69,7 +69,9 @@
     void releaseSessionWithRouter2(IMediaRouter2 router, String sessionId);
 
     // Methods for MediaRouter2Manager
-    List<RoutingSessionInfo> getActiveSessions(IMediaRouter2Manager manager);
+    List<RoutingSessionInfo> getRemoteSessions(IMediaRouter2Manager manager);
+    RoutingSessionInfo getSystemSessionInfoForPackage(
+            IMediaRouter2Manager manager, String packageName);
     void registerManager(IMediaRouter2Manager manager, String packageName);
     void unregisterManager(IMediaRouter2Manager manager);
     void setRouteVolumeWithManager(IMediaRouter2Manager manager, int requestId,
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 62b9cb0..e432eb6 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -48,6 +48,7 @@
 import android.view.Display;
 import android.view.DisplayAddress;
 
+import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.lang.annotation.Retention;
@@ -148,7 +149,7 @@
                     ServiceManager.getService(Context.MEDIA_ROUTER_SERVICE));
 
             mSystemCategory = new RouteCategory(
-                    com.android.internal.R.string.default_audio_route_category_name,
+                    R.string.default_audio_route_category_name,
                     ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO, false);
             mSystemCategory.mIsSystem = true;
 
@@ -163,14 +164,15 @@
         // Called after sStatic is initialized
         void startMonitoringRoutes(Context appContext) {
             mDefaultAudioVideo = new RouteInfo(mSystemCategory);
-            mDefaultAudioVideo.mNameResId = com.android.internal.R.string.default_audio_route_name;
+            mDefaultAudioVideo.mNameResId = R.string.default_audio_route_name;
             mDefaultAudioVideo.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO;
             mDefaultAudioVideo.updatePresentationDisplay();
             if (((AudioManager) appContext.getSystemService(Context.AUDIO_SERVICE))
                     .isVolumeFixed()) {
                 mDefaultAudioVideo.mVolumeHandling = RouteInfo.PLAYBACK_VOLUME_FIXED;
             }
-
+            mDefaultAudioVideo.mGlobalRouteId = sStatic.mResources.getString(
+                    R.string.default_audio_route_id);
             addRouteStatic(mDefaultAudioVideo);
 
             // This will select the active wifi display route if there is one.
@@ -215,15 +217,15 @@
                 int name;
                 if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HEADPHONES) != 0
                         || (newRoutes.mainType & AudioRoutesInfo.MAIN_HEADSET) != 0) {
-                    name = com.android.internal.R.string.default_audio_route_name_headphones;
+                    name = R.string.default_audio_route_name_headphones;
                 } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) {
-                    name = com.android.internal.R.string.default_audio_route_name_dock_speakers;
+                    name = R.string.default_audio_route_name_dock_speakers;
                 } else if ((newRoutes.mainType&AudioRoutesInfo.MAIN_HDMI) != 0) {
-                    name = com.android.internal.R.string.default_audio_route_name_hdmi;
+                    name = R.string.default_audio_route_name_hdmi;
                 } else if ((newRoutes.mainType&AudioRoutesInfo.MAIN_USB) != 0) {
-                    name = com.android.internal.R.string.default_audio_route_name_usb;
+                    name = R.string.default_audio_route_name_usb;
                 } else {
-                    name = com.android.internal.R.string.default_audio_route_name;
+                    name = R.string.default_audio_route_name;
                 }
                 mDefaultAudioVideo.mNameResId = name;
                 dispatchRouteChanged(mDefaultAudioVideo);
@@ -243,9 +245,12 @@
                         final RouteInfo info = new RouteInfo(mSystemCategory);
                         info.mName = newRoutes.bluetoothName;
                         info.mDescription = mResources.getText(
-                                com.android.internal.R.string.bluetooth_a2dp_audio_route_name);
+                                R.string.bluetooth_a2dp_audio_route_name);
                         info.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO;
                         info.mDeviceType = RouteInfo.DEVICE_TYPE_BLUETOOTH;
+                        info.mGlobalRouteId = sStatic.mResources.getString(
+                                R.string.bluetooth_a2dp_audio_route_id);
+
                         mBluetoothA2dpRoute = info;
                         addRouteStatic(mBluetoothA2dpRoute);
                     } else {
@@ -508,6 +513,9 @@
             outer: for (int i = mRoutes.size(); i-- > 0; ) {
                 final RouteInfo route = mRoutes.get(i);
                 final String globalRouteId = route.mGlobalRouteId;
+                if (route.isDefault() || route.isBluetooth()) {
+                    continue;
+                }
                 if (globalRouteId != null) {
                     for (int j = 0; j < globalRouteCount; j++) {
                         MediaRouterClientState.RouteInfo globalRoute = globalRoutes.get(j);
@@ -1572,7 +1580,7 @@
         newRoute.mEnabled = isWifiDisplayEnabled(display, wfdStatus);
         newRoute.mName = display.getFriendlyDisplayName();
         newRoute.mDescription = sStatic.mResources.getText(
-                com.android.internal.R.string.wireless_display_route_description);
+                R.string.wireless_display_route_description);
         newRoute.updatePresentationDisplay();
         newRoute.mDeviceType = RouteInfo.DEVICE_TYPE_TV;
         return newRoute;
@@ -1867,19 +1875,19 @@
             int resId;
             switch (statusCode) {
                 case STATUS_SCANNING:
-                    resId = com.android.internal.R.string.media_route_status_scanning;
+                    resId = R.string.media_route_status_scanning;
                     break;
                 case STATUS_CONNECTING:
-                    resId = com.android.internal.R.string.media_route_status_connecting;
+                    resId = R.string.media_route_status_connecting;
                     break;
                 case STATUS_AVAILABLE:
-                    resId = com.android.internal.R.string.media_route_status_available;
+                    resId = R.string.media_route_status_available;
                     break;
                 case STATUS_NOT_AVAILABLE:
-                    resId = com.android.internal.R.string.media_route_status_not_available;
+                    resId = R.string.media_route_status_not_available;
                     break;
                 case STATUS_IN_USE:
-                    resId = com.android.internal.R.string.media_route_status_in_use;
+                    resId = R.string.media_route_status_in_use;
                     break;
                 case STATUS_CONNECTED:
                 case STATUS_NONE:
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index fbf7def..4b32dbf 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -300,7 +300,8 @@
         mManagerCallback = new ManagerCallback();
         mHandler = new Handler(Looper.getMainLooper());
         mSystemController = new SystemRoutingController(
-                ensureClientPackageNameForSystemSession(sManager.getSystemRoutingSession()));
+                ensureClientPackageNameForSystemSession(
+                        sManager.getSystemRoutingSession(clientPackageName)));
         mDiscoveryPreference = new RouteDiscoveryPreference.Builder(
                 sManager.getPreferredFeatures(clientPackageName), true).build();
         updateAllRoutesFromManager();
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 7f7fb60..83fa7c2 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -351,16 +351,21 @@
     }
 
     /**
-     * Gets the system routing session associated with no specific application.
+     * Gets the system routing session for the given {@code packageName}.
+     * Apps can select a route that is not the global route. (e.g. an app can select the device
+     * route while BT route is available.)
+     *
+     * @param packageName the package name of the application.
      */
-    @NonNull
-    public RoutingSessionInfo getSystemRoutingSession() {
-        for (RoutingSessionInfo sessionInfo : getActiveSessions()) {
-            if (sessionInfo.isSystemSession()) {
-                return sessionInfo;
-            }
+    @Nullable
+    public RoutingSessionInfo getSystemRoutingSession(@Nullable String packageName) {
+        try {
+            return mMediaRouterService.getSystemSessionInfoForPackage(
+                    getOrCreateClient(), packageName);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Unable to get current system session info", ex);
         }
-        throw new IllegalStateException("No system routing session");
+        return null;
     }
 
     /**
@@ -377,13 +382,10 @@
             return null;
         }
         if (playbackInfo.getPlaybackType() == MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
-            return new RoutingSessionInfo.Builder(getSystemRoutingSession())
-                    .setClientPackageName(mediaController.getPackageName())
-                    .build();
+            return getSystemRoutingSession(mediaController.getPackageName());
         }
-        for (RoutingSessionInfo sessionInfo : getActiveSessions()) {
-            if (!sessionInfo.isSystemSession()
-                    && areSessionsMatched(mediaController, sessionInfo)) {
+        for (RoutingSessionInfo sessionInfo : getRemoteSessions()) {
+            if (areSessionsMatched(mediaController, sessionInfo)) {
                 return sessionInfo;
             }
         }
@@ -395,20 +397,17 @@
      * The first element of the returned list is the system routing session.
      *
      * @param packageName the package name of the application that is routing.
-     * @see #getSystemRoutingSession()
+     * @see #getSystemRoutingSession(String)
      */
     @NonNull
     public List<RoutingSessionInfo> getRoutingSessions(@NonNull String packageName) {
         Objects.requireNonNull(packageName, "packageName must not be null");
 
         List<RoutingSessionInfo> sessions = new ArrayList<>();
+        sessions.add(getSystemRoutingSession(packageName));
 
-        for (RoutingSessionInfo sessionInfo : getActiveSessions()) {
-            if (sessionInfo.isSystemSession()) {
-                sessions.add(new RoutingSessionInfo.Builder(sessionInfo)
-                        .setClientPackageName(packageName)
-                        .build());
-            } else if (TextUtils.equals(sessionInfo.getClientPackageName(), packageName)) {
+        for (RoutingSessionInfo sessionInfo : getRemoteSessions()) {
+            if (TextUtils.equals(sessionInfo.getClientPackageName(), packageName)) {
                 sessions.add(sessionInfo);
             }
         }
@@ -416,23 +415,21 @@
     }
 
     /**
-     * Gets the list of all active routing sessions.
+     * Gets the list of all routing sessions except the system routing session.
      * <p>
-     * The first element of the list is the system routing session containing
-     * phone speakers, wired headset, Bluetooth devices.
-     * The system routing session is shared by apps such that controlling it will affect
-     * all apps.
      * If you want to transfer media of an application, use {@link #getRoutingSessions(String)}.
+     * If you want to get only the system routing session, use
+     * {@link #getSystemRoutingSession(String)}.
      *
      * @see #getRoutingSessions(String)
-     * @see #getSystemRoutingSession()
+     * @see #getSystemRoutingSession(String)
      */
     @NonNull
-    public List<RoutingSessionInfo> getActiveSessions() {
+    public List<RoutingSessionInfo> getRemoteSessions() {
         Client client = getOrCreateClient();
         if (client != null) {
             try {
-                return mMediaRouterService.getActiveSessions(client);
+                return mMediaRouterService.getRemoteSessions(client);
             } catch (RemoteException ex) {
                 Log.e(TAG, "Unable to get sessions. Service probably died.", ex);
             }
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
index 3a34e75..d7e9ae9 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
@@ -115,7 +115,8 @@
     public void setUp() throws Exception {
         mContext = InstrumentationRegistry.getTargetContext();
         mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
-        mUiAutomation.adoptShellPermissionIdentity(Manifest.permission.MEDIA_CONTENT_CONTROL);
+        mUiAutomation.adoptShellPermissionIdentity(Manifest.permission.MEDIA_CONTENT_CONTROL,
+                Manifest.permission.MODIFY_AUDIO_ROUTING);
         MediaRouter2ManagerTestActivity.startActivity(mContext);
 
         mManager = MediaRouter2Manager.getInstance(mContext);
@@ -305,7 +306,7 @@
 
         mManager.selectRoute(mPackageName, routeToSelect);
         assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-        assertEquals(2, mManager.getActiveSessions().size());
+        assertEquals(1, mManager.getRemoteSessions().size());
     }
 
     @Test
@@ -368,7 +369,7 @@
                 .addFeature(FEATURE_REMOTE_PLAYBACK)
                 .build();
 
-        mManager.transfer(mManager.getSystemRoutingSession(), unknownRoute);
+        mManager.transfer(mManager.getSystemRoutingSession(null), unknownRoute);
         assertFalse(onSessionCreatedLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
         assertTrue(onTransferFailedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
     }
@@ -512,12 +513,12 @@
         assertFalse(managerOnSessionReleasedLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
 
         assertEquals(2, sessions.size());
-        List<String> activeSessionIds = mManager.getActiveSessions().stream()
+        List<String> remoteSessionIds = mManager.getRemoteSessions().stream()
                 .map(RoutingSessionInfo::getId)
                 .collect(Collectors.toList());
-        // The old session shouldn't appear on the active session list.
-        assertFalse(activeSessionIds.contains(sessions.get(0).getId()));
-        assertTrue(activeSessionIds.contains(sessions.get(1).getId()));
+        // The old session shouldn't appear on the session list.
+        assertFalse(remoteSessionIds.contains(sessions.get(0).getId()));
+        assertTrue(remoteSessionIds.contains(sessions.get(1).getId()));
 
         assertFalse(serviceOnReleaseSessionLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
         mManager.releaseSession(sessions.get(0));
@@ -554,13 +555,14 @@
         assertTrue(onFailedLatch.await(MediaRouter2Manager.TRANSFER_TIMEOUT_MS,
                 TimeUnit.MILLISECONDS));
     }
+
     @Test
     public void testSetSystemRouteVolume() throws Exception {
         // ensure client
         addManagerCallback(new MediaRouter2Manager.Callback() {});
         String selectedSystemRouteId =
                 MediaRouter2Utils.getOriginalId(
-                mManager.getActiveSessions().get(0).getSelectedRoutes().get(0));
+                mManager.getSystemRoutingSession(mPackageName).getSelectedRoutes().get(0));
         Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL);
         MediaRoute2Info volRoute = routes.get(selectedSystemRouteId);
         assertNotNull(volRoute);
@@ -814,11 +816,6 @@
         assertTrue(onSessionCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
     }
 
-    @Test
-    public void testGetActiveSessions_returnsNonEmptyList() {
-        assertFalse(mManager.getActiveSessions().isEmpty());
-    }
-
     Map<String, MediaRoute2Info> waitAndGetRoutesWithManager(List<String> routeFeatures)
             throws Exception {
         CountDownLatch addedLatch = new CountDownLatch(1);
@@ -938,7 +935,7 @@
         // ensure ManagerRecord in MediaRouter2ServiceImpl
         addManagerCallback(new MediaRouter2Manager.Callback() {});
 
-        for (RoutingSessionInfo session : mManager.getActiveSessions()) {
+        for (RoutingSessionInfo session : mManager.getRemoteSessions()) {
             mManager.releaseSession(session);
         }
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index 3c43f4a6..dd8f604 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -112,11 +112,9 @@
      */
     boolean connectDeviceWithoutPackageName(MediaDevice device) {
         boolean isConnected = false;
-        final List<RoutingSessionInfo> infos = mRouterManager.getActiveSessions();
-        if (infos.size() > 0) {
-            final RoutingSessionInfo info = infos.get(0);
+        final RoutingSessionInfo info = mRouterManager.getSystemRoutingSession(null);
+        if (info != null) {
             mRouterManager.transfer(info, device.mRouteInfo);
-
             isConnected = true;
         }
         return isConnected;
@@ -414,7 +412,10 @@
     }
 
     List<RoutingSessionInfo> getActiveMediaSession() {
-        return mRouterManager.getActiveSessions();
+        List<RoutingSessionInfo> infos = new ArrayList<>();
+        infos.add(mRouterManager.getSystemRoutingSession(null));
+        infos.addAll(mRouterManager.getRemoteSessions());
+        return infos;
     }
 
     private void buildAvailableRoutes() {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
index 0d03f33..2d53831 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
@@ -237,7 +237,7 @@
 
         final List<RoutingSessionInfo> infos = new ArrayList<>();
 
-        mShadowRouter2Manager.setActiveSessions(infos);
+        mShadowRouter2Manager.setRemoteSessions(infos);
 
         assertThat(mInfoMediaManager.connectDeviceWithoutPackageName(device)).isFalse();
     }
@@ -525,10 +525,18 @@
 
     @Test
     public void getActiveMediaSession_returnActiveSession() {
+        RoutingSessionInfo sysSessionInfo = mock(RoutingSessionInfo.class);
         final List<RoutingSessionInfo> infos = new ArrayList<>();
-        mShadowRouter2Manager.setActiveSessions(infos);
+        infos.add(mock(RoutingSessionInfo.class));
+        final List<RoutingSessionInfo> activeSessionInfos = new ArrayList<>();
+        activeSessionInfos.add(sysSessionInfo);
+        activeSessionInfos.addAll(infos);
 
-        assertThat(mInfoMediaManager.getActiveMediaSession()).containsExactlyElementsIn(infos);
+        mShadowRouter2Manager.setSystemRoutingSession(sysSessionInfo);
+        mShadowRouter2Manager.setRemoteSessions(infos);
+
+        assertThat(mInfoMediaManager.getActiveMediaSession())
+                .containsExactlyElementsIn(activeSessionInfos);
     }
 
     @Test
diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowRouter2Manager.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowRouter2Manager.java
index 5959863..dac8142 100644
--- a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowRouter2Manager.java
+++ b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowRouter2Manager.java
@@ -16,6 +16,7 @@
 package com.android.settingslib.testutils.shadow;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.media.MediaRoute2Info;
 import android.media.MediaRouter2Manager;
 import android.media.RoutingSessionInfo;
@@ -33,8 +34,9 @@
     private List<MediaRoute2Info> mAvailableRoutes;
     private List<MediaRoute2Info> mAllRoutes;
     private List<MediaRoute2Info> mDeselectableRoutes;
-    private List<RoutingSessionInfo> mActiveSessions;
+    private List<RoutingSessionInfo> mRemoteSessions;
     private List<RoutingSessionInfo> mRoutingSessions;
+    private RoutingSessionInfo mSystemRoutingSession;
 
     @Implementation
     protected List<MediaRoute2Info> getAvailableRoutes(String packageName) {
@@ -55,12 +57,12 @@
     }
 
     @Implementation
-    protected List<RoutingSessionInfo> getActiveSessions() {
-        return mActiveSessions;
+    protected List<RoutingSessionInfo> getRemoteSessions() {
+        return mRemoteSessions;
     }
 
-    public void setActiveSessions(List<RoutingSessionInfo> infos) {
-        mActiveSessions = infos;
+    public void setRemoteSessions(List<RoutingSessionInfo> infos) {
+        mRemoteSessions = infos;
     }
 
     @Implementation
@@ -73,6 +75,15 @@
     }
 
     @Implementation
+    public RoutingSessionInfo getSystemRoutingSession(@Nullable String packageName) {
+        return mSystemRoutingSession;
+    }
+
+    public void setSystemRoutingSession(RoutingSessionInfo sessionInfo) {
+        mSystemRoutingSession = sessionInfo;
+    }
+
+    @Implementation
     public List<MediaRoute2Info> getDeselectableRoutes(@NonNull RoutingSessionInfo sessionInfo) {
         return mDeselectableRoutes;
     }
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 54fb647..b9eec6e 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -554,6 +554,7 @@
 
     <!-- Permission required for CTS test - SystemMediaRouter2Test -->
     <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />
+    <uses-permission android:name="android.permission.MODIFY_AUDIO_ROUTING" />
 
     <!-- Permission required for CTS test - CtsRotationResolverServiceDeviceTestCases -->
     <uses-permission android:name="android.permission.MANAGE_ROTATION_RESOLVER" />
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 7d08ad0..303ab46 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -189,7 +189,8 @@
     }
 
     @NonNull
-    public RoutingSessionInfo getSystemSessionInfo() {
+    public RoutingSessionInfo getSystemSessionInfo(
+            @Nullable String packageName, boolean setDeviceRouteSelected) {
         final int uid = Binder.getCallingUid();
         final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
         final boolean hasModifyAudioRoutingPermission = mContext.checkCallingOrSelfPermission(
@@ -203,14 +204,22 @@
                 UserRecord userRecord = getOrCreateUserRecordLocked(userId);
                 List<RoutingSessionInfo> sessionInfos;
                 if (hasModifyAudioRoutingPermission) {
-                    sessionInfos = userRecord.mHandler.mSystemProvider.getSessionInfos();
-                    if (sessionInfos != null && !sessionInfos.isEmpty()) {
-                        systemSessionInfo = sessionInfos.get(0);
+                    if (setDeviceRouteSelected) {
+                        systemSessionInfo = userRecord.mHandler.mSystemProvider
+                                .generateDeviceRouteSelectedSessionInfo(packageName);
                     } else {
-                        Slog.w(TAG, "System provider does not have any session info.");
+                        sessionInfos = userRecord.mHandler.mSystemProvider.getSessionInfos();
+                        if (sessionInfos != null && !sessionInfos.isEmpty()) {
+                            systemSessionInfo = new RoutingSessionInfo.Builder(sessionInfos.get(0))
+                                    .setClientPackageName(packageName).build();
+                        } else {
+                            Slog.w(TAG, "System provider does not have any session info.");
+                        }
                     }
                 } else {
-                    systemSessionInfo = userRecord.mHandler.mSystemProvider.getDefaultSessionInfo();
+                    systemSessionInfo = new RoutingSessionInfo.Builder(
+                            userRecord.mHandler.mSystemProvider.getDefaultSessionInfo())
+                            .setClientPackageName(packageName).build();
                 }
             }
             return systemSessionInfo;
@@ -403,12 +412,12 @@
     ////////////////////////////////////////////////////////////////
 
     @NonNull
-    public List<RoutingSessionInfo> getActiveSessions(IMediaRouter2Manager manager) {
+    public List<RoutingSessionInfo> getRemoteSessions(IMediaRouter2Manager manager) {
         Objects.requireNonNull(manager, "manager must not be null");
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mLock) {
-                return getActiveSessionsLocked(manager);
+                return getRemoteSessionsLocked(manager);
             }
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -861,19 +870,21 @@
     ////   - Should have @NonNull/@Nullable on all arguments
     ////////////////////////////////////////////////////////////
 
-    private List<RoutingSessionInfo> getActiveSessionsLocked(
+    private List<RoutingSessionInfo> getRemoteSessionsLocked(
             @NonNull IMediaRouter2Manager manager) {
         final IBinder binder = manager.asBinder();
         ManagerRecord managerRecord = mAllManagerRecords.get(binder);
 
         if (managerRecord == null) {
-            Slog.w(TAG, "getActiveSessionLocked: Ignoring unknown manager");
+            Slog.w(TAG, "getRemoteSessionLocked: Ignoring unknown manager");
             return Collections.emptyList();
         }
 
         List<RoutingSessionInfo> sessionInfos = new ArrayList<>();
         for (MediaRoute2Provider provider : managerRecord.mUserRecord.mHandler.mRouteProviders) {
-            sessionInfos.addAll(provider.getSessionInfos());
+            if (!provider.mIsSystemRouteProvider) {
+                sessionInfos.addAll(provider.getSessionInfos());
+            }
         }
         return sessionInfos;
     }
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index a57d7db..eb0b2bb 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -25,6 +25,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.media.AudioPlaybackConfiguration;
 import android.media.AudioRoutesInfo;
 import android.media.AudioSystem;
@@ -116,12 +117,17 @@
 
     //TODO: remove this when it's finished
     private final MediaRouter2ServiceImpl mService2;
+    private final String mDefaultAudioRouteId;
+    private final String mBluetoothA2dpRouteId;
 
     public MediaRouterService(Context context) {
         mService2 = new MediaRouter2ServiceImpl(context);
-
         mContext = context;
         Watchdog.getInstance().addMonitor(this);
+        Resources res = context.getResources();
+        mDefaultAudioRouteId = res.getString(com.android.internal.R.string.default_audio_route_id);
+        mBluetoothA2dpRouteId =
+                res.getString(com.android.internal.R.string.bluetooth_a2dp_audio_route_id);
 
         mAudioService = IAudioService.Stub.asInterface(
                 ServiceManager.getService(Context.AUDIO_SERVICE));
@@ -451,7 +457,8 @@
     // Binder call
     @Override
     public RoutingSessionInfo getSystemSessionInfo() {
-        return mService2.getSystemSessionInfo();
+        return mService2.getSystemSessionInfo(
+                null /* packageName */, false /* setDeviceRouteSelected */);
     }
 
     // Binder call
@@ -528,8 +535,29 @@
 
     // Binder call
     @Override
-    public List<RoutingSessionInfo> getActiveSessions(IMediaRouter2Manager manager) {
-        return mService2.getActiveSessions(manager);
+    public List<RoutingSessionInfo> getRemoteSessions(IMediaRouter2Manager manager) {
+        return mService2.getRemoteSessions(manager);
+    }
+
+    // Binder call
+    @Override
+    public RoutingSessionInfo getSystemSessionInfoForPackage(IMediaRouter2Manager manager,
+            String packageName) {
+        final int uid = Binder.getCallingUid();
+        final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
+        boolean setDeviceRouteSelected = false;
+        synchronized (mLock) {
+            UserRecord userRecord = mUserRecords.get(userId);
+            for (ClientRecord clientRecord : userRecord.mClientRecords) {
+                if (TextUtils.equals(clientRecord.mPackageName, packageName)) {
+                    if (mDefaultAudioRouteId.equals(clientRecord.mSelectedRouteId)) {
+                        setDeviceRouteSelected = true;
+                        break;
+                    }
+                }
+            }
+        }
+        return mService2.getSystemSessionInfo(packageName, setDeviceRouteSelected);
     }
 
     // Binder call
@@ -783,7 +811,15 @@
             String routeId, boolean explicit) {
         ClientRecord clientRecord = mAllClientRecords.get(client.asBinder());
         if (clientRecord != null) {
-            final String oldRouteId = clientRecord.mSelectedRouteId;
+            // In order not to handle system routes as a global route,
+            // set the IDs null if system routes.
+            final String oldRouteId = (mDefaultAudioRouteId.equals(clientRecord.mSelectedRouteId)
+                    || mBluetoothA2dpRouteId.equals(clientRecord.mSelectedRouteId))
+                    ? null : clientRecord.mSelectedRouteId;
+            clientRecord.mSelectedRouteId = routeId;
+            if (mDefaultAudioRouteId.equals(routeId) || mBluetoothA2dpRouteId.equals(routeId)) {
+                routeId = null;
+            }
             if (!Objects.equals(routeId, oldRouteId)) {
                 if (DEBUG) {
                     Slog.d(TAG, clientRecord + ": Set selected route, routeId=" + routeId
@@ -791,7 +827,6 @@
                             + ", explicit=" + explicit);
                 }
 
-                clientRecord.mSelectedRouteId = routeId;
                 // Only let the system connect to new global routes for now.
                 // A similar check exists in the display manager for wifi display.
                 if (explicit && clientRecord.mTrusted) {
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index 4f7af94..7878159 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -96,6 +96,9 @@
             mHandler.post(() -> {
                 updateDeviceRoute(newRoutes);
                 notifyProviderState();
+                if (updateSessionInfosIfNeeded()) {
+                    notifySessionInfoUpdated();
+                }
             });
         }
     };
@@ -120,10 +123,7 @@
         // .getInstance returns null if there is no bt adapter available
         mBtRouteProvider = BluetoothRouteProvider.createInstance(context, (routes) -> {
             publishProviderState();
-
-            boolean sessionInfoChanged;
-            sessionInfoChanged = updateSessionInfosIfNeeded();
-            if (sessionInfoChanged) {
+            if (updateSessionInfosIfNeeded()) {
                 notifySessionInfoUpdated();
             }
         });
@@ -237,6 +237,23 @@
         return mDefaultSessionInfo;
     }
 
+    public RoutingSessionInfo generateDeviceRouteSelectedSessionInfo(String packageName) {
+        synchronized (mLock) {
+            if (mSessionInfos.isEmpty()) {
+                return null;
+            }
+            RoutingSessionInfo.Builder builder = new RoutingSessionInfo.Builder(
+                    SYSTEM_SESSION_ID, packageName).setSystemSession(true);
+            builder.addSelectedRoute(mDeviceRoute.getId());
+            if (mBtRouteProvider != null) {
+                for (MediaRoute2Info route : mBtRouteProvider.getAllBluetoothRoutes()) {
+                    builder.addTransferableRoute(route.getId());
+                }
+            }
+            return builder.setProviderId(mUniqueId).build();
+        }
+    }
+
     private void updateDeviceRoute(AudioRoutesInfo newRoutes) {
         int name = R.string.default_audio_route_name;
         int type = TYPE_BUILTIN_SPEAKER;