Snap for 6864616 from d3d88afee78473034e0f23b21743e67c260a6983 to rvc-qpr1-release

Change-Id: I107bc46efdeedeb792cbd03295aa0fd91fb76a3e
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 9260201..de4ae39 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1922,6 +1922,7 @@
             <intent-filter android:priority="1">
                 <action android:name="android.settings.APPLICATION_DEVELOPMENT_SETTINGS" />
                 <action android:name="com.android.settings.APPLICATION_DEVELOPMENT_SETTINGS" />
+                <action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES"/>
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
             <intent-filter>
diff --git a/res/layout/adb_qrcode_scanner_fragment.xml b/res/layout/adb_qrcode_scanner_fragment.xml
index f37c9a6..9a337d9 100644
--- a/res/layout/adb_qrcode_scanner_fragment.xml
+++ b/res/layout/adb_qrcode_scanner_fragment.xml
@@ -19,7 +19,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:theme="@style/GlifV3Theme.Light"
+    android:theme="@style/GlifV3Theme"
     android:icon="@drawable/ic_scan_32dp">
 
     <LinearLayout
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index 64919d9..11a5825 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -18,6 +18,10 @@
 
 import static android.content.Intent.EXTRA_USER;
 import static android.content.Intent.EXTRA_USER_ID;
+import static android.media.MediaRoute2Info.TYPE_GROUP;
+import static android.media.MediaRoute2Info.TYPE_REMOTE_SPEAKER;
+import static android.media.MediaRoute2Info.TYPE_REMOTE_TV;
+import static android.media.MediaRoute2Info.TYPE_UNKNOWN;
 import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
 import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
 
@@ -53,6 +57,8 @@
 import android.graphics.drawable.VectorDrawable;
 import android.hardware.face.FaceManager;
 import android.hardware.fingerprint.FingerprintManager;
+import android.media.MediaRoute2Info;
+import android.media.MediaRouter2Manager;
 import android.net.ConnectivityManager;
 import android.net.LinkProperties;
 import android.net.Network;
@@ -1137,4 +1143,31 @@
         drawable.draw(canvas);
         return roundedBitmap;
     }
+
+    /**
+     * Returns {@code true} if needed to disable media output, otherwise returns {@code false}.
+     */
+    public static boolean isMediaOutputDisabled(
+            MediaRouter2Manager router2Manager, String packageName) {
+        boolean isMediaOutputDisabled = false;
+        if (!TextUtils.isEmpty(packageName)) {
+            final List<MediaRoute2Info> infos = router2Manager.getAvailableRoutes(packageName);
+            if (infos.size() == 1) {
+                final MediaRoute2Info info = infos.get(0);
+                final int deviceType = info.getType();
+                switch (deviceType) {
+                    case TYPE_UNKNOWN:
+                    case TYPE_REMOTE_TV:
+                    case TYPE_REMOTE_SPEAKER:
+                    case TYPE_GROUP:
+                        isMediaOutputDisabled = true;
+                        break;
+                    default:
+                        isMediaOutputDisabled = false;
+                        break;
+                }
+            }
+        }
+        return isMediaOutputDisabled;
+    }
 }
diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
index f2d60f1..8eb5c4f 100644
--- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
+++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.development;
 
+import static android.service.quicksettings.TileService.ACTION_QS_TILE_PREFERENCES;
+
 import android.app.Activity;
 import android.app.settings.SettingsEnums;
 import android.bluetooth.BluetoothA2dp;
@@ -23,12 +25,14 @@
 import android.bluetooth.BluetoothCodecStatus;
 import android.bluetooth.BluetoothProfile;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.Bundle;
 import android.os.SystemProperties;
 import android.os.UserManager;
+import android.text.TextUtils;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -41,6 +45,7 @@
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
 import com.android.settings.Utils;
+import com.android.settings.core.SubSettingLauncher;
 import com.android.settings.dashboard.RestrictedDashboardFragment;
 import com.android.settings.development.autofill.AutofillLoggingLevelPreferenceController;
 import com.android.settings.development.autofill.AutofillResetOptionsPreferenceController;
@@ -52,6 +57,7 @@
 import com.android.settings.development.bluetooth.BluetoothHDAudioPreferenceController;
 import com.android.settings.development.bluetooth.BluetoothQualityDialogPreferenceController;
 import com.android.settings.development.bluetooth.BluetoothSampleRateDialogPreferenceController;
+import com.android.settings.development.qstile.DevelopmentTiles;
 import com.android.settings.development.storage.SharedDataPreferenceController;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.widget.SwitchBar;
@@ -199,11 +205,42 @@
         // Restore UI state based on whether developer options is enabled
         if (DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(getContext())) {
             enableDeveloperOptions();
+            handleQsTileLongPressActionIfAny();
         } else {
             disableDeveloperOptions();
         }
     }
 
+    /**
+     * Long-pressing a developer options quick settings tile will by default (see
+     * QS_TILE_PREFERENCES in the manifest) take you to the developer options page.
+     * Some tiles may want to go into their own page within the developer options.
+     */
+    private void handleQsTileLongPressActionIfAny() {
+        Intent intent = getActivity().getIntent();
+        if (intent == null || !TextUtils.equals(ACTION_QS_TILE_PREFERENCES, intent.getAction())) {
+            return;
+        }
+
+        Log.d(TAG, "Developer options started from qstile long-press");
+        final ComponentName componentName = (ComponentName) intent.getParcelableExtra(
+                Intent.EXTRA_COMPONENT_NAME);
+        if (componentName == null) {
+            return;
+        }
+
+        if (DevelopmentTiles.WirelessDebugging.class.getName().equals(
+                componentName.getClassName()) && getDevelopmentOptionsController(
+                    WirelessDebuggingPreferenceController.class).isAvailable()) {
+            Log.d(TAG, "Long press from wireless debugging qstile");
+            new SubSettingLauncher(getContext())
+                    .setDestination(WirelessDebuggingFragment.class.getName())
+                    .setSourceMetricsCategory(SettingsEnums.SETTINGS_ADB_WIRELESS)
+                    .launch();
+        }
+        // Add other qstiles here
+    }
+
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
index 0075529..fc39b59 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
@@ -243,7 +243,7 @@
         final MetricsFeatureProvider metricsFeatureProvider =
                 FeatureFactory.getFactory(mContext).getMetricsFeatureProvider();
 
-        //navigate back to the homepage, screen rotate or after card dismissal
+        // navigate back to the homepage, screen rotate or after card dismissal
         if (!mIsFirstLaunch) {
             onContextualCardUpdated(cardsToKeep.stream()
                     .collect(groupingBy(ContextualCard::getCardType)));
@@ -266,8 +266,17 @@
                     SettingsEnums.ACTION_CONTEXTUAL_CARD_LOAD_TIMEOUT,
                     SettingsEnums.SETTINGS_HOMEPAGE,
                     null /* key */, (int) loadTime /* value */);
+
+            // display a card on timeout if the one-card space is pre-allocated
+            if (!cards.isEmpty() && ContextualCardLoader.getCardCount(mContext) == 1) {
+                onContextualCardUpdated(cards.stream()
+                        .collect(groupingBy(ContextualCard::getCardType)));
+                metricsFeatureProvider.action(mContext,
+                        SettingsEnums.ACTION_CONTEXTUAL_CARD_SHOW,
+                        ContextualCardLogUtils.buildCardListLog(cards));
+            }
         }
-        //only log homepage display upon a fresh launch
+        // only log homepage display upon a fresh launch
         final long totalTime = System.currentTimeMillis() - mStartTime;
         metricsFeatureProvider.action(mContext,
                 SettingsEnums.ACTION_CONTEXTUAL_HOME_SHOW, (int) totalTime);
diff --git a/src/com/android/settings/media/MediaOutputIndicatorSlice.java b/src/com/android/settings/media/MediaOutputIndicatorSlice.java
index 17c8ef8..305c7df 100644
--- a/src/com/android/settings/media/MediaOutputIndicatorSlice.java
+++ b/src/com/android/settings/media/MediaOutputIndicatorSlice.java
@@ -27,6 +27,7 @@
 import android.graphics.Bitmap;
 import android.media.session.MediaController;
 import android.net.Uri;
+import android.text.TextUtils;
 
 import androidx.annotation.VisibleForTesting;
 import androidx.core.graphics.drawable.IconCompat;
@@ -62,8 +63,12 @@
                 com.android.internal.R.drawable.ic_settings_bluetooth);
         final CharSequence title = mContext.getString(R.string.media_output_label_title,
                 Utils.getApplicationLabel(mContext, getWorker().getPackageName()));
+        final int requestCode = TextUtils.isEmpty(getWorker().getPackageName())
+                ? 0
+                : getWorker().getPackageName().hashCode();
         final PendingIntent primaryActionIntent = PendingIntent.getActivity(mContext,
-                0 /* requestCode */, getMediaOutputSliceIntent(), FLAG_UPDATE_CURRENT);
+                requestCode,
+                getMediaOutputSliceIntent(), FLAG_UPDATE_CURRENT);
         final SliceAction primarySliceAction = SliceAction.createDeeplink(
                 primaryActionIntent, icon, ListBuilder.ICON_IMAGE, title);
         @ColorInt final int color = Utils.getColorAccentDefaultColor(mContext);
diff --git a/src/com/android/settings/media/MediaOutputSlice.java b/src/com/android/settings/media/MediaOutputSlice.java
index b9d43b4..6611e8d 100644
--- a/src/com/android/settings/media/MediaOutputSlice.java
+++ b/src/com/android/settings/media/MediaOutputSlice.java
@@ -257,9 +257,11 @@
                 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                 .putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME,
                         getWorker().getPackageName());
-
+        final int requestCode = TextUtils.isEmpty(getWorker().getPackageName())
+                ? 0
+                : getWorker().getPackageName().hashCode();
         return SliceAction.createDeeplink(
-                PendingIntent.getActivity(mContext, 0 /* requestCode */, intent, 0 /* flags */),
+                PendingIntent.getActivity(mContext, requestCode, intent, 0 /* flags */),
                 IconCompat.createWithResource(mContext, R.drawable.ic_add_blue_24dp),
                 ListBuilder.ICON_IMAGE,
                 mContext.getText(R.string.add));
diff --git a/src/com/android/settings/media/RemoteMediaSlice.java b/src/com/android/settings/media/RemoteMediaSlice.java
index 510a60e..4198269 100644
--- a/src/com/android/settings/media/RemoteMediaSlice.java
+++ b/src/com/android/settings/media/RemoteMediaSlice.java
@@ -17,6 +17,7 @@
 package com.android.settings.media;
 
 import static android.app.slice.Slice.EXTRA_RANGE_VALUE;
+import static android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE;
 
 import static com.android.settings.slices.CustomSliceRegistry.REMOTE_MEDIA_SLICE_URI;
 
@@ -24,11 +25,15 @@
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Bitmap;
+import android.media.MediaRouter2Manager;
 import android.media.RoutingSessionInfo;
 import android.net.Uri;
+import android.text.SpannableString;
 import android.text.TextUtils;
+import android.text.style.ForegroundColorSpan;
 import android.util.Log;
 
+import androidx.annotation.VisibleForTesting;
 import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.Slice;
 import androidx.slice.builders.ListBuilder;
@@ -59,6 +64,9 @@
 
     private MediaDeviceUpdateWorker mWorker;
 
+    @VisibleForTesting
+    MediaRouter2Manager mRouterManager;
+
     public RemoteMediaSlice(Context context) {
         mContext = context;
     }
@@ -80,6 +88,9 @@
             Log.e(TAG, "Unable to get the slice worker.");
             return listBuilder.build();
         }
+        if (mRouterManager == null) {
+            mRouterManager = MediaRouter2Manager.getInstance(mContext);
+        }
         // Only displaying remote devices
         final List<RoutingSessionInfo> infos = getWorker().getActiveRemoteMediaDevice();
         if (infos.isEmpty()) {
@@ -98,8 +109,10 @@
                         + maxVolume);
                 continue;
             }
+            final CharSequence appName = Utils.getApplicationLabel(
+                    mContext, info.getClientPackageName());
             final CharSequence outputTitle = mContext.getString(R.string.media_output_label_title,
-                    Utils.getApplicationLabel(mContext, info.getClientPackageName()));
+                    appName);
             listBuilder.addInputRange(new InputRangeBuilder()
                     .setTitleItem(icon, ListBuilder.ICON_IMAGE)
                     .setTitle(castVolume)
@@ -107,11 +120,21 @@
                     .setPrimaryAction(getSoundSettingAction(castVolume, icon, info.getId()))
                     .setMax(maxVolume)
                     .setValue(info.getVolume()));
+
+            final boolean isMediaOutputDisabled =
+                    Utils.isMediaOutputDisabled(mRouterManager, info.getClientPackageName());
+            final SpannableString spannableTitle = new SpannableString(
+                    TextUtils.isEmpty(appName) ? "" : appName);
+            spannableTitle.setSpan(new ForegroundColorSpan(
+                            Utils.getColorAttrDefaultColor(
+                                    mContext, android.R.attr.textColorSecondary)), 0,
+                    spannableTitle.length(), SPAN_EXCLUSIVE_EXCLUSIVE);
             listBuilder.addRow(new ListBuilder.RowBuilder()
-                    .setTitle(outputTitle)
+                    .setTitle(isMediaOutputDisabled ? spannableTitle : outputTitle)
                     .setSubtitle(info.getName())
                     .setTitleItem(emptyIcon, ListBuilder.ICON_IMAGE)
-                    .setPrimaryAction(getMediaOutputSliceAction(info.getClientPackageName())));
+                    .setPrimaryAction(getMediaOutputSliceAction(
+                            info.getClientPackageName(), isMediaOutputDisabled)));
         }
         return listBuilder.build();
     }
@@ -144,15 +167,19 @@
         return primarySliceAction;
     }
 
-    private SliceAction getMediaOutputSliceAction(String packageName) {
+    private SliceAction getMediaOutputSliceAction(
+            String packageName, boolean isMediaOutputDisabled) {
         final Intent intent = new Intent()
-                .setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT)
+                .setAction(isMediaOutputDisabled
+                        ? ""
+                        : MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT)
                 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                 .putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME, packageName);
         final IconCompat icon = IconCompat.createWithResource(mContext,
                 R.drawable.ic_volume_remote);
+        final int requestCode = TextUtils.isEmpty(packageName) ? 0 : packageName.hashCode();
         final PendingIntent primaryActionIntent = PendingIntent.getActivity(mContext,
-                0 /* requestCode */, intent, 0 /* flags */);
+                requestCode, intent, 0 /* flags */);
         final SliceAction primarySliceAction = SliceAction.createDeeplink(
                 primaryActionIntent, icon, ListBuilder.ICON_IMAGE,
                 mContext.getString(R.string.media_output_label_title,
diff --git a/src/com/android/settings/network/telephony/NrDisabledInDsdsFooterPreferenceController.java b/src/com/android/settings/network/telephony/NrDisabledInDsdsFooterPreferenceController.java
index 3911fb8..78dfe51 100644
--- a/src/com/android/settings/network/telephony/NrDisabledInDsdsFooterPreferenceController.java
+++ b/src/com/android/settings/network/telephony/NrDisabledInDsdsFooterPreferenceController.java
@@ -55,6 +55,13 @@
         super.updateState(preference);
 
         if (preference != null) {
+            // This is necessary to ensure that setting the title to the spannable string returned
+            // by getFooterText will be accepted.  Internally, setTitle does an equality check on
+            // the spannable string being set to the text already set on the preference.  That
+            // equality check apparently only takes into account the raw text and not and spannables
+            // that are part of the text.  So we clear the title before applying the spannable
+            // footer to ensure it is accepted.
+            preference.setTitle("");
             preference.setTitle(getFooterText());
         }
     }
diff --git a/src/com/android/settings/notification/RemoteVolumeGroupController.java b/src/com/android/settings/notification/RemoteVolumeGroupController.java
index 6d3c96d..bb62a56 100644
--- a/src/com/android/settings/notification/RemoteVolumeGroupController.java
+++ b/src/com/android/settings/notification/RemoteVolumeGroupController.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.media.MediaRouter2Manager;
 import android.media.RoutingSessionInfo;
 import android.text.TextUtils;
 
@@ -57,6 +58,8 @@
 
     @VisibleForTesting
     LocalMediaManager mLocalMediaManager;
+    @VisibleForTesting
+    MediaRouter2Manager mRouterManager;
 
     public RemoteVolumeGroupController(Context context, String preferenceKey) {
         super(context, preferenceKey);
@@ -65,6 +68,7 @@
             mLocalMediaManager.registerCallback(this);
             mLocalMediaManager.startScan();
         }
+        mRouterManager = MediaRouter2Manager.getInstance(context);
     }
 
     @Override
@@ -111,8 +115,10 @@
             if (mPreferenceCategory.findPreference(info.getId()) != null) {
                 continue;
             }
+            final CharSequence appName = Utils.getApplicationLabel(
+                    mContext, info.getClientPackageName());
             final CharSequence outputTitle = mContext.getString(R.string.media_output_label_title,
-                    Utils.getApplicationLabel(mContext, info.getClientPackageName()));
+                    appName);
             // Add slider
             final RemoteVolumeSeekBarPreference seekBarPreference =
                     new RemoteVolumeSeekBarPreference(mContext);
@@ -125,10 +131,13 @@
             seekBarPreference.setIcon(R.drawable.ic_volume_remote);
             mPreferenceCategory.addPreference(seekBarPreference);
             // Add output indicator
+            final boolean isMediaOutputDisabled = Utils.isMediaOutputDisabled(
+                    mRouterManager, info.getClientPackageName());
             final Preference preference = new Preference(mContext);
             preference.setKey(SWITCHER_PREFIX + info.getId());
-            preference.setTitle(outputTitle);
+            preference.setTitle(isMediaOutputDisabled ? appName : outputTitle);
             preference.setSummary(info.getName());
+            preference.setEnabled(!isMediaOutputDisabled);
             mPreferenceCategory.addPreference(preference);
         }
     }
diff --git a/tests/robotests/src/com/android/settings/UtilsTest.java b/tests/robotests/src/com/android/settings/UtilsTest.java
index 2aa8418..303fb1b 100644
--- a/tests/robotests/src/com/android/settings/UtilsTest.java
+++ b/tests/robotests/src/com/android/settings/UtilsTest.java
@@ -40,6 +40,8 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.VectorDrawable;
+import android.media.MediaRoute2Info;
+import android.media.MediaRouter2Manager;
 import android.net.ConnectivityManager;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
@@ -299,4 +301,33 @@
 
         assertThat(Utils.isSettingsIntelligence(mContext)).isFalse();
     }
+
+    @Test
+    public void isMediaOutputDisabled_infosSizeEqual1_returnsTrue() {
+        final MediaRouter2Manager router2Manager = mock(MediaRouter2Manager.class);
+        final MediaRoute2Info info = mock(MediaRoute2Info.class);
+        final List<MediaRoute2Info> infos = new ArrayList<>();
+        infos.add(info);
+
+        when(router2Manager.getAvailableRoutes(anyString())).thenReturn(infos);
+        when(info.getType()).thenReturn(0);
+
+        assertThat(Utils.isMediaOutputDisabled(router2Manager, "test")).isTrue();
+    }
+
+    @Test
+    public void isMediaOutputDisabled_infosSizeOverThan1_returnsFalse() {
+        final MediaRouter2Manager router2Manager = mock(MediaRouter2Manager.class);
+        final MediaRoute2Info info = mock(MediaRoute2Info.class);
+        final MediaRoute2Info info2 = mock(MediaRoute2Info.class);
+        final List<MediaRoute2Info> infos = new ArrayList<>();
+        infos.add(info);
+        infos.add(info2);
+
+        when(router2Manager.getAvailableRoutes(anyString())).thenReturn(infos);
+        when(info.getType()).thenReturn(0);
+        when(info2.getType()).thenReturn(0);
+
+        assertThat(Utils.isMediaOutputDisabled(router2Manager, "test")).isFalse();
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java
index 69333d7..96d0c3b 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java
@@ -16,6 +16,7 @@
 
 package com.android.settings.homepage.contextualcards;
 
+import static com.android.settings.homepage.contextualcards.ContextualCardLoader.CONTEXTUAL_CARD_COUNT;
 import static com.android.settings.homepage.contextualcards.ContextualCardManager.KEY_CONTEXTUAL_CARDS;
 import static com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer.VIEW_TYPE_FULL_WIDTH;
 import static com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer.VIEW_TYPE_HALF_WIDTH;
@@ -307,7 +308,7 @@
     }
 
     @Test
-    public void onFinishCardLoading_fastLoad_shouldCallOnContextualCardUpdated() {
+    public void onFinishCardLoading_fastLoad_shouldUpdateContextualCard() {
         mManager.mStartTime = System.currentTimeMillis();
         final ContextualCardManager manager = spy(mManager);
         doNothing().when(manager).onContextualCardUpdated(anyMap());
@@ -318,7 +319,7 @@
     }
 
     @Test
-    public void onFinishCardLoading_slowLoad_shouldSkipOnContextualCardUpdated() {
+    public void onFinishCardLoading_slowLoadAndNoCard_shouldNotUpdateContextualCard() {
         mManager.mStartTime = 0;
         final ContextualCardManager manager = spy(mManager);
         doNothing().when(manager).onContextualCardUpdated(anyMap());
@@ -329,6 +330,30 @@
     }
 
     @Test
+    public void onFinishCardLoading_slowLoadAndNotPreAllocateSpace_shouldNotUpdateContextualCard() {
+        mManager.mStartTime = 0;
+        Settings.Global.putInt(mContext.getContentResolver(), CONTEXTUAL_CARD_COUNT, 3);
+        final ContextualCardManager manager = spy(mManager);
+        doNothing().when(manager).onContextualCardUpdated(anyMap());
+
+        manager.onFinishCardLoading(Arrays.asList(buildContextualCard(TEST_SLICE_URI)));
+
+        verify(manager, never()).onContextualCardUpdated(anyMap());
+    }
+
+    @Test
+    public void onFinishCardLoading_slowLoadAndPreAllocateSpace_shouldUpdateContextualCard() {
+        mManager.mStartTime = 0;
+        Settings.Global.putInt(mContext.getContentResolver(), CONTEXTUAL_CARD_COUNT, 1);
+        final ContextualCardManager manager = spy(mManager);
+        doNothing().when(manager).onContextualCardUpdated(anyMap());
+
+        manager.onFinishCardLoading(Arrays.asList(buildContextualCard(TEST_SLICE_URI)));
+
+        verify(manager).onContextualCardUpdated(anyMap());
+    }
+
+    @Test
     public void onFinishCardLoading_newLaunch_twoLoadedCards_shouldShowTwoCards() {
         mManager.mStartTime = System.currentTimeMillis();
         mManager.setListener(mListener);
diff --git a/tests/robotests/src/com/android/settings/media/RemoteMediaSliceTest.java b/tests/robotests/src/com/android/settings/media/RemoteMediaSliceTest.java
index 017faa5..e0e6e50 100644
--- a/tests/robotests/src/com/android/settings/media/RemoteMediaSliceTest.java
+++ b/tests/robotests/src/com/android/settings/media/RemoteMediaSliceTest.java
@@ -32,6 +32,7 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.media.MediaRouter2Manager;
 import android.media.RoutingSessionInfo;
 import android.net.Uri;
 
@@ -87,6 +88,7 @@
         SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
 
         mRemoteMediaSlice = new RemoteMediaSlice(mContext);
+        mRemoteMediaSlice.mRouterManager = mock(MediaRouter2Manager.class);
         sMediaDeviceUpdateWorker = spy(new MediaDeviceUpdateWorker(mContext,
                 REMOTE_MEDIA_SLICE_URI));
         sMediaDeviceUpdateWorker.mLocalMediaManager = mLocalMediaManager;
diff --git a/tests/robotests/src/com/android/settings/notification/RemoteVolumeGroupControllerTest.java b/tests/robotests/src/com/android/settings/notification/RemoteVolumeGroupControllerTest.java
index e824505..09a40a7 100644
--- a/tests/robotests/src/com/android/settings/notification/RemoteVolumeGroupControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/RemoteVolumeGroupControllerTest.java
@@ -30,6 +30,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageStats;
+import android.media.MediaRouter2Manager;
 import android.media.RoutingSessionInfo;
 
 import androidx.preference.Preference;
@@ -94,6 +95,7 @@
         mContext = RuntimeEnvironment.application;
         mController = new RemoteVolumeGroupController(mContext, KEY_REMOTE_VOLUME_GROUP);
         mController.mLocalMediaManager = mLocalMediaManager;
+        mController.mRouterManager = mock(MediaRouter2Manager.class);
         mPreferenceCategory = spy(new PreferenceCategory(mContext));
         mPreferenceCategory.setKey(mController.getPreferenceKey());