Merge "Add missing required permissions for Settings" into main
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 25aa508..19e774c 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -5140,9 +5140,9 @@
         <activity
             android:name=".privatespace.PrivateSpaceAuthenticationActivity"
             android:theme="@*android:style/Theme.DeviceDefault.Settings.Dialog.NoActionBar"
-            android:exported="true">
+            android:exported="false">
             <intent-filter>
-                <action android:name="com.android.settings.action.PRIVATE_SPACE_SETUP_FLOW" />
+                <action android:name="com.android.settings.action.OPEN_PRIVATE_SPACE_SETTINGS" />
                 <category android:name="android.intent.category.DEFAULT"/>
             </intent-filter>
         </activity>
@@ -5154,6 +5154,14 @@
                   android:exported="false">
         </activity>
 
+        <receiver android:name=".privatespace.PrivateSpaceBroadcastReceiver"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.PRE_BOOT_COMPLETED"/>
+                <action android:name="android.intent.action.BOOT_COMPLETED"/>
+            </intent-filter>
+        </receiver>
+
         <activity-alias android:name="UsageStatsActivity"
                         android:exported="true"
                         android:label="@string/testing_usage_stats"
diff --git a/res/layout/preference_progress_category.xml b/res/layout/preference_progress_category.xml
index b04f5be..192f601 100644
--- a/res/layout/preference_progress_category.xml
+++ b/res/layout/preference_progress_category.xml
@@ -54,6 +54,7 @@
     <ProgressBar
         android:id="@+id/scanning_progress"
         style="?android:attr/progressBarStyleSmallTitle"
+        android:focusable="true"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
diff --git a/res/xml/display_settings.xml b/res/xml/display_settings.xml
index a59b30b..0c6d673 100644
--- a/res/xml/display_settings.xml
+++ b/res/xml/display_settings.xml
@@ -36,7 +36,10 @@
             android:key="auto_brightness_entry"
             android:title="@string/auto_brightness_title"
             android:fragment="com.android.settings.display.AutoBrightnessSettings"
-            settings:controller="com.android.settings.display.AutoBrightnessPreferenceController"/>
+            settings:useAdminDisabledSummary="true"
+            settings:userRestriction="no_config_brightness"
+            settings:controller="com.android.settings.display.AutoBrightnessPreferenceController" />
+
         <SwitchPreferenceCompat
             android:key="even_dimmer_activated"
             android:title="@string/even_dimmer_display_title"
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index 7d1e02d..b44d3c7 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -1385,7 +1385,7 @@
      * @param activity the Activity need to setup the edge to edge feature.
      */
     public static void setupEdgeToEdge(@NonNull FragmentActivity activity) {
-        if (com.android.window.flags.Flags.edgeToEdgeByDefault()) {
+        if (com.android.window.flags.Flags.enforceEdgeToEdge()) {
             ViewCompat.setOnApplyWindowInsetsListener(activity.findViewById(android.R.id.content),
                     (v, windowInsets) -> {
                         Insets insets = windowInsets.getInsets(
diff --git a/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java
index 8250f70..0ee3986 100644
--- a/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java
+++ b/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java
@@ -136,12 +136,8 @@
     @Override
     public boolean onPreferenceClick(Preference preference) {
         mMetricsFeatureProvider.logClickedPreference(preference, mMetricsCategory);
-        final CachedBluetoothDevice device =
-                ((BluetoothDevicePreference) preference).getBluetoothDevice();
-        FeatureFactory.getFeatureFactory()
-                .getAudioSharingFeatureProvider()
-                .handleMediaDeviceOnClick(mLocalManager);
-        return device.setActive();
+        mDevicePreferenceCallback.onDeviceClick(preference);
+        return true;
     }
 
     @Override
diff --git a/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupController.java b/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupController.java
index 0535d15..56ef4b0 100644
--- a/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupController.java
+++ b/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupController.java
@@ -35,6 +35,7 @@
 import com.android.settings.R;
 import com.android.settings.accessibility.HearingAidUtils;
 import com.android.settings.bluetooth.AvailableMediaBluetoothDeviceUpdater;
+import com.android.settings.bluetooth.BluetoothDevicePreference;
 import com.android.settings.bluetooth.BluetoothDeviceUpdater;
 import com.android.settings.bluetooth.Utils;
 import com.android.settings.core.BasePreferenceController;
@@ -150,6 +151,13 @@
         }
     }
 
+    @Override
+    public void onDeviceClick(Preference preference) {
+        final CachedBluetoothDevice cachedDevice =
+                ((BluetoothDevicePreference) preference).getBluetoothDevice();
+        cachedDevice.setActive();
+    }
+
     public void init(DashboardFragment fragment) {
         mFragmentManager = fragment.getParentFragmentManager();
         mBluetoothDeviceUpdater =
diff --git a/src/com/android/settings/connecteddevice/DevicePreferenceCallback.java b/src/com/android/settings/connecteddevice/DevicePreferenceCallback.java
index 7ee2063..c91e2a0 100644
--- a/src/com/android/settings/connecteddevice/DevicePreferenceCallback.java
+++ b/src/com/android/settings/connecteddevice/DevicePreferenceCallback.java
@@ -18,19 +18,26 @@
 
 import androidx.preference.Preference;
 
-/**
- * Callback to add or remove {@link Preference} in device group.
- */
+/** Callback to add or remove {@link Preference} in device group. */
 public interface DevicePreferenceCallback {
     /**
      * Called when a device(i.e. bluetooth, usb) is added
+     *
      * @param preference present the device
      */
     void onDeviceAdded(Preference preference);
 
     /**
      * Called when a device(i.e. bluetooth, usb) is removed
+     *
      * @param preference present the device
      */
     void onDeviceRemoved(Preference preference);
+
+    /**
+     * Called when a device(i.e. bluetooth, usb) is click
+     *
+     * @param preference present the device
+     */
+    default void onDeviceClick(Preference preference) {}
 }
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingFeatureProvider.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingFeatureProvider.java
index 9fe4d50..50812e9 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingFeatureProvider.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingFeatureProvider.java
@@ -50,7 +50,4 @@
      */
     boolean isAudioSharingFilterMatched(
             @NonNull CachedBluetoothDevice cachedDevice, LocalBluetoothManager localBtManager);
-
-    /** Handle preference onClick in "Media devices" section. */
-    void handleMediaDeviceOnClick(LocalBluetoothManager localBtManager);
 }
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingFeatureProviderImpl.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingFeatureProviderImpl.java
index 259ed7a..96200db 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingFeatureProviderImpl.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingFeatureProviderImpl.java
@@ -52,7 +52,4 @@
             @NonNull CachedBluetoothDevice cachedDevice, LocalBluetoothManager localBtManager) {
         return false;
     }
-
-    @Override
-    public void handleMediaDeviceOnClick(LocalBluetoothManager localBtManager) {}
 }
diff --git a/src/com/android/settings/display/AutoBrightnessPreferenceController.java b/src/com/android/settings/display/AutoBrightnessPreferenceController.java
index d925de3..bf21183 100644
--- a/src/com/android/settings/display/AutoBrightnessPreferenceController.java
+++ b/src/com/android/settings/display/AutoBrightnessPreferenceController.java
@@ -18,11 +18,15 @@
 import static android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
 
 import android.content.Context;
+import android.os.Process;
+import android.os.UserManager;
 import android.provider.Settings;
 
+import androidx.preference.Preference;
+
 import com.android.settings.R;
 import com.android.settings.core.TogglePreferenceController;
-
+import com.android.settingslib.PrimarySwitchPreference;
 
 public class AutoBrightnessPreferenceController extends TogglePreferenceController {
 
@@ -56,6 +60,17 @@
     }
 
     @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+        PrimarySwitchPreference pref = (PrimarySwitchPreference) preference;
+        if (pref.isEnabled() && UserManager.get(mContext).hasBaseUserRestriction(
+                UserManager.DISALLOW_CONFIG_BRIGHTNESS, Process.myUserHandle())) {
+            pref.setEnabled(false);
+            pref.setSwitchEnabled(false);
+        }
+    }
+
+    @Override
     public CharSequence getSummary() {
         return mContext.getText(isChecked()
                 ? R.string.auto_brightness_summary_on
diff --git a/src/com/android/settings/network/MobileNetworkRepository.java b/src/com/android/settings/network/MobileNetworkRepository.java
index 381f3c1..672e2ed 100644
--- a/src/com/android/settings/network/MobileNetworkRepository.java
+++ b/src/com/android/settings/network/MobileNetworkRepository.java
@@ -245,7 +245,11 @@
     }
 
     private void createTelephonyManagerBySubId(int subId) {
-        if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+        if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID
+                || mTelephonyCallbackMap.containsKey(subId)) {
+            if (DEBUG) {
+                Log.d(TAG, "createTelephonyManagerBySubId: directly return for subId = " + subId);
+            }
             return;
         }
         PhoneCallStateTelephonyCallback
diff --git a/src/com/android/settings/privatespace/PrivateSpaceAuthenticationActivity.java b/src/com/android/settings/privatespace/PrivateSpaceAuthenticationActivity.java
index 53d6b22..f61f7bb 100644
--- a/src/com/android/settings/privatespace/PrivateSpaceAuthenticationActivity.java
+++ b/src/com/android/settings/privatespace/PrivateSpaceAuthenticationActivity.java
@@ -50,7 +50,7 @@
  * This class represents an activity responsible for user authentication before starting the private
  * space setup flow or accessing the private space settings page if already created. Also prompts
  * user to set a device lock if not set with an alert dialog. This can be launched using the intent
- * com.android.settings.action.PRIVATE_SPACE_SETUP_FLOW.
+ * com.android.settings.action.OPEN_PRIVATE_SPACE_SETTINGS.
  */
 public class PrivateSpaceAuthenticationActivity extends FragmentActivity {
     private static final String TAG = "PrivateSpaceAuthCheck";
diff --git a/src/com/android/settings/privatespace/PrivateSpaceBroadcastReceiver.java b/src/com/android/settings/privatespace/PrivateSpaceBroadcastReceiver.java
new file mode 100644
index 0000000..4c59ab9
--- /dev/null
+++ b/src/com/android/settings/privatespace/PrivateSpaceBroadcastReceiver.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.privatespace;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.UserManager;
+import android.util.Log;
+
+/** Broadcast receiver for enabling/disabling Private Space Root Activity. */
+public class PrivateSpaceBroadcastReceiver extends BroadcastReceiver {
+
+    private static final String TAG = "PrivateSpaceBroadcastReceiver";
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        if (android.multiuser.Flags.enablePrivateSpaceFeatures()
+                && android.multiuser.Flags.blockPrivateSpaceCreation()) {
+            Log.d("Here", "Intent: " + intent.getAction());
+            PrivateSpaceMaintainer privateSpaceMaintainer =
+                    PrivateSpaceMaintainer.getInstance(context);
+            // Disable the PrivateSpaceAuthenticationActivity when
+            // -Private Profile is not present and
+            // -Private Profile cannot be added.
+            final int enableState = privateSpaceMaintainer.doesPrivateSpaceExist()
+                    || context.getSystemService(UserManager.class).canAddPrivateProfile()
+                    ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+                    : PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+            ComponentName privateSpaceAuth = new ComponentName(context,
+                    PrivateSpaceAuthenticationActivity.class);
+            Log.d(TAG, "Setting component " + privateSpaceAuth + " state: " + enableState);
+            context.getPackageManager().setComponentEnabledSetting(
+                    privateSpaceAuth,
+                    enableState,
+                    PackageManager.DONT_KILL_APP);
+        }
+    }
+}
diff --git a/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java b/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java
index 3fb9b15..6623516 100644
--- a/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java
+++ b/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java
@@ -155,7 +155,7 @@
             return true;
         }
 
-        List<UserInfo> users = mUserManager.getProfiles(0);
+        List<UserInfo> users = mUserManager.getProfiles(mContext.getUserId());
         for (UserInfo user : users) {
             if (user.isPrivateProfile()) {
                 mUserHandle = user.getUserHandle();
diff --git a/src/com/android/settings/privatespace/PrivateSpaceSafetySource.java b/src/com/android/settings/privatespace/PrivateSpaceSafetySource.java
index 4e1741a..3272f12 100644
--- a/src/com/android/settings/privatespace/PrivateSpaceSafetySource.java
+++ b/src/com/android/settings/privatespace/PrivateSpaceSafetySource.java
@@ -44,11 +44,27 @@
             return;
         }
 
-        // Check the profile type - we don't want to show this for anything other than primary user.
         UserManager userManager = context.getSystemService(UserManager.class);
-        if (userManager != null && !userManager.isMainUser()) {
-            Log.i(TAG, "setSafetySourceData not main user");
-            return;
+        PrivateSpaceMaintainer privateSpaceMaintainer =
+                PrivateSpaceMaintainer.getInstance(context);
+        if (android.multiuser.Flags.enablePrivateSpaceFeatures()
+                && android.multiuser.Flags.blockPrivateSpaceCreation()) {
+            // Do not add the entry point when
+            // -Private Profile is not present and
+            // -Private Profile cannot be added.
+            if (!privateSpaceMaintainer.doesPrivateSpaceExist()
+                    && userManager != null
+                    && !userManager.canAddPrivateProfile()) {
+                Log.i(TAG, "Private Space not allowed for user " + context.getUser());
+                return;
+            }
+        } else {
+            // Check the profile type - we don't want to show this for anything other than primary
+            // user.
+            if (userManager != null && !userManager.isMainUser()) {
+                Log.i(TAG, "setSafetySourceData not main user");
+                return;
+            }
         }
 
         if (!Flags.allowPrivateProfile()
diff --git a/src/com/android/settings/spa/network/SimOnboardingLabelSim.kt b/src/com/android/settings/spa/network/SimOnboardingLabelSim.kt
index 94e4a88..f702894 100644
--- a/src/com/android/settings/spa/network/SimOnboardingLabelSim.kt
+++ b/src/com/android/settings/spa/network/SimOnboardingLabelSim.kt
@@ -56,12 +56,12 @@
         imageVector = Icons.Outlined.SignalCellularAlt,
         title = stringResource(R.string.sim_onboarding_label_sim_title),
         actionButton = BottomAppBarButton(
-            stringResource(R.string.sim_onboarding_next),
-            nextAction
+            text = stringResource(R.string.sim_onboarding_next),
+            onClick = nextAction
         ),
         dismissButton = BottomAppBarButton(
-            stringResource(R.string.cancel),
-            cancelAction
+            text = stringResource(R.string.cancel),
+            onClick = cancelAction
         ),
     ) {
         LabelSimBody(onboardingService)
diff --git a/src/com/android/settings/spa/network/SimOnboardingPrimarySim.kt b/src/com/android/settings/spa/network/SimOnboardingPrimarySim.kt
index 4fad332..0306aad 100644
--- a/src/com/android/settings/spa/network/SimOnboardingPrimarySim.kt
+++ b/src/com/android/settings/spa/network/SimOnboardingPrimarySim.kt
@@ -59,12 +59,12 @@
         imageVector = Icons.Outlined.SignalCellularAlt,
         title = stringResource(id = R.string.sim_onboarding_primary_sim_title),
         actionButton = BottomAppBarButton(
-            stringResource(id = R.string.done),
-            nextAction
+            text = stringResource(id = R.string.done),
+            onClick = nextAction
         ),
         dismissButton = BottomAppBarButton(
-            stringResource(id = R.string.cancel),
-            cancelAction
+            text = stringResource(id = R.string.cancel),
+            onClick = cancelAction
         ),
     ) {
         val callsSelectedId = rememberSaveable {
diff --git a/src/com/android/settings/spa/network/SimOnboardingSelectSim.kt b/src/com/android/settings/spa/network/SimOnboardingSelectSim.kt
index 5e71b12..b033a28 100644
--- a/src/com/android/settings/spa/network/SimOnboardingSelectSim.kt
+++ b/src/com/android/settings/spa/network/SimOnboardingSelectSim.kt
@@ -16,12 +16,12 @@
 
 package com.android.settings.spa.network
 
-import android.util.Log
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.padding
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.outlined.SignalCellularAlt
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.MutableState
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.saveable.rememberSaveable
@@ -29,7 +29,6 @@
 import androidx.compose.ui.res.stringResource
 import com.android.settings.R
 import com.android.settings.network.SimOnboardingService
-import com.android.settings.sim.SimDialogActivity
 import com.android.settingslib.spa.framework.theme.SettingsDimension
 import com.android.settingslib.spa.widget.preference.CheckboxPreference
 import com.android.settingslib.spa.widget.preference.CheckboxPreferenceModel
@@ -46,44 +45,47 @@
     cancelAction: () -> Unit,
     onboardingService: SimOnboardingService
 ) {
+    var actionButtonController = rememberSaveable { mutableStateOf(false) }
+
     SuwScaffold(
         imageVector = Icons.Outlined.SignalCellularAlt,
         title = stringResource(id = R.string.sim_onboarding_select_sim_title),
         actionButton = BottomAppBarButton(
-            stringResource(id = R.string.sim_onboarding_next),
-            nextAction
+            text = stringResource(id = R.string.sim_onboarding_next),
+            enabled = actionButtonController.value,
+            onClick = nextAction
         ),
         dismissButton = BottomAppBarButton(
-            stringResource(id = R.string.cancel),
-            cancelAction
+            text = stringResource(id = R.string.cancel),
+            onClick = cancelAction
         ),
     ) {
-        selectSimBody(onboardingService)
+        SelectSimBody(onboardingService, actionButtonController)
     }
 }
 
 @Composable
-private fun selectSimBody(onboardingService: SimOnboardingService) {
+private fun SelectSimBody(
+    onboardingService: SimOnboardingService,
+    isFinished: MutableState<Boolean>
+) {
     Column(Modifier.padding(SettingsDimension.itemPadding)) {
         SettingsBody(stringResource(id = R.string.sim_onboarding_select_sim_msg))
     }
-    var isFinished = rememberSaveable { mutableStateOf(false) }
     isFinished.value = onboardingService.isSimSelectionFinished
     for (subInfo in onboardingService.getSelectableSubscriptionInfoList()) {
         var title = onboardingService.getSubscriptionInfoDisplayName(subInfo)
-        var summaryNumber =
-            subInfo.number // TODO using the SubscriptionUtil.getFormattedPhoneNumber
+        val phoneNumber = phoneNumber(subInfo)
         var checked = rememberSaveable {
             mutableStateOf(
                 onboardingService.getSelectedSubscriptionInfoList().contains(subInfo)
             )
         }
-
         CheckboxPreference(remember {
             object : CheckboxPreferenceModel {
                 override val title = title
                 override val summary: () -> String
-                    get() = { summaryNumber }
+                    get() = { phoneNumber.value ?: "" }
                 override val checked = { checked.value }
                 override val onCheckedChange = { newChecked: Boolean ->
                     checked.value = newChecked
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorialTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorialTest.java
index 404dbe5..edefec2 100644
--- a/tests/robotests/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorialTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorialTest.java
@@ -54,11 +54,10 @@
 import org.mockito.junit.MockitoRule;
 import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.LooperMode;
+import org.robolectric.shadows.ShadowLooper;
 
 /** Tests for {@link AccessibilityGestureNavigationTutorial}. */
 @RunWith(RobolectricTestRunner.class)
-@LooperMode(LooperMode.Mode.LEGACY)
 public final class AccessibilityGestureNavigationTutorialTest {
 
     @Rule
@@ -178,6 +177,7 @@
         final AlertDialog alertDialog =
                 createAccessibilityTutorialDialog(mContext, mShortcutTypes);
         alertDialog.show();
+        ShadowLooper.idleMainLooper();
 
         assertThat(alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE).getVisibility())
                 .isEqualTo(View.GONE);
@@ -204,6 +204,7 @@
         alertDialog.show();
 
         alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick();
+        ShadowLooper.idleMainLooper();
 
         assertThat(alertDialog.isShowing()).isFalse();
     }
@@ -216,6 +217,7 @@
         alertDialog.show();
 
         alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick();
+        ShadowLooper.idleMainLooper();
 
         verify(mOnClickListener).onClick(alertDialog, DialogInterface.BUTTON_POSITIVE);
     }
@@ -228,6 +230,7 @@
         alertDialog.show();
 
         alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE).performClick();
+        ShadowLooper.idleMainLooper();
 
         final Intent intent = shadowOf(activity).peekNextStartedActivity();
         assertThat(intent.getComponent().getClassName()).isEqualTo(SubSettings.class.getName());
@@ -243,6 +246,7 @@
                 showGestureNavigationTutorialDialog(mContext, mOnDismissListener);
 
         alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick();
+        ShadowLooper.idleMainLooper();
 
         assertThat(alertDialog.isShowing()).isFalse();
         verify(mOnDismissListener).onDismiss(alertDialog);
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilityQuickSettingsPrimarySwitchPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilityQuickSettingsPrimarySwitchPreferenceControllerTest.java
index b13d0e4..08cbaae 100644
--- a/tests/robotests/src/com/android/settings/accessibility/AccessibilityQuickSettingsPrimarySwitchPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityQuickSettingsPrimarySwitchPreferenceControllerTest.java
@@ -53,15 +53,14 @@
 import org.mockito.junit.MockitoRule;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.annotation.Config;
-import org.robolectric.annotation.LooperMode;
 import org.robolectric.shadow.api.Shadow;
 import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.shadows.ShadowLooper;
 
 /**
  * Tests for {@link AccessibilityQuickSettingsPrimarySwitchPreferenceController}.
  */
 @RunWith(RobolectricTestRunner.class)
-@LooperMode(LooperMode.Mode.LEGACY)
 public class AccessibilityQuickSettingsPrimarySwitchPreferenceControllerTest {
 
     private static final String PLACEHOLDER_PACKAGE_NAME = "com.placeholder.example";
@@ -160,6 +159,7 @@
         mController.onCreate(savedInstanceState);
 
         mController.displayPreference(mScreen);
+        ShadowLooper.idleMainLooper();
 
         assertThat(getLatestPopupWindow().isShowing()).isTrue();
     }
diff --git a/tests/robotests/src/com/android/settings/accessibility/HearingAidDialogFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingAidDialogFragmentTest.java
index adfd573..9d37c2a 100644
--- a/tests/robotests/src/com/android/settings/accessibility/HearingAidDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/HearingAidDialogFragmentTest.java
@@ -44,11 +44,10 @@
 import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.annotation.Config;
-import org.robolectric.annotation.LooperMode;
+import org.robolectric.shadows.ShadowLooper;
 
 /** Tests for {@link HearingAidDialogFragment}. */
 @RunWith(RobolectricTestRunner.class)
-@LooperMode(LooperMode.Mode.LEGACY)
 @Config(shadows = {
         com.android.settings.testutils.shadow.ShadowFragment.class,
         ShadowAlertDialogCompat.class,
@@ -81,6 +80,7 @@
         dialog.show();
 
         dialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick();
+        ShadowLooper.idleMainLooper();
 
         final Intent intent = shadowOf(mActivity).getNextStartedActivity();
         assertThat(intent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT))
@@ -93,6 +93,7 @@
         dialog.show();
 
         dialog.getButton(DialogInterface.BUTTON_NEGATIVE).performClick();
+        ShadowLooper.idleMainLooper();
 
         assertThat(dialog.isShowing()).isFalse();
     }
diff --git a/tests/robotests/src/com/android/settings/accessibility/HearingAidPairingDialogFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingAidPairingDialogFragmentTest.java
index d082b1f..7abf9a4 100644
--- a/tests/robotests/src/com/android/settings/accessibility/HearingAidPairingDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/HearingAidPairingDialogFragmentTest.java
@@ -60,12 +60,11 @@
 import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.annotation.Config;
-import org.robolectric.annotation.LooperMode;
 import org.robolectric.shadow.api.Shadow;
+import org.robolectric.shadows.ShadowLooper;
 
 /** Tests for {@link HearingAidPairingDialogFragment}. */
 @RunWith(RobolectricTestRunner.class)
-@LooperMode(LooperMode.Mode.LEGACY)
 @Config(shadows = {
         com.android.settings.testutils.shadow.ShadowAlertDialogCompat.class,
         com.android.settings.testutils.shadow.ShadowBluetoothAdapter.class,
@@ -122,6 +121,7 @@
         dialog.show();
 
         dialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick();
+        ShadowLooper.idleMainLooper();
 
         final Intent intent = shadowOf(mActivity).getNextStartedActivity();
         assertThat(intent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT))
@@ -135,6 +135,7 @@
         dialog.show();
 
         dialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick();
+        ShadowLooper.idleMainLooper();
 
         final Intent intent = shadowOf(mActivity).getNextStartedActivity();
         assertThat(intent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT))
@@ -147,6 +148,7 @@
         dialog.show();
 
         dialog.getButton(DialogInterface.BUTTON_NEGATIVE).performClick();
+        ShadowLooper.idleMainLooper();
 
         assertThat(dialog.isShowing()).isFalse();
     }
diff --git a/tests/robotests/src/com/android/settings/accessibility/PreviewSizeSeekBarControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/PreviewSizeSeekBarControllerTest.java
index 14306e0..af72beb 100644
--- a/tests/robotests/src/com/android/settings/accessibility/PreviewSizeSeekBarControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/PreviewSizeSeekBarControllerTest.java
@@ -61,15 +61,14 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.annotation.Config;
-import org.robolectric.annotation.LooperMode;
 import org.robolectric.shadow.api.Shadow;
 import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.shadows.ShadowLooper;
 
 /**
  * Tests for {@link PreviewSizeSeekBarController}.
  */
 @RunWith(RobolectricTestRunner.class)
-@LooperMode(LooperMode.Mode.LEGACY)
 @Config(shadows = {ShadowInteractionJankMonitor.class})
 public class PreviewSizeSeekBarControllerTest {
 
@@ -194,8 +193,9 @@
         mSeekBarPreference.setProgress(mSeekBarPreference.getMax());
         mSeekBarPreference.onProgressChanged(new SeekBar(mContext), /* progress= */
                 0, /* fromUser= */ false);
+        ShadowLooper.idleMainLooper();
 
-        verify(mInteractionListener).notifyPreferenceChanged();
+        verify(mInteractionListener).onProgressChanged();
     }
 
     @Test
@@ -259,6 +259,7 @@
         mSeekBarController.onCreate(savedInstanceState);
 
         mSeekBarController.displayPreference(mPreferenceScreen);
+        ShadowLooper.idleMainLooper();
 
         assertThat(getLatestPopupWindow().isShowing()).isTrue();
     }
diff --git a/tests/robotests/src/com/android/settings/accessibility/TextReadingPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/TextReadingPreferenceFragmentTest.java
index 8212ba2..0230e26 100644
--- a/tests/robotests/src/com/android/settings/accessibility/TextReadingPreferenceFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/TextReadingPreferenceFragmentTest.java
@@ -52,7 +52,7 @@
 import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.annotation.Config;
-import org.robolectric.annotation.LooperMode;
+import org.robolectric.shadows.ShadowLooper;
 import org.robolectric.shadows.ShadowToast;
 
 import java.util.ArrayList;
@@ -61,7 +61,6 @@
 
 /** Tests for {@link TextReadingPreferenceFragment}. */
 @RunWith(RobolectricTestRunner.class)
-@LooperMode(LooperMode.Mode.LEGACY)
 @Config(shadows = {
         com.android.settings.testutils.shadow.ShadowFragment.class,
 })
@@ -98,6 +97,7 @@
         dialog.show();
 
         dialog.getButton(DialogInterface.BUTTON_POSITIVE).callOnClick();
+        ShadowLooper.idleMainLooper();
 
         assertThat(mFragment.mNeedResetSettings).isTrue();
     }
@@ -112,6 +112,7 @@
         dialog.show();
 
         dialog.getButton(DialogInterface.BUTTON_POSITIVE).callOnClick();
+        ShadowLooper.idleMainLooper();
 
         verify(listener1).resetState();
         verify(listener2).resetState();
@@ -126,6 +127,7 @@
         dialog.show();
 
         dialog.getButton(DialogInterface.BUTTON_POSITIVE).callOnClick();
+        ShadowLooper.idleMainLooper();
 
         assertThat(ShadowToast.getTextOfLatestToast())
                 .isEqualTo(mContext.getString(R.string.accessibility_text_reading_reset_message));
diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java
index 6fb1c3f..3d0f223 100644
--- a/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java
@@ -74,15 +74,14 @@
 import org.mockito.Spy;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.annotation.Config;
-import org.robolectric.annotation.LooperMode;
 import org.robolectric.shadow.api.Shadow;
 import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.shadows.ShadowLooper;
 
 import java.util.Locale;
 
 /** Tests for {@link ToggleFeaturePreferenceFragment} */
 @RunWith(RobolectricTestRunner.class)
-@LooperMode(LooperMode.Mode.LEGACY)
 @Config(shadows = {
         ShadowFragment.class,
 })
@@ -252,6 +251,7 @@
         final CheckBox hardwareTypeCheckBox = dialogHardwareView.findViewById(R.id.checkbox);
         hardwareTypeCheckBox.setChecked(true);
         dialog.getButton(DialogInterface.BUTTON_POSITIVE).callOnClick();
+        ShadowLooper.idleMainLooper();
         final boolean skipTimeoutRestriction = Settings.Secure.getInt(mContext.getContentResolver(),
                 Settings.Secure.SKIP_ACCESSIBILITY_SHORTCUT_DIALOG_TIMEOUT_RESTRICTION, 0) != 0;
 
diff --git a/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java
index 5a7e247..6aa2831 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java
@@ -372,6 +372,6 @@
     public void onClick_Preference_setActive() {
         mBluetoothDeviceUpdater.onPreferenceClick(mPreference);
 
-        verify(mCachedBluetoothDevice).setActive();
+        verify(mDevicePreferenceCallback).onDeviceClick(mPreference);
     }
 }
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupControllerTest.java
index 357420a..8f07cca 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupControllerTest.java
@@ -32,9 +32,9 @@
 import android.bluetooth.BluetoothProfile;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
 import android.media.AudioManager;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.util.Pair;
 
 import androidx.appcompat.app.AlertDialog;
 import androidx.fragment.app.FragmentActivity;
@@ -46,6 +46,7 @@
 
 import com.android.settings.R;
 import com.android.settings.bluetooth.AvailableMediaBluetoothDeviceUpdater;
+import com.android.settings.bluetooth.BluetoothDevicePreference;
 import com.android.settings.bluetooth.Utils;
 import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
 import com.android.settings.testutils.shadow.ShadowAudioManager;
@@ -64,7 +65,8 @@
 import org.junit.runner.RunWith;
 import org.mockito.Answers;
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
 import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
@@ -79,11 +81,11 @@
             ShadowAlertDialogCompat.class,
         })
 public class AvailableMediaDeviceGroupControllerTest {
-    @Rule
-    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+    @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
 
     private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1";
     private static final String PREFERENCE_KEY_1 = "pref_key_1";
+    private static final String TEST_DEVICE_NAME = "test";
 
     @Mock private AvailableMediaBluetoothDeviceUpdater mAvailableMediaBluetoothDeviceUpdater;
     @Mock private PreferenceScreen mPreferenceScreen;
@@ -96,6 +98,9 @@
     @Mock private LocalBluetoothManager mLocalBluetoothManager;
     @Mock private CachedBluetoothDeviceManager mCachedDeviceManager;
     @Mock private CachedBluetoothDevice mCachedBluetoothDevice;
+    @Mock private BluetoothDevice mDevice;
+    @Mock
+    private Drawable mDrawable;
 
     private PreferenceGroup mPreferenceGroup;
     private Context mContext;
@@ -107,8 +112,6 @@
 
     @Before
     public void setUp() {
-        MockitoAnnotations.initMocks(this);
-
         mContext = spy(RuntimeEnvironment.application);
         mLifecycleOwner = () -> mLifecycle;
         mLifecycle = new Lifecycle(mLifecycleOwner);
@@ -262,4 +265,19 @@
         final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
         assertThat(dialog.isShowing()).isTrue();
     }
+
+    @Test
+    public void onDeviceClick_setActive() {
+        when(mCachedBluetoothDevice.getDevice()).thenReturn(mDevice);
+        Pair<Drawable, String> pair = new Pair<>(mDrawable, TEST_DEVICE_NAME);
+        when(mCachedBluetoothDevice.getDrawableWithDescription()).thenReturn(pair);
+        BluetoothDevicePreference preference =
+                new BluetoothDevicePreference(
+                        mContext,
+                        mCachedBluetoothDevice,
+                        true,
+                        BluetoothDevicePreference.SortType.TYPE_NO_SORT);
+        mAvailableMediaDeviceGroupController.onDeviceClick(preference);
+        verify(mCachedBluetoothDevice).setActive();
+    }
 }
diff --git a/tests/spa_unit/src/com/android/settings/spa/network/SimOnboardingSelectSimTest.kt b/tests/spa_unit/src/com/android/settings/spa/network/SimOnboardingSelectSimTest.kt
index e063f69..5b7778e 100644
--- a/tests/spa_unit/src/com/android/settings/spa/network/SimOnboardingSelectSimTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/network/SimOnboardingSelectSimTest.kt
@@ -18,19 +18,31 @@
 
 import android.content.Context
 import android.telephony.SubscriptionInfo
+import android.telephony.SubscriptionManager
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalLifecycleOwner
+import androidx.compose.ui.test.assertHasClickAction
 import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertIsOn
+import androidx.compose.ui.test.hasText
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.compose.ui.test.onNodeWithText
 import androidx.compose.ui.test.performClick
+import androidx.lifecycle.testing.TestLifecycleOwner
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.settings.R
 import com.android.settings.network.SimOnboardingService
+import com.android.settingslib.spa.testutils.waitUntilExists
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.doAnswer
 import org.mockito.kotlin.doReturn
 import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
 import org.mockito.kotlin.stub
 import org.mockito.kotlin.verify
 
@@ -38,8 +50,20 @@
 class SimOnboardingSelectSimTest {
     @get:Rule
     val composeTestRule = createComposeRule()
+    private val mockSubscriptionManager = mock<SubscriptionManager> {
+        on { addOnSubscriptionsChangedListener(any(), any()) } doAnswer {
+            val listener = it.arguments[1] as SubscriptionManager.OnSubscriptionsChangedListener
+            listener.onSubscriptionsChanged()
+        }
+        on { getPhoneNumber(SUB_ID_1) } doReturn NUMBER_1
+        on { getPhoneNumber(SUB_ID_2) } doReturn NUMBER_2
+        on { getPhoneNumber(SUB_ID_3) } doReturn NUMBER_3
+    }
 
-    private val context: Context = ApplicationProvider.getApplicationContext()
+    private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
+        on { getSystemService(SubscriptionManager::class.java) } doReturn mockSubscriptionManager
+    }
+
     private var mockSimOnboardingService = mock<SimOnboardingService> {
         on { targetSubId }.doReturn(-1)
         on { targetSubInfo }.doReturn(null)
@@ -78,6 +102,24 @@
 
     @Test
     fun simOnboardingSelectSimImpl_clickNextAction_verifyNextAction() {
+        mockSimOnboardingService.stub {
+            on { targetSubId }.doReturn(SUB_ID_1)
+            on { targetSubInfo }.doReturn(SUB_INFO_1)
+            on { availableSubInfoList }.doReturn(listOf(SUB_INFO_1, SUB_INFO_2, SUB_INFO_3))
+            on { activeSubInfoList }.doReturn(listOf(SUB_INFO_2, SUB_INFO_3))
+            on { getSelectableSubscriptionInfoList() }.doReturn(
+                listOf(
+                    SUB_INFO_1,
+                    SUB_INFO_2,
+                    SUB_INFO_3
+                )
+            )
+            on { getSubscriptionInfoDisplayName(SUB_INFO_1) }.doReturn(DISPLAY_NAME_1)
+            on { getSubscriptionInfoDisplayName(SUB_INFO_2) }.doReturn(DISPLAY_NAME_2)
+            on { getSubscriptionInfoDisplayName(SUB_INFO_3) }.doReturn(DISPLAY_NAME_3)
+            on {isSimSelectionFinished}.doReturn(true)
+        }
+
         composeTestRule.setContent {
             SimOnboardingSelectSimImpl(nextAction, cancelAction, mockSimOnboardingService)
         }
@@ -85,7 +127,7 @@
         composeTestRule.onNodeWithText(context.getString(R.string.sim_onboarding_next))
             .performClick()
 
-        verify(nextAction)
+        verify(nextAction)()
     }
 
     @Test
@@ -97,7 +139,7 @@
         composeTestRule.onNodeWithText(context.getString(R.string.cancel))
             .performClick()
 
-        verify(cancelAction)
+        verify(cancelAction)()
     }
 
     @Test
@@ -120,15 +162,23 @@
         }
 
         composeTestRule.setContent {
-            SimOnboardingSelectSimImpl(nextAction, cancelAction, mockSimOnboardingService)
+            CompositionLocalProvider(
+                LocalContext provides context,
+                LocalLifecycleOwner provides TestLifecycleOwner(),
+            ) {
+                SimOnboardingSelectSimImpl(nextAction, cancelAction, mockSimOnboardingService)
+            }
         }
+//        composeTestRule.setContent {
+//            SimOnboardingSelectSimImpl(nextAction, cancelAction, mockSimOnboardingService)
+//        }
 
         composeTestRule.onNodeWithText(DISPLAY_NAME_1).assertIsDisplayed()
-        composeTestRule.onNodeWithText(NUMBER_1).assertIsDisplayed()
+        composeTestRule.waitUntilExists(hasText(NUMBER_1))
         composeTestRule.onNodeWithText(DISPLAY_NAME_2).assertIsDisplayed()
-        composeTestRule.onNodeWithText(NUMBER_2).assertIsDisplayed()
+        composeTestRule.waitUntilExists(hasText(NUMBER_2))
         composeTestRule.onNodeWithText(DISPLAY_NAME_3).assertIsDisplayed()
-        composeTestRule.onNodeWithText(NUMBER_3).assertIsDisplayed()
+        composeTestRule.waitUntilExists(hasText(NUMBER_3))
     }
 
     private companion object {
@@ -141,24 +191,28 @@
         const val NUMBER_1 = "000000001"
         const val NUMBER_2 = "000000002"
         const val NUMBER_3 = "000000003"
+        const val MCC = "310"
         const val PRIMARY_SIM_ASK_EVERY_TIME = -1
 
         val SUB_INFO_1: SubscriptionInfo = SubscriptionInfo.Builder().apply {
             setId(SUB_ID_1)
             setDisplayName(DISPLAY_NAME_1)
             setNumber(NUMBER_1)
+            setMcc(MCC)
         }.build()
 
         val SUB_INFO_2: SubscriptionInfo = SubscriptionInfo.Builder().apply {
             setId(SUB_ID_2)
             setDisplayName(DISPLAY_NAME_2)
             setNumber(NUMBER_2)
+            setMcc(MCC)
         }.build()
 
         val SUB_INFO_3: SubscriptionInfo = SubscriptionInfo.Builder().apply {
             setId(SUB_ID_3)
             setDisplayName(DISPLAY_NAME_3)
             setNumber(NUMBER_3)
+            setMcc(MCC)
         }.build()
     }
 }