Merge "Update source metric category of HearingAidDialogFragment and HearingAidPairingDialogFragment"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index ec52bbf..938e33d 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -250,12 +250,14 @@
             android:name=".Settings$MobileNetworkActivity"
             android:label="@string/network_settings_title"
             android:configChanges="orientation|screenSize|keyboardHidden"
-            android:launchMode="singleInstance"
+            android:launchMode="singleTop"
             android:exported="true">
             <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
                        android:value="com.android.settings.network.telephony.MobileNetworkSettings"/>
             <intent-filter android:priority="1">
                 <!-- Displays the MobileNetworkActivity and opt-in dialog for capability discovery. -->
+                <!-- Please sync with a list created within MobileNetworkIntentConverter.java -->
+                <action android:name="android.intent.action.MAIN" />
                 <action android:name="android.telephony.ims.action.SHOW_CAPABILITY_DISCOVERY_OPT_IN" />
                 <action android:name="android.settings.NETWORK_OPERATOR_SETTINGS" />
                 <action android:name="android.settings.DATA_ROAMING_SETTINGS" />
diff --git a/OWNERS b/OWNERS
index c2ff692..cc33111 100644
--- a/OWNERS
+++ b/OWNERS
@@ -12,6 +12,7 @@
 sunnyshao@google.com
 tmfang@google.com
 yantingyang@google.com
+ykhung@google.com
 
 # Emergency only
 hanxu@google.com
diff --git a/res/drawable-nodpi/auto_awesome_battery b/res/drawable-nodpi/auto_awesome_battery
deleted file mode 100644
index e69de29..0000000
--- a/res/drawable-nodpi/auto_awesome_battery
+++ /dev/null
diff --git a/res/drawable-nodpi/gesture_ambient_tap b/res/drawable-nodpi/gesture_ambient_tap
deleted file mode 100644
index e69de29..0000000
--- a/res/drawable-nodpi/gesture_ambient_tap
+++ /dev/null
diff --git a/res/drawable-nodpi/gesture_ambient_tap_screen b/res/drawable-nodpi/gesture_ambient_tap_screen
deleted file mode 100644
index e69de29..0000000
--- a/res/drawable-nodpi/gesture_ambient_tap_screen
+++ /dev/null
diff --git a/res/raw/auto_awesome_battery.mp4 b/res/raw/auto_awesome_battery.mp4
deleted file mode 100644
index e69de29..0000000
--- a/res/raw/auto_awesome_battery.mp4
+++ /dev/null
diff --git a/res/raw/gesture_ambient_tap.mp4 b/res/raw/gesture_ambient_tap.mp4
deleted file mode 100644
index e69de29..0000000
--- a/res/raw/gesture_ambient_tap.mp4
+++ /dev/null
diff --git a/res/raw/gesture_ambient_tap_screen.mp4 b/res/raw/gesture_ambient_tap_screen.mp4
deleted file mode 100644
index e69de29..0000000
--- a/res/raw/gesture_ambient_tap_screen.mp4
+++ /dev/null
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f397b47..cc7690e 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -606,7 +606,7 @@
     <!-- Date & time setting screen setting switch title: whether the system clock (Unix epoch time) should be determined automatically [CHAR LIMIT=100] -->
     <string name="date_time_auto">Set time automatically</string>
     <!-- Date & time setting screen setting switch title: whether the time zone should be determined automatically [CHAR LIMIT=100]  -->
-    <string name="zone_auto_title">Set time zone automatically</string>
+    <string name="zone_auto_title">Set automatically</string>
     <!-- Date & time setting screen setting option summary text for the automatic 24 hour setting checkbox [CHAR LIMIT=100] -->
     <string name="date_time_24hour_auto">Use locale default</string>
     <!-- Date & time setting screen setting check box title [CHAR LIMIT=30] -->
@@ -4254,7 +4254,7 @@
     <string name="managed_profile_location_services">Location services for work</string>
 
     <!-- [CHAR LIMIT=60] Date&Time settings screen, toggle button title -->
-    <string name="location_time_zone_detection_toggle_title">Use location to set time zone</string>
+    <string name="location_time_zone_detection_toggle_title">Use location</string>
     <!-- [CHAR LIMIT=60] Date&Time settings screen, title of the dialog shown when user tries to
          enable GeoTZ when Location toggle is off. -->
     <string name="location_time_zone_detection_location_is_off_dialog_title">Device location needed</string>
@@ -4280,6 +4280,8 @@
     <!-- [CHAR LIMIT=NONE] Location settings screen, summary when location time zone detection is not
          allowed for the user, e.g. because of device policy -->
     <string name="location_time_zone_detection_not_allowed">Location time zone detection changes are not allowed</string>
+    <!-- [CHAR LIMIT=NONE] Location settings screen, summary when location time zone detection is enabled. -->
+    <string name="location_time_zone_detection_auto_is_on">Location may be used to set time zone</string>
 
     <!-- [CHAR LIMIT=30] Security & location settings screen, setting check box label for Google location service (cell ID, wifi, etc.) -->
     <string name="location_network_based">Wi\u2011Fi &amp; mobile network location</string>
@@ -6835,6 +6837,14 @@
         behalf.  It comes from the <xliff:g id="voice_input_service_app_name">%s</xliff:g>
         application.  Enable the use of this service?</string>
 
+    <!-- On-device recognition settings --><skip />
+    <!-- [CHAR_LIMIT=NONE] Name of the settings item to open the on-device recognition settings. -->
+    <string name="on_device_recognition_settings">On-device recognition settings</string>
+    <!-- [CHAR_LIMIT=NONE] Title of the on-device recognition settings -->
+    <string name="on_device_recognition_settings_title">On-device recognition</string>
+    <!-- [CHAR_LIMIT=NONE] Summary of the on-device recognition settings -->
+    <string name="on_device_recognition_settings_summary">On-device speech recognition</string>
+
     <!-- [CHAR LIMIT=50] The text for the settings section that is used to set a preferred text to speech engine -->
     <string name="tts_engine_preference_title">Preferred engine</string>
     <!-- [CHAR LIMIT=50] The text for a settings screen of the currently set text to speech engine -->
diff --git a/res/xml/date_time_prefs.xml b/res/xml/date_time_prefs.xml
index a0801f9..e3d0a7e 100644
--- a/res/xml/date_time_prefs.xml
+++ b/res/xml/date_time_prefs.xml
@@ -45,7 +45,6 @@
         <com.android.settingslib.RestrictedSwitchPreference
             android:key="auto_zone"
             android:title="@string/zone_auto_title"
-            settings:allowDividerAbove="true"
             settings:userRestriction="no_config_date_time"/>
 
         <!-- This preference gets removed if location-based time zone detection is not supported -->
diff --git a/res/xml/language_and_input.xml b/res/xml/language_and_input.xml
index 770a862..64b5003 100644
--- a/res/xml/language_and_input.xml
+++ b/res/xml/language_and_input.xml
@@ -64,6 +64,13 @@
             android:fragment="com.android.settings.language.DefaultVoiceInputPicker" />
 
         <Preference
+            android:key="on_device_recognition_settings"
+            android:title="@string/on_device_recognition_settings_title"
+            android:summary="@string/on_device_recognition_settings_summary"
+            settings:controller=
+                "com.android.settings.language.OnDeviceRecognitionPreferenceController" />
+
+        <Preference
             android:key="tts_settings_summary"
             android:title="@string/tts_settings_title"
             android:fragment="com.android.settings.tts.TextToSpeechSettings"
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index ee0743a..c3ab8e2 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -22,8 +22,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
-import android.telephony.SubscriptionInfo;
-import android.telephony.SubscriptionManager;
 import android.telephony.ims.ImsRcsManager;
 import android.text.TextUtils;
 import android.util.FeatureFlagUtils;
@@ -33,8 +31,7 @@
 import com.android.settings.biometrics.face.FaceSettings;
 import com.android.settings.core.FeatureFlags;
 import com.android.settings.enterprise.EnterprisePrivacySettings;
-import com.android.settings.network.SubscriptionUtil;
-import com.android.settings.network.telephony.MobileNetworkUtils;
+import com.android.settings.network.MobileNetworkIntentConverter;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.safetycenter.SafetyCenterManagerWrapper;
 import com.android.settings.security.SecuritySettingsFeatureProvider;
@@ -370,41 +367,37 @@
     public static class PowerMenuSettingsActivity extends SettingsActivity {}
     public static class MobileNetworkActivity extends SettingsActivity {
 
+        public static final String TAG = "MobileNetworkActivity";
         public static final String EXTRA_MMS_MESSAGE = "mms_message";
         public static final String EXTRA_SHOW_CAPABILITY_DISCOVERY_OPT_IN =
                 "show_capability_discovery_opt_in";
 
+        private MobileNetworkIntentConverter mIntentConverter;
+
+        /**
+         * Override of #onNewIntent() requires Activity to have "singleTop" launch mode within
+         * AndroidManifest.xml
+         */
         @Override
-        public Intent getIntent() {
-            final Intent intent = new Intent(super.getIntent());
-            int subId = intent.getIntExtra(android.provider.Settings.EXTRA_SUB_ID,
-                    SubscriptionManager.INVALID_SUBSCRIPTION_ID);
-            SubscriptionInfo subInfo = SubscriptionUtil.getSubscriptionOrDefault(
-                    getApplicationContext(), subId);
-            CharSequence title = SubscriptionUtil.getUniqueSubscriptionDisplayName(
-                    subInfo, getApplicationContext());
-            intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE, title);
-            intent.putExtra(android.provider.Settings.EXTRA_SUB_ID, subId);
-            if (android.provider.Settings.ACTION_MMS_MESSAGE_SETTING.equals(intent.getAction())) {
-                // highlight "mms_message" preference.
-                intent.putExtra(EXTRA_FRAGMENT_ARG_KEY, EXTRA_MMS_MESSAGE);
-            }
+        protected void onNewIntent(Intent intent) {
+            super.onNewIntent(intent);
 
-            if (doesIntentContainOptInAction(intent)) {
-                intent.putExtra(EXTRA_SHOW_CAPABILITY_DISCOVERY_OPT_IN,
-                        maybeShowContactDiscoveryDialog(subId));
-            }
+            Log.d(TAG, "Starting onNewIntent");
 
-            return intent;
+            createUiFromIntent(null /* savedState */, convertIntent(intent));
         }
 
-        private boolean maybeShowContactDiscoveryDialog(int subId) {
-            // If this activity was launched using ACTION_SHOW_CAPABILITY_DISCOVERY_OPT_IN, show the
-            // associated dialog only if the opt-in has not been granted yet.
-            return MobileNetworkUtils.isContactDiscoveryVisible(getApplicationContext(), subId)
-                    // has the user already enabled this configuration?
-                    && !MobileNetworkUtils.isContactDiscoveryEnabled(
-                            getApplicationContext(), subId);
+        @Override
+        public Intent getIntent() {
+            return convertIntent(super.getIntent());
+        }
+
+        private Intent convertIntent(Intent copyFrom) {
+            if (mIntentConverter == null) {
+                mIntentConverter = new MobileNetworkIntentConverter(this);
+            }
+            Intent intent = mIntentConverter.apply(copyFrom);
+            return (intent == null) ? copyFrom : intent;
         }
 
         public static boolean doesIntentContainOptInAction(Intent intent) {
diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
index 1a9bdc7..4341851 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -70,6 +70,7 @@
 import com.android.settings.homepage.SettingsHomepageActivity;
 import com.android.settings.homepage.TopLevelSettings;
 import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.password.PasswordUtils;
 import com.android.settings.wfd.WifiDisplaySettings;
 import com.android.settings.widget.SettingsMainSwitchBar;
 import com.android.settingslib.core.instrumentation.Instrumentable;
@@ -154,6 +155,7 @@
     public static final String EXTRA_IS_FROM_SLICE = "is_from_slice";
 
     public static final String EXTRA_USER_HANDLE = "user_handle";
+    public static final String EXTRA_INITIAL_CALLING_PACKAGE = "initial_calling_package";
 
     /**
      * Personal or Work profile tab of {@link ProfileSelectFragment}
@@ -264,7 +266,10 @@
 
         super.onCreate(savedState);
         Log.d(LOG_TAG, "Starting onCreate");
+        createUiFromIntent(savedState, intent);
+    }
 
+    protected void createUiFromIntent(Bundle savedState, Intent intent) {
         long startTime = System.currentTimeMillis();
 
         final FeatureFactory factory = FeatureFactory.getFactory(this);
@@ -415,6 +420,8 @@
     }
 
     private boolean tryStartTwoPaneDeepLink(Intent intent) {
+        intent.putExtra(EXTRA_INITIAL_CALLING_PACKAGE, PasswordUtils.getCallingAppPackageName(
+                getActivityToken()));
         final Intent trampolineIntent;
         if (intent.getBooleanExtra(EXTRA_IS_FROM_SLICE, false)) {
             // Get menu key for slice deep link case.
@@ -502,6 +509,17 @@
         return true;
     }
 
+    /** Returns the initial calling package name that launches the activity. */
+    public String getInitialCallingPackage() {
+        String callingPackage = PasswordUtils.getCallingAppPackageName(getActivityToken());
+        if (!TextUtils.equals(callingPackage, getPackageName())) {
+            return callingPackage;
+        }
+
+        String initialCallingPackage = getIntent().getStringExtra(EXTRA_INITIAL_CALLING_PACKAGE);
+        return TextUtils.isEmpty(initialCallingPackage) ? callingPackage : initialCallingPackage;
+    }
+
     /** Returns the initial fragment name that the activity will launch. */
     @VisibleForTesting
     public String getInitialFragmentName(Intent intent) {
diff --git a/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizard.java b/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizard.java
index 4eea9f5..6c32edd 100644
--- a/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizard.java
+++ b/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizard.java
@@ -33,6 +33,7 @@
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityManager;
 
+import androidx.annotation.VisibleForTesting;
 import androidx.preference.Preference;
 import androidx.recyclerview.widget.RecyclerView;
 
@@ -58,17 +59,21 @@
     private static final String SELECT_TO_SPEAK_PREFERENCE = "select_to_speak_preference";
 
     // Package names and service names used to identify screen reader and SelectToSpeak services.
-    private static final String SCREEN_READER_PACKAGE_NAME = "com.google.android.marvin.talkback";
-    private static final String SCREEN_READER_SERVICE_NAME =
+    @VisibleForTesting
+    static final String SCREEN_READER_PACKAGE_NAME = "com.google.android.marvin.talkback";
+    @VisibleForTesting
+    static final String SCREEN_READER_SERVICE_NAME =
             "com.google.android.marvin.talkback.TalkBackService";
-    private static final String SELECT_TO_SPEAK_PACKAGE_NAME = "com.google.android.marvin.talkback";
-    private static final String SELECT_TO_SPEAK_SERVICE_NAME =
+    @VisibleForTesting
+    static final String SELECT_TO_SPEAK_PACKAGE_NAME = "com.google.android.marvin.talkback";
+    @VisibleForTesting
+    static final String SELECT_TO_SPEAK_SERVICE_NAME =
             "com.google.android.accessibility.selecttospeak.SelectToSpeakService";
 
     // Preference controls.
-    private Preference mDisplayMagnificationPreference;
-    private RestrictedPreference mScreenReaderPreference;
-    private RestrictedPreference mSelectToSpeakPreference;
+    protected Preference mDisplayMagnificationPreference;
+    protected RestrictedPreference mScreenReaderPreference;
+    protected RestrictedPreference mSelectToSpeakPreference;
 
     @Override
     public int getMetricsCategory() {
diff --git a/src/com/android/settings/applications/AppsPreferenceController.java b/src/com/android/settings/applications/AppsPreferenceController.java
index fad513e..922ba3c 100644
--- a/src/com/android/settings/applications/AppsPreferenceController.java
+++ b/src/com/android/settings/applications/AppsPreferenceController.java
@@ -20,7 +20,6 @@
 import android.app.usage.UsageStats;
 import android.content.Context;
 import android.icu.text.RelativeDateTimeFormatter;
-import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 
@@ -63,10 +62,9 @@
     static final String KEY_SEE_ALL = "see_all_apps";
 
     private final ApplicationsState mApplicationsState;
-    private final int mUserId;
 
     @VisibleForTesting
-    List<UsageStats> mRecentApps;
+    List<RecentAppStatsMixin.UsageStatsWrapper> mRecentApps;
     @VisibleForTesting
     PreferenceCategory mRecentAppsCategory;
     @VisibleForTesting
@@ -83,7 +81,6 @@
         super(context, KEY_RECENT_APPS_CATEGORY);
         mApplicationsState = ApplicationsState.getInstance(
                 (Application) mContext.getApplicationContext());
-        mUserId = UserHandle.myUserId();
     }
 
     public void setFragment(Fragment fragment) {
@@ -156,7 +153,7 @@
     }
 
     @VisibleForTesting
-    List<UsageStats> loadRecentApps() {
+    List<RecentAppStatsMixin.UsageStatsWrapper> loadRecentApps() {
         final RecentAppStatsMixin recentAppStatsMixin = new RecentAppStatsMixin(mContext,
                 SHOW_RECENT_APP_COUNT);
         recentAppStatsMixin.loadDisplayableRecentApps(SHOW_RECENT_APP_COUNT);
@@ -187,26 +184,28 @@
             }
 
             int showAppsCount = 0;
-            for (UsageStats stat : mRecentApps) {
-                final String pkgName = stat.getPackageName();
+            for (RecentAppStatsMixin.UsageStatsWrapper statsWrapper : mRecentApps) {
+                final UsageStats stats = statsWrapper.mUsageStats;
+                final String pkgName = statsWrapper.mUsageStats.getPackageName();
+                final String key = pkgName + statsWrapper.mUserId;
                 final ApplicationsState.AppEntry appEntry =
-                        mApplicationsState.getEntry(pkgName, mUserId);
+                        mApplicationsState.getEntry(pkgName, statsWrapper.mUserId);
                 if (appEntry == null) {
                     continue;
                 }
 
                 boolean rebindPref = true;
-                Preference pref = existedAppPreferences.remove(pkgName);
+                Preference pref = existedAppPreferences.remove(key);
                 if (pref == null) {
                     pref = new AppPreference(mContext);
                     rebindPref = false;
                 }
 
-                pref.setKey(pkgName);
+                pref.setKey(key);
                 pref.setTitle(appEntry.label);
                 pref.setIcon(Utils.getBadgedIcon(mContext, appEntry.info));
                 pref.setSummary(StringUtil.formatRelativeTime(mContext,
-                        System.currentTimeMillis() - stat.getLastTimeUsed(), false,
+                        System.currentTimeMillis() - stats.getLastTimeUsed(), false,
                         RelativeDateTimeFormatter.Style.SHORT));
                 pref.setOrder(showAppsCount++);
                 pref.setOnPreferenceClickListener(preference -> {
diff --git a/src/com/android/settings/applications/RecentAppStatsMixin.java b/src/com/android/settings/applications/RecentAppStatsMixin.java
index 4bf3864..03b2203 100644
--- a/src/com/android/settings/applications/RecentAppStatsMixin.java
+++ b/src/com/android/settings/applications/RecentAppStatsMixin.java
@@ -26,6 +26,7 @@
 import android.content.pm.PackageManager;
 import android.os.PowerManager;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
@@ -33,6 +34,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
 
+import com.android.settings.Utils;
 import com.android.settingslib.applications.AppUtils;
 import com.android.settingslib.applications.ApplicationsState;
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
@@ -42,26 +44,31 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
-import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 
-
-public class RecentAppStatsMixin implements Comparator<UsageStats>, LifecycleObserver, OnStart {
+/**
+ * A helper class that loads recent app data in the background and sends it in a callback to a
+ * listener.
+ */
+public class RecentAppStatsMixin implements LifecycleObserver, OnStart {
 
     private static final String TAG = "RecentAppStatsMixin";
     private static final Set<String> SKIP_SYSTEM_PACKAGES = new ArraySet<>();
 
     @VisibleForTesting
-    final List<UsageStats> mRecentApps;
-    private final int mUserId;
+    List<UsageStatsWrapper> mRecentApps;
+
     private final int mMaximumApps;
     private final Context mContext;
     private final PackageManager mPm;
-    private final PowerManager mPowerManager;;
-    private final UsageStatsManager mUsageStatsManager;
+    private final PowerManager mPowerManager;
+    private final int mWorkUserId;
+    private final UsageStatsManager mPersonalUsageStatsManager;
+    private final Optional<UsageStatsManager> mWorkUsageStatsManager;
     private final ApplicationsState mApplicationsState;
     private final List<RecentAppStatsListener> mAppStatsListeners;
     private Calendar mCalendar;
@@ -80,10 +87,15 @@
     public RecentAppStatsMixin(Context context, int maximumApps) {
         mContext = context;
         mMaximumApps = maximumApps;
-        mUserId = UserHandle.myUserId();
         mPm = mContext.getPackageManager();
         mPowerManager = mContext.getSystemService(PowerManager.class);
-        mUsageStatsManager = mContext.getSystemService(UsageStatsManager.class);
+        final UserManager userManager = mContext.getSystemService(UserManager.class);
+        mWorkUserId = Utils.getManagedProfileId(userManager, UserHandle.myUserId());
+        mPersonalUsageStatsManager = mContext.getSystemService(UsageStatsManager.class);
+        final UserHandle workUserHandle = Utils.getManagedProfile(userManager);
+        mWorkUsageStatsManager = Optional.ofNullable(workUserHandle).map(
+                handle -> mContext.createContextAsUser(handle, /* flags */ 0)
+                        .getSystemService(UsageStatsManager.class));
         mApplicationsState = ApplicationsState.getInstance(
                 (Application) mContext.getApplicationContext());
         mRecentApps = new ArrayList<>();
@@ -100,32 +112,56 @@
         });
     }
 
-    @Override
-    public final int compare(UsageStats a, UsageStats b) {
-        // return by descending order
-        return Long.compare(b.getLastTimeUsed(), a.getLastTimeUsed());
-    }
-
     public void addListener(@NonNull RecentAppStatsListener listener) {
         mAppStatsListeners.add(listener);
     }
 
     @VisibleForTesting
-    void loadDisplayableRecentApps(int number) {
+    void loadDisplayableRecentApps(int limit) {
         mRecentApps.clear();
         mCalendar = Calendar.getInstance();
         mCalendar.add(Calendar.DAY_OF_YEAR, -1);
-        final List<UsageStats> mStats = mPowerManager.isPowerSaveMode()
+
+        final int personalUserId = UserHandle.myUserId();
+        final List<UsageStats> personalStats =
+                getRecentAppsStats(mPersonalUsageStatsManager, personalUserId);
+        final List<UsageStats> workStats = mWorkUsageStatsManager
+                .map(statsManager -> getRecentAppsStats(statsManager, mWorkUserId))
+                .orElse(new ArrayList<>());
+
+        // Both lists are already sorted, so we can create a sorted merge in linear time
+        int personal = 0;
+        int work = 0;
+        while (personal < personalStats.size() && work < workStats.size()
+                && mRecentApps.size() < limit) {
+            UsageStats currentPersonal = personalStats.get(personal);
+            UsageStats currentWork = workStats.get(work);
+            if (currentPersonal.getLastTimeUsed() > currentWork.getLastTimeUsed()) {
+                mRecentApps.add(new UsageStatsWrapper(currentPersonal, personalUserId));
+                personal++;
+            } else {
+                mRecentApps.add(new UsageStatsWrapper(currentWork, mWorkUserId));
+                work++;
+            }
+        }
+        while (personal < personalStats.size() && mRecentApps.size() < limit) {
+            mRecentApps.add(new UsageStatsWrapper(personalStats.get(personal++), personalUserId));
+        }
+        while (work < workStats.size() && mRecentApps.size() < limit) {
+            mRecentApps.add(new UsageStatsWrapper(workStats.get(work++), mWorkUserId));
+        }
+    }
+
+    private List<UsageStats> getRecentAppsStats(UsageStatsManager usageStatsManager, int userId) {
+        final List<UsageStats> recentAppStats = mPowerManager.isPowerSaveMode()
                 ? new ArrayList<>()
-                : mUsageStatsManager.queryUsageStats(
+                : usageStatsManager.queryUsageStats(
                         UsageStatsManager.INTERVAL_BEST, mCalendar.getTimeInMillis(),
                         System.currentTimeMillis());
 
         final Map<String, UsageStats> map = new ArrayMap<>();
-        final int statCount = mStats.size();
-        for (int i = 0; i < statCount; i++) {
-            final UsageStats pkgStats = mStats.get(i);
-            if (!shouldIncludePkgInRecents(pkgStats)) {
+        for (final UsageStats pkgStats : recentAppStats) {
+            if (!shouldIncludePkgInRecents(pkgStats, userId)) {
                 continue;
             }
             final String pkgName = pkgStats.getPackageName();
@@ -136,28 +172,15 @@
                 existingStats.add(pkgStats);
             }
         }
-        final List<UsageStats> packageStats = new ArrayList<>();
-        packageStats.addAll(map.values());
-        Collections.sort(packageStats, this /* comparator */);
-        int count = 0;
-        for (UsageStats stat : packageStats) {
-            final ApplicationsState.AppEntry appEntry = mApplicationsState.getEntry(
-                    stat.getPackageName(), mUserId);
-            if (appEntry == null) {
-                continue;
-            }
-            mRecentApps.add(stat);
-            count++;
-            if (count >= number) {
-                break;
-            }
-        }
+        final List<UsageStats> packageStats = new ArrayList<>(map.values());
+        packageStats.sort(Comparator.comparingLong(UsageStats::getLastTimeUsed).reversed());
+        return packageStats;
     }
 
     /**
      * Whether or not the app should be included in recent list.
      */
-    private boolean shouldIncludePkgInRecents(UsageStats stat) {
+    private boolean shouldIncludePkgInRecents(UsageStats stat, int userId) {
         final String pkgName = stat.getPackageName();
         if (stat.getLastTimeUsed() < mCalendar.getTimeInMillis()) {
             Log.d(TAG, "Invalid timestamp (usage time is more than 24 hours ago), skipping "
@@ -169,26 +192,49 @@
             Log.d(TAG, "System package, skipping " + pkgName);
             return false;
         }
+
         if (AppUtils.isHiddenSystemModule(mContext, pkgName)) {
             return false;
         }
+
+        final ApplicationsState.AppEntry appEntry = mApplicationsState.getEntry(pkgName, userId);
+        if (appEntry == null) {
+            return false;
+        }
+
         final Intent launchIntent = new Intent().addCategory(Intent.CATEGORY_LAUNCHER)
                 .setPackage(pkgName);
-
-        if (mPm.resolveActivity(launchIntent, 0) == null) {
+        if (mPm.resolveActivityAsUser(launchIntent, 0, userId) == null) {
             // Not visible on launcher -> likely not a user visible app, skip if non-instant.
-            final ApplicationsState.AppEntry appEntry =
-                    mApplicationsState.getEntry(pkgName, mUserId);
-            if (appEntry == null || appEntry.info == null || !AppUtils.isInstant(appEntry.info)) {
+            if (appEntry.info == null || !AppUtils.isInstant(appEntry.info)) {
                 Log.d(TAG, "Not a user visible or instant app, skipping " + pkgName);
                 return false;
             }
         }
+
         return true;
     }
 
     public interface RecentAppStatsListener {
 
-        void onReloadDataCompleted(List<UsageStats> recentApps);
+        /** A callback after loading the recent app data. */
+        void onReloadDataCompleted(List<UsageStatsWrapper> recentApps);
+    }
+
+    static class UsageStatsWrapper {
+
+        public final UsageStats mUsageStats;
+        public final int mUserId;
+
+        UsageStatsWrapper(UsageStats usageStats, int userId) {
+            mUsageStats = usageStats;
+            mUserId = userId;
+        }
+
+        @Override
+        public String toString() {
+            return String.format("UsageStatsWrapper(pkg:%s,uid:%s)",
+                    mUsageStats.getPackageName(), mUserId);
+        }
     }
 }
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
index df65a69..bf04d5f 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
@@ -639,13 +639,17 @@
             new Animator.AnimatorListener() {
 
                 @Override
-                public void onAnimationStart(Animator animation) { }
+                public void onAnimationStart(Animator animation) {
+                    startIconAnimation();
+                }
 
                 @Override
                 public void onAnimationRepeat(Animator animation) { }
 
                 @Override
                 public void onAnimationEnd(Animator animation) {
+                    stopIconAnimation();
+
                     if (mProgressBar.getProgress() >= PROGRESS_BAR_MAX) {
                         mProgressBar.postDelayed(mDelayedFinishRunnable, getFinishDelay());
                     }
diff --git a/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java
index 14c20f1..3d8e148 100644
--- a/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java
+++ b/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java
@@ -66,7 +66,7 @@
         }
 
         boolean isFilterMatched = false;
-        if (isDeviceConnected(cachedDevice)) {
+        if (isDeviceConnected(cachedDevice) && isDeviceInCachedDevicesList(cachedDevice)) {
             if (DBG) {
                 Log.d(TAG, "isFilterMatched() current audio profile : " + currentAudioProfile);
             }
@@ -74,6 +74,8 @@
             // It would show in Available Devices group.
             if (cachedDevice.isConnectedHearingAidDevice()
                     || cachedDevice.isConnectedLeAudioDevice()) {
+                Log.d(TAG, "isFilterMatched() device : " +
+                        cachedDevice.getName() + ", the profile is connected.");
                 return true;
             }
             // According to the current audio profile type,
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java
index d65500b..8934676 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java
@@ -326,4 +326,8 @@
             ((BluetoothDevicePreference) preference).onPreferenceAttributesChanged();
         }
     }
+
+    protected boolean isDeviceInCachedDevicesList(CachedBluetoothDevice cachedDevice){
+        return mLocalManager.getCachedDeviceManager().getCachedDevicesCopy().contains(cachedDevice);
+    }
 }
diff --git a/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java b/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java
index 7d27a37..8542fcd 100644
--- a/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java
+++ b/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java
@@ -126,7 +126,7 @@
                 // "Clear All Notifications" button
 
                 Intent deleteIntent = new Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY);
-                deleteIntent.setPackage("com.android.bluetooth.services");
+                deleteIntent.setPackage("com.android.bluetooth");
                 deleteIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
                 deleteIntent.putExtra(BluetoothDevice.EXTRA_CONNECTION_ACCESS_RESULT,
                         BluetoothDevice.CONNECTION_ACCESS_NO);
diff --git a/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java
index d1c45b6..5c3dda3 100644
--- a/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java
+++ b/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java
@@ -66,7 +66,7 @@
         }
 
         boolean isFilterMatched = false;
-        if (isDeviceConnected(cachedDevice)) {
+        if (isDeviceConnected(cachedDevice) && isDeviceInCachedDevicesList(cachedDevice)) {
             if (DBG) {
                 Log.d(TAG, "isFilterMatched() current audio profile : " + currentAudioProfile);
             }
diff --git a/src/com/android/settings/bluetooth/QrCodeScanModeFragment.java b/src/com/android/settings/bluetooth/QrCodeScanModeFragment.java
index dcf89ca..7f58c06 100644
--- a/src/com/android/settings/bluetooth/QrCodeScanModeFragment.java
+++ b/src/com/android/settings/bluetooth/QrCodeScanModeFragment.java
@@ -232,8 +232,7 @@
     }
 
     private void updateSummary() {
-        mSummary.setText(getString(R.string.bt_le_audio_scan_qr_code_scanner,
-                null /* broadcast_name*/));;
+        mSummary.setText(getString(R.string.bt_le_audio_scan_qr_code_scanner));
     }
 
     @Override
diff --git a/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java
index 3bdf91e..e7a8317 100644
--- a/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java
+++ b/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java
@@ -106,7 +106,8 @@
                     + cachedDevice.isConnected());
         }
         return device.getBondState() == BluetoothDevice.BOND_BONDED
-                && (mDisplayConnected || !device.isConnected());
+                && (mDisplayConnected || (!device.isConnected() && isDeviceInCachedDevicesList(
+                cachedDevice)));
     }
 
     @Override
diff --git a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java
index 7e6eefe..ea8a5f5 100644
--- a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java
+++ b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java
@@ -25,9 +25,9 @@
 import androidx.annotation.VisibleForTesting;
 
 import com.android.settings.R;
+import com.android.settings.SettingsActivity;
 import com.android.settings.core.SettingsUIDeviceConfig;
 import com.android.settings.dashboard.DashboardFragment;
-import com.android.settings.password.PasswordUtils;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.slices.SlicePreferenceController;
 import com.android.settingslib.search.SearchIndexable;
@@ -71,8 +71,8 @@
         super.onAttach(context);
         final boolean nearbyEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SETTINGS_UI,
                 SettingsUIDeviceConfig.BT_NEAR_BY_SUGGESTION_ENABLED, true);
-        String callingAppPackageName = PasswordUtils.getCallingAppPackageName(
-                getActivity().getActivityToken());
+        String callingAppPackageName = ((SettingsActivity) getActivity())
+                .getInitialCallingPackage();
         String action = getIntent() != null ? getIntent().getAction() : "";
         if (DEBUG) {
             Log.d(TAG, "onAttach() calling package name is : " + callingAppPackageName
diff --git a/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceController.java b/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceController.java
index 93e6d0a..36cbc9e 100644
--- a/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceController.java
+++ b/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceController.java
@@ -174,7 +174,7 @@
             // If capability is possessed, toggle status already tells all the information needed.
             // Returning null will make previous text stick on toggling.
             // See AbstractPreferenceController#refreshSummary.
-            return "";
+            summaryResId = R.string.location_time_zone_detection_auto_is_on;
         } else {
             // This is unexpected: getAvailabilityStatus() should ensure that the UI element isn't
             // even shown for known cases, or the capability is unknown.
diff --git a/src/com/android/settings/development/BluetoothMaxConnectedAudioDevicesPreferenceController.java b/src/com/android/settings/development/BluetoothMaxConnectedAudioDevicesPreferenceController.java
index af9a295..bd8169a 100644
--- a/src/com/android/settings/development/BluetoothMaxConnectedAudioDevicesPreferenceController.java
+++ b/src/com/android/settings/development/BluetoothMaxConnectedAudioDevicesPreferenceController.java
@@ -47,10 +47,10 @@
 
         try {
             Resources res = context.getPackageManager().getResourcesForApplication(
-                    "com.android.bluetooth.services");
+                    "com.android.bluetooth");
             mDefaultMaxConnectedAudioDevices = res.getInteger(res.getIdentifier(
                     "config_bluetooth_max_connected_audio_devices",
-                    "integer", "com.android.bluetooth.services"));
+                    "integer", "com.android.bluetooth"));
         } catch (PackageManager.NameNotFoundException e) {
             e.printStackTrace();
         }
diff --git a/src/com/android/settings/display/ScreenResolutionFragment.java b/src/com/android/settings/display/ScreenResolutionFragment.java
index a827e92..bc82514 100644
--- a/src/com/android/settings/display/ScreenResolutionFragment.java
+++ b/src/com/android/settings/display/ScreenResolutionFragment.java
@@ -46,6 +46,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /** Preference fragment used for switch screen resolution */
 @SearchIndexable
@@ -61,7 +62,7 @@
     private String[] mScreenResolutionSummaries;
 
     private IllustrationPreference mImagePreference;
-    private DensityRestorer mDensityRestorer;
+    private DisplayObserver mDisplayObserver;
 
     @Override
     public void onAttach(Context context) {
@@ -76,7 +77,7 @@
                 mResources.getStringArray(R.array.config_screen_resolution_summaries_strings);
         mResolutions = getAllSupportedResolution();
         mImagePreference = new IllustrationPreference(context);
-        mDensityRestorer = new DensityRestorer(context);
+        mDisplayObserver = new DisplayObserver(context);
     }
 
     @Override
@@ -155,11 +156,7 @@
     /** Using display manager to set the display mode. */
     @VisibleForTesting
     public void setDisplayMode(final int width) {
-        if (width == getDisplayMode().getPhysicalWidth()) {
-            return;
-        }
-
-        mDensityRestorer.startObserve();
+        mDisplayObserver.startObserve();
         mDefaultDisplay.setUserPreferredDisplayMode(getPreferMode(width));
     }
 
@@ -171,6 +168,13 @@
                 : width == QHD_WIDTH ? mScreenResolutionOptions[QHD_INDEX] : null;
     }
 
+    /** Get the width corresponding to the resolution key. */
+    int getWidthForResoluitonKey(String key) {
+        return mScreenResolutionOptions[FHD_INDEX].equals(key)
+                ? FHD_WIDTH
+                : mScreenResolutionOptions[QHD_INDEX].equals(key) ? QHD_WIDTH : -1;
+    }
+
     @Override
     protected String getDefaultKey() {
         int physicalWidth = getDisplayMode().getPhysicalWidth();
@@ -180,17 +184,28 @@
 
     @Override
     protected boolean setDefaultKey(final String key) {
-        if (mScreenResolutionOptions[FHD_INDEX].equals(key)) {
-            setDisplayMode(FHD_WIDTH);
-
-        } else if (mScreenResolutionOptions[QHD_INDEX].equals(key)) {
-            setDisplayMode(QHD_WIDTH);
+        int width = getWidthForResoluitonKey(key);
+        if (width < 0) {
+          return false;
         }
 
+        setDisplayMode(width);
         updateIllustrationImage(mImagePreference);
+
         return true;
     }
 
+    @Override
+    public void onRadioButtonClicked(SelectorWithWidgetPreference selected) {
+        String selectedKey = selected.getKey();
+        int selectedWidth = getWidthForResoluitonKey(selectedKey);
+        if (!mDisplayObserver.setPendingResolutionChange(selectedWidth)) {
+          return;
+        }
+
+        super.onRadioButtonClicked(selected);
+    }
+
     /** Update the resolution image according display mode. */
     private void updateIllustrationImage(IllustrationPreference preference) {
         String key = getDefaultKey();
@@ -252,12 +267,13 @@
                 }
             };
 
-    private static final class DensityRestorer implements DisplayManager.DisplayListener {
+    private static final class DisplayObserver implements DisplayManager.DisplayListener {
         private final @Nullable Context mContext;
         private int mDefaultDensity;
         private int mCurrentIndex;
+        private AtomicInteger mPreviousWidth = new AtomicInteger(-1);
 
-        DensityRestorer(Context context) {
+        DisplayObserver(Context context) {
             mContext = context;
         }
 
@@ -301,26 +317,59 @@
                 return;
             }
 
+            if (!isDensityChanged() || !isResolutionChangeApplied()) {
+              return;
+            }
+
             restoreDensity();
+            stopObserve();
         }
 
         private void restoreDensity() {
-            if (mContext == null) {
-                return;
-            }
-
             final DisplayDensityUtils density = new DisplayDensityUtils(mContext);
-            if (density.getDefaultDensity() == mDefaultDensity) {
-                return;
-            }
-
             if (density.getValues()[mCurrentIndex] != density.getDefaultDensity()) {
                 DisplayDensityUtils.setForcedDisplayDensity(
                         Display.DEFAULT_DISPLAY, density.getValues()[mCurrentIndex]);
             }
 
             mDefaultDensity = density.getDefaultDensity();
-            stopObserve();
+        }
+
+        private boolean isDensityChanged() {
+            final DisplayDensityUtils density = new DisplayDensityUtils(mContext);
+            if (density.getDefaultDensity() == mDefaultDensity) {
+                return false;
+            }
+
+            return true;
+        }
+
+        private int getCurrentWidth() {
+            final DisplayManager dm = mContext.getSystemService(DisplayManager.class);
+            return dm.getDisplay(Display.DEFAULT_DISPLAY).getMode().getPhysicalWidth();
+        }
+
+        private boolean setPendingResolutionChange(int selectedWidth) {
+            int currentWidth = getCurrentWidth();
+
+            if (selectedWidth == currentWidth) {
+              return false;
+            }
+            if (mPreviousWidth.get() != -1 && !isResolutionChangeApplied()) {
+              return false;
+            }
+
+            mPreviousWidth.set(currentWidth);
+
+            return true;
+        }
+
+        private boolean isResolutionChangeApplied() {
+            if (mPreviousWidth.get() == getCurrentWidth()) {
+              return false;
+            }
+
+            return true;
         }
     }
 }
diff --git a/src/com/android/settings/enterprise/EnterprisePrivacySettings.java b/src/com/android/settings/enterprise/EnterprisePrivacySettings.java
index 92e4f4a..a154ded 100644
--- a/src/com/android/settings/enterprise/EnterprisePrivacySettings.java
+++ b/src/com/android/settings/enterprise/EnterprisePrivacySettings.java
@@ -77,6 +77,10 @@
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
+        if (mPrivacySettingsPreference instanceof PrivacySettingsFinancedPreference) {
+            return;
+        }
+
         replaceEnterprisePreferenceScreenTitle(
                 MANAGED_DEVICE_INFO, R.string.enterprise_privacy_settings);
 
diff --git a/src/com/android/settings/language/LanguageAndInputSettings.java b/src/com/android/settings/language/LanguageAndInputSettings.java
index 71b48f9..2d80da5 100644
--- a/src/com/android/settings/language/LanguageAndInputSettings.java
+++ b/src/com/android/settings/language/LanguageAndInputSettings.java
@@ -50,6 +50,7 @@
 
     private static final String KEY_KEYBOARDS_CATEGORY = "keyboards_category";
     private static final String KEY_SPEECH_CATEGORY = "speech_category";
+    private static final String KEY_ON_DEVICE_RECOGNITION = "odsr_settings";
     private static final String KEY_TEXT_TO_SPEECH = "tts_settings_summary";
     private static final String KEY_POINTER_CATEGORY = "pointer_category";
 
@@ -123,11 +124,21 @@
                 new DefaultVoiceInputPreferenceController(context, lifecycle);
         final TtsPreferenceController ttsPreferenceController =
                 new TtsPreferenceController(context, KEY_TEXT_TO_SPEECH);
+        final OnDeviceRecognitionPreferenceController onDeviceRecognitionPreferenceController =
+                new OnDeviceRecognitionPreferenceController(context, KEY_ON_DEVICE_RECOGNITION);
+
         controllers.add(defaultVoiceInputPreferenceController);
         controllers.add(ttsPreferenceController);
-        controllers.add(new PreferenceCategoryController(context,
-                KEY_SPEECH_CATEGORY).setChildren(
-                Arrays.asList(defaultVoiceInputPreferenceController, ttsPreferenceController)));
+        List<AbstractPreferenceController> speechCategoryChildren = new ArrayList<>(
+                List.of(defaultVoiceInputPreferenceController, ttsPreferenceController));
+
+        if (onDeviceRecognitionPreferenceController.isAvailable()) {
+            controllers.add(onDeviceRecognitionPreferenceController);
+            speechCategoryChildren.add(onDeviceRecognitionPreferenceController);
+        }
+
+        controllers.add(new PreferenceCategoryController(context, KEY_SPEECH_CATEGORY)
+                .setChildren(speechCategoryChildren));
 
         // Pointer
         final PointerSpeedController pointerController = new PointerSpeedController(context);
diff --git a/src/com/android/settings/language/OnDeviceRecognitionPreferenceController.java b/src/com/android/settings/language/OnDeviceRecognitionPreferenceController.java
new file mode 100644
index 0000000..3186639
--- /dev/null
+++ b/src/com/android/settings/language/OnDeviceRecognitionPreferenceController.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2022 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.language;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+import androidx.preference.Preference;
+
+import com.android.internal.R;
+import com.android.settings.core.BasePreferenceController;
+
+import java.util.ArrayList;
+import java.util.Optional;
+
+/** Controller of the On-device recognition preference. */
+public class OnDeviceRecognitionPreferenceController extends BasePreferenceController {
+
+    private static final String TAG = "OnDeviceRecognitionPreferenceController";
+
+    private Optional<Intent> mIntent;
+
+    public OnDeviceRecognitionPreferenceController(Context context, String preferenceKey) {
+        super(context, preferenceKey);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        if (mIntent == null) {
+            mIntent = Optional.ofNullable(onDeviceRecognitionIntent());
+        }
+        return mIntent.isPresent()
+                ? AVAILABLE
+                : CONDITIONALLY_UNAVAILABLE;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+        if (mIntent != null && mIntent.isPresent()) {
+            preference.setIntent(mIntent.get());
+        }
+    }
+
+    /**
+     * Create an {@link Intent} for the activity in the default on-device recognizer service if
+     * there is a properly defined speech recognition xml meta-data for that service.
+     *
+     * @return {@link Intent} if the proper activity is fount, {@code null} otherwise.
+     */
+    @Nullable
+    private Intent onDeviceRecognitionIntent() {
+        final String resString = mContext.getString(
+                R.string.config_defaultOnDeviceSpeechRecognitionService);
+
+        if (resString == null) {
+            Log.v(TAG, "No on-device recognizer, intent not created.");
+            return null;
+        }
+
+        final ComponentName defaultOnDeviceRecognizerComponentName =
+                ComponentName.unflattenFromString(resString);
+
+        if (defaultOnDeviceRecognizerComponentName == null) {
+            Log.v(TAG, "Invalid on-device recognizer string format, intent not created.");
+            return null;
+        }
+
+        final ArrayList<VoiceInputHelper.RecognizerInfo> validRecognitionServices =
+                VoiceInputHelper.validRecognitionServices(mContext);
+
+        if (validRecognitionServices.isEmpty()) {
+            Log.v(TAG, "No speech recognition services"
+                    + "with proper `recognition-service` meta-data found.");
+            return null;
+        }
+
+        // Filter the recognizer services which are in the same package as the default on-device
+        // speech recognizer and have a settings activity defined in the meta-data.
+        final ArrayList<VoiceInputHelper.RecognizerInfo> validOnDeviceRecognitionServices =
+                new ArrayList<>();
+        for (VoiceInputHelper.RecognizerInfo recognizerInfo: validRecognitionServices) {
+            if (!defaultOnDeviceRecognizerComponentName.getPackageName().equals(
+                    recognizerInfo.mService.packageName)) {
+                Log.v(TAG, String.format("Recognition service not in the same package as the "
+                        + "default on-device recognizer: %s.",
+                        recognizerInfo.mComponentName.flattenToString()));
+            } else if (recognizerInfo.mSettings == null) {
+                Log.v(TAG, String.format("Recognition service with no settings activity: %s.",
+                        recognizerInfo.mComponentName.flattenToString()));
+            } else {
+                validOnDeviceRecognitionServices.add(recognizerInfo);
+                Log.v(TAG, String.format("Recognition service in the same package as the default "
+                                + "on-device recognizer with settings activity: %s.",
+                        recognizerInfo.mSettings.flattenToString()));
+            }
+        }
+
+        if (validOnDeviceRecognitionServices.isEmpty()) {
+            Log.v(TAG, "No speech recognition services with proper `recognition-service` "
+                    + "meta-data found in the same package as the default on-device recognizer.");
+            return null;
+        }
+
+        // Not more than one proper recognition services should be found in the same
+        // package as the default on-device recognizer. If that happens,
+        // the first one which passed the filter will be selected.
+        if (validOnDeviceRecognitionServices.size() > 1) {
+            Log.w(TAG, "More than one recognition services with proper `recognition-service` "
+                    + "meta-data found in the same package as the default on-device recognizer.");
+        }
+        VoiceInputHelper.RecognizerInfo chosenRecognizer = validOnDeviceRecognitionServices.get(0);
+
+        return new Intent(Intent.ACTION_MAIN).setComponent(chosenRecognizer.mSettings);
+    }
+}
diff --git a/src/com/android/settings/language/VoiceInputHelper.java b/src/com/android/settings/language/VoiceInputHelper.java
index 7915ba4..289a2f9 100644
--- a/src/com/android/settings/language/VoiceInputHelper.java
+++ b/src/com/android/settings/language/VoiceInputHelper.java
@@ -29,6 +29,7 @@
 import android.speech.RecognitionService;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.Pair;
 import android.util.Xml;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -44,12 +45,11 @@
     static final String TAG = "VoiceInputHelper";
     final Context mContext;
 
-    final List<ResolveInfo> mAvailableRecognition;
-
     /**
      * Base info of the Voice Input provider.
      *
      * TODO: Remove this superclass as we only have 1 class now (RecognizerInfo).
+     * TODO: Group recognition service xml meta-data attributes in a single class.
      */
     public static class BaseInfo implements Comparable<BaseInfo> {
         public final ServiceInfo mService;
@@ -90,16 +90,12 @@
         }
     }
 
-    final ArrayList<RecognizerInfo> mAvailableRecognizerInfos = new ArrayList<>();
+    ArrayList<RecognizerInfo> mAvailableRecognizerInfos = new ArrayList<>();
 
     ComponentName mCurrentRecognizer;
 
     public VoiceInputHelper(Context context) {
         mContext = context;
-
-        mAvailableRecognition = mContext.getPackageManager().queryIntentServices(
-                new Intent(RecognitionService.SERVICE_INTERFACE),
-                PackageManager.GET_META_DATA);
     }
 
     /** Draws the UI of the Voice Input picker page. */
@@ -113,63 +109,120 @@
             mCurrentRecognizer = null;
         }
 
-        // Iterate through all the available recognizers and load up their info to show
-        // in the preference.
-        int size = mAvailableRecognition.size();
-        for (int i = 0; i < size; i++) {
-            ResolveInfo resolveInfo = mAvailableRecognition.get(i);
-            ComponentName comp = new ComponentName(resolveInfo.serviceInfo.packageName,
-                    resolveInfo.serviceInfo.name);
-            ServiceInfo si = resolveInfo.serviceInfo;
-            String settingsActivity = null;
-            // Always show in voice input settings unless specifically set to False.
-            boolean selectableAsDefault = true;
-            try (XmlResourceParser parser = si.loadXmlMetaData(mContext.getPackageManager(),
-                    RecognitionService.SERVICE_META_DATA)) {
-                if (parser == null) {
-                    throw new XmlPullParserException("No " + RecognitionService.SERVICE_META_DATA
-                            + " meta-data for " + si.packageName);
-                }
+        final ArrayList<RecognizerInfo> validRecognitionServices =
+                validRecognitionServices(mContext);
 
-                Resources res = mContext.getPackageManager().getResourcesForApplication(
-                        si.applicationInfo);
-
-                AttributeSet attrs = Xml.asAttributeSet(parser);
-
-                int type;
-                while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                        && type != XmlPullParser.START_TAG) {
-                    // Intentionally do nothing.
-                }
-
-                String nodeName = parser.getName();
-                if (!"recognition-service".equals(nodeName)) {
-                    throw new XmlPullParserException(
-                            "Meta-data does not start with recognition-service tag");
-                }
-
-                TypedArray array = res.obtainAttributes(attrs,
-                        com.android.internal.R.styleable.RecognitionService);
-                settingsActivity = array.getString(
-                        com.android.internal.R.styleable.RecognitionService_settingsActivity);
-                selectableAsDefault = array.getBoolean(
-                        com.android.internal.R.styleable.RecognitionService_selectableAsDefault,
-                        true);
-                array.recycle();
-            } catch (XmlPullParserException e) {
-                Log.e(TAG, "error parsing recognition service meta-data", e);
-            } catch (IOException e) {
-                Log.e(TAG, "error parsing recognition service meta-data", e);
-            } catch (PackageManager.NameNotFoundException e) {
-                Log.e(TAG, "error parsing recognition service meta-data", e);
-            }
-            // The current recognizer must always be shown in the settings, whatever its
-            // selectableAsDefault value is.
-            if (selectableAsDefault || comp.equals(mCurrentRecognizer)) {
-                mAvailableRecognizerInfos.add(new RecognizerInfo(mContext.getPackageManager(),
-                        resolveInfo.serviceInfo, settingsActivity, selectableAsDefault));
+        // Filter all recognizers which can be selected as default or are the current recognizer.
+        mAvailableRecognizerInfos = new ArrayList<>();
+        for (RecognizerInfo recognizerInfo: validRecognitionServices) {
+            if (recognizerInfo.mSelectableAsDefault || new ComponentName(
+                    recognizerInfo.mService.packageName, recognizerInfo.mService.name)
+                    .equals(mCurrentRecognizer)) {
+                mAvailableRecognizerInfos.add(recognizerInfo);
             }
         }
+
         Collections.sort(mAvailableRecognizerInfos);
     }
+
+    /**
+     * Query all services with {@link RecognitionService#SERVICE_INTERFACE} intent. Filter only
+     * those which have proper xml meta-data which start with a `recognition-service` tag.
+     * Filtered services are sorted by their labels in the ascending order.
+     *
+     * @param context {@link Context} inside which the settings app is run.
+     *
+     * @return {@link ArrayList}&lt;{@link RecognizerInfo}&gt;
+     * containing info about the filtered speech recognition services.
+     */
+    static ArrayList<RecognizerInfo> validRecognitionServices(Context context) {
+        final List<ResolveInfo> resolvedRecognitionServices =
+                context.getPackageManager().queryIntentServices(
+                        new Intent(RecognitionService.SERVICE_INTERFACE),
+                        PackageManager.GET_META_DATA);
+
+        final ArrayList<RecognizerInfo> validRecognitionServices = new ArrayList<>();
+
+        for (ResolveInfo resolveInfo: resolvedRecognitionServices) {
+            final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
+
+            final Pair<String, Boolean> recognitionServiceAttributes =
+                    parseRecognitionServiceXmlMetadata(context, serviceInfo);
+
+            if (recognitionServiceAttributes != null) {
+                validRecognitionServices.add(new RecognizerInfo(
+                        context.getPackageManager(),
+                        serviceInfo,
+                        recognitionServiceAttributes.first      /* settingsActivity */,
+                        recognitionServiceAttributes.second     /* selectableAsDefault */));
+            }
+        }
+
+        return validRecognitionServices;
+    }
+
+    /**
+     * Load recognition service's xml meta-data and parse it. Return the meta-data attributes,
+     * namely, `settingsActivity` {@link String} and `selectableAsDefault` {@link Boolean}.
+     *
+     * <p>Parsing fails if the meta-data for the given service is not found
+     * or the found meta-data does not start with a `recognition-service`.</p>
+     *
+     * @param context {@link Context} inside which the settings app is run.
+     * @param serviceInfo {@link ServiceInfo} containing info
+     * about the speech recognition service in question.
+     *
+     * @return {@link Pair}&lt;{@link String}, {@link Boolean}&gt;  containing `settingsActivity`
+     * and `selectableAsDefault` attributes if the parsing was successful, {@code null} otherwise.
+     */
+    private static Pair<String, Boolean> parseRecognitionServiceXmlMetadata(
+            Context context, ServiceInfo serviceInfo) {
+        // Default recognition service attribute values.
+        // Every recognizer can be selected unless specified otherwise.
+        String settingsActivity;
+        boolean selectableAsDefault = true;
+
+        // Parse xml meta-data.
+        try (XmlResourceParser parser = serviceInfo.loadXmlMetaData(
+                context.getPackageManager(), RecognitionService.SERVICE_META_DATA)) {
+            if (parser == null) {
+                throw new XmlPullParserException(String.format("No %s meta-data for %s package",
+                        RecognitionService.SERVICE_META_DATA, serviceInfo.packageName));
+            }
+
+            final Resources res = context.getPackageManager().getResourcesForApplication(
+                    serviceInfo.applicationInfo);
+            final AttributeSet attrs = Xml.asAttributeSet(parser);
+
+            // Xml meta-data must start with a `recognition-service tag`.
+            int type;
+            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                    && type != XmlPullParser.START_TAG) {
+                // Intentionally do nothing.
+            }
+
+            final String nodeName = parser.getName();
+            if (!"recognition-service".equals(nodeName)) {
+                throw new XmlPullParserException(String.format(
+                        "%s package meta-data does not start with a `recognition-service` tag",
+                        serviceInfo.packageName));
+            }
+
+            final TypedArray array = res.obtainAttributes(attrs,
+                    com.android.internal.R.styleable.RecognitionService);
+            settingsActivity = array.getString(
+                    com.android.internal.R.styleable.RecognitionService_settingsActivity);
+            selectableAsDefault = array.getBoolean(
+                    com.android.internal.R.styleable.RecognitionService_selectableAsDefault,
+                    selectableAsDefault);
+            array.recycle();
+        } catch (XmlPullParserException | IOException
+                | PackageManager.NameNotFoundException e) {
+            Log.e(TAG, String.format("Error parsing %s package recognition service meta-data",
+                    serviceInfo.packageName), e);
+            return null;
+        }
+
+        return Pair.create(settingsActivity, selectableAsDefault);
+    }
 }
diff --git a/src/com/android/settings/network/MobileNetworkIntentConverter.java b/src/com/android/settings/network/MobileNetworkIntentConverter.java
new file mode 100644
index 0000000..648ac61
--- /dev/null
+++ b/src/com/android/settings/network/MobileNetworkIntentConverter.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2022 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.network;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.ims.ImsRcsManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+
+import com.android.settings.Settings.MobileNetworkActivity;
+import com.android.settings.SettingsActivity;
+import com.android.settings.network.telephony.MobileNetworkUtils;
+
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Function;
+
+/**
+ * A Java {@link Function} for conversion between {@link Intent} to Settings,
+ * and within Settings itself.
+ */
+public class MobileNetworkIntentConverter implements Function<Intent, Intent> {
+    private static final String TAG = "MobileNetworkIntentConverter";
+
+    private static final ComponentName sTargetComponent = ComponentName
+            .createRelative("com.android.settings",
+                    MobileNetworkActivity.class.getTypeName());
+
+    /**
+     * These actions has better aligned with definitions within AndroidManifest.xml
+     */
+    private static final String [] sPotentialActions = new String [] {
+        null,
+        Intent.ACTION_MAIN,
+        android.provider.Settings.ACTION_NETWORK_OPERATOR_SETTINGS,
+        android.provider.Settings.ACTION_DATA_ROAMING_SETTINGS,
+        android.provider.Settings.ACTION_MMS_MESSAGE_SETTING,
+        ImsRcsManager.ACTION_SHOW_CAPABILITY_DISCOVERY_OPT_IN
+    };
+
+    private static final String RE_ROUTE_TAG = ":reroute:" + TAG;
+    private static final AtomicReference<String> mCachedClassName =
+            new AtomicReference<String>();
+
+    private final Context mAppContext;
+    private final ComponentName mComponent;
+
+    /**
+     * Constructor
+     * @param activity which receiving {@link Intent}
+     */
+    public MobileNetworkIntentConverter(@NonNull Activity activity) {
+        mAppContext = activity.getApplicationContext();
+        mComponent = activity.getComponentName();
+    }
+
+    /**
+     * API defined by {@link Function}.
+     * @param fromIntent is the {@link Intent} for convert.
+     * @return {@link Intent} for sending internally within Settings.
+     *      Return {@code null} when failure.
+     */
+    public Intent apply(Intent fromIntent) {
+        long startTime = SystemClock.elapsedRealtimeNanos();
+
+        Intent potentialReqIntent = null;
+        if (isAttachedToExposedComponents()) {
+            potentialReqIntent = convertFromDeepLink(fromIntent);
+        } else if (mayRequireConvert(fromIntent)) {
+            potentialReqIntent = fromIntent;
+        } else {
+            return null;
+        }
+
+        final Intent reqIntent = potentialReqIntent;
+        String action = reqIntent.getAction();
+
+        // Find out the subscription ID of request.
+        final int subId = extractSubscriptionId(reqIntent);
+
+        // Prepare the arguments Bundle.
+        Function<Intent, Intent> ops = Function.identity();
+
+        if (TextUtils.equals(action,
+                android.provider.Settings.ACTION_NETWORK_OPERATOR_SETTINGS)
+                || TextUtils.equals(action,
+                        android.provider.Settings.ACTION_DATA_ROAMING_SETTINGS)) {
+            // Accepted.
+            ops = ops.andThen(intent -> extractArguments(intent, subId))
+                     .andThen(args -> rePackIntent(args, reqIntent))
+                     .andThen(intent -> updateFragment(intent, mAppContext, subId));
+        } else if (TextUtils.equals(action,
+                android.provider.Settings.ACTION_MMS_MESSAGE_SETTING)) {
+            ops = ops.andThen(intent -> extractArguments(intent, subId))
+                     .andThen(args -> convertMmsArguments(args))
+                     .andThen(args -> rePackIntent(args, reqIntent))
+                     .andThen(intent -> updateFragment(intent, mAppContext, subId));
+        } else if (TextUtils.equals(action,
+                ImsRcsManager.ACTION_SHOW_CAPABILITY_DISCOVERY_OPT_IN)) {
+            ops = ops.andThen(intent -> extractArguments(intent, subId))
+                     .andThen(args -> supportContactDiscoveryDialog(args, mAppContext, subId))
+                     .andThen(args -> rePackIntent(args, reqIntent))
+                     .andThen(intent -> updateFragment(intent, mAppContext, subId));
+        } else if ((sTargetComponent.compareTo(mComponent) == 0)
+                && ((action == null) || Intent.ACTION_MAIN.equals(action))) {
+            Log.d(TAG, "Support default actions direct to this component");
+            ops = ops.andThen(intent -> extractArguments(intent, subId))
+                     .andThen(args -> rePackIntent(args, reqIntent))
+                     .andThen(intent -> replaceIntentAction(intent))
+                     .andThen(intent -> updateFragment(intent, mAppContext, subId));
+        } else {
+            return null;
+        }
+
+        if (!isAttachedToExposedComponents()) {
+            ops = ops.andThen(intent -> configForReRoute(intent));
+        }
+
+        Intent result = ops.apply(reqIntent);
+        if (result != null) {
+            long endTime = SystemClock.elapsedRealtimeNanos();
+            Log.d(TAG, mComponent.toString() + " intent conversion: "
+                    + (endTime - startTime) + " ns");
+        }
+        return result;
+    }
+
+    @VisibleForTesting
+    protected boolean isAttachedToExposedComponents() {
+        return (sTargetComponent.compareTo(mComponent) == 0);
+    }
+
+    protected int extractSubscriptionId(Intent reqIntent) {
+        return reqIntent.getIntExtra(android.provider.Settings.EXTRA_SUB_ID,
+                SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+    }
+
+    protected Bundle extractArguments(Intent reqIntent, int subId) {
+        // Duplicate from SettingsActivity#getIntent()
+        Bundle args = reqIntent.getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS);
+        Bundle result = (args != null) ? new Bundle(args) : new Bundle();
+        result.putParcelable("intent", reqIntent);
+        result.putInt(android.provider.Settings.EXTRA_SUB_ID, subId);
+        return result;
+    }
+
+    protected Bundle convertMmsArguments(Bundle args) {
+        // highlight "mms_message" preference.
+        args.putString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY,
+                MobileNetworkActivity.EXTRA_MMS_MESSAGE);
+        return args;
+    }
+
+    @VisibleForTesting
+    protected boolean mayShowContactDiscoveryDialog(Context context, int subId) {
+        // If this activity was launched using ACTION_SHOW_CAPABILITY_DISCOVERY_OPT_IN, show the
+        // associated dialog only if the opt-in has not been granted yet.
+        return MobileNetworkUtils.isContactDiscoveryVisible(context, subId)
+                // has the user already enabled this configuration?
+                && !MobileNetworkUtils.isContactDiscoveryEnabled(context, subId);
+    }
+
+    protected Bundle supportContactDiscoveryDialog(Bundle args, Context context, int subId) {
+        boolean showDialog = mayShowContactDiscoveryDialog(context, subId);
+        Log.d(TAG, "maybeShowContactDiscoveryDialog subId=" + subId + ", show=" + showDialog);
+        args.putBoolean(MobileNetworkActivity.EXTRA_SHOW_CAPABILITY_DISCOVERY_OPT_IN,
+                showDialog);
+        return args;
+    }
+
+    protected Intent rePackIntent(Bundle args, Intent reqIntent) {
+        Intent intent = new Intent(reqIntent);
+        intent.setComponent(sTargetComponent);
+        intent.putExtra(android.provider.Settings.EXTRA_SUB_ID,
+                args.getInt(android.provider.Settings.EXTRA_SUB_ID));
+        intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);
+        return intent;
+    }
+
+    protected Intent replaceIntentAction(Intent intent) {
+        intent.setAction(android.provider.Settings.ACTION_NETWORK_OPERATOR_SETTINGS);
+        return intent;
+    }
+
+    @VisibleForTesting
+    protected CharSequence getFragmentTitle(Context context, int subId) {
+        SubscriptionInfo subInfo = SubscriptionUtil.getSubscriptionOrDefault(context, subId);
+        return SubscriptionUtil.getUniqueSubscriptionDisplayName(subInfo, context);
+    }
+
+    protected Intent updateFragment(Intent intent, Context context, int subId) {
+        if (intent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE) == null) {
+            CharSequence title = getFragmentTitle(context, subId);
+            if (title != null) {
+                intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE, title.toString());
+            }
+        }
+        intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT, getFragmentClass(context));
+        return intent;
+    }
+
+    protected String getFragmentClass(Context context) {
+        String className = mCachedClassName.get();
+        if (className != null) {
+            return className;
+        }
+        try {
+            ActivityInfo ai = context.getPackageManager()
+                    .getActivityInfo(sTargetComponent, PackageManager.GET_META_DATA);
+            if (ai != null && ai.metaData != null) {
+                className = ai.metaData.getString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS);
+                if (className != null) {
+                    mCachedClassName.set(className);
+                }
+                return className;
+            }
+        } catch (NameNotFoundException nnfe) {
+            // No recovery
+            Log.d(TAG, "Cannot get Metadata for: " + sTargetComponent.toString());
+        }
+        return null;
+    }
+
+    protected Intent configForReRoute(Intent intent) {
+        if (intent.hasExtra(RE_ROUTE_TAG)) {
+            Log.d(TAG, "Skip re-routed intent " + intent);
+            return null;
+        }
+        return intent.putExtra(RE_ROUTE_TAG, intent.getAction())
+                .setComponent(null);
+    }
+
+    protected static boolean mayRequireConvert(Intent intent) {
+        if (intent == null) {
+            return false;
+        }
+        final String action = intent.getAction();
+        return Arrays.stream(sPotentialActions).anyMatch(potentialAction ->
+                        TextUtils.equals(action, potentialAction)
+                );
+    }
+
+    protected Intent convertFromDeepLink(Intent intent) {
+        if (intent == null) {
+            return null;
+        }
+        if (!TextUtils.equals(intent.getAction(),
+                android.provider.Settings.ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY)) {
+            return intent;
+        }
+        try {
+            return Intent.parseUri(intent.getStringExtra(
+                android.provider.Settings.EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI),
+                Intent.URI_INTENT_SCHEME);
+        } catch (URISyntaxException exception) {
+            Log.d(TAG, "Intent URI corrupted", exception);
+        }
+        return null;
+    }
+}
diff --git a/src/com/android/settings/network/telephony/RoamingDialogFragment.java b/src/com/android/settings/network/telephony/RoamingDialogFragment.java
index bd45226..3e9875e 100644
--- a/src/com/android/settings/network/telephony/RoamingDialogFragment.java
+++ b/src/com/android/settings/network/telephony/RoamingDialogFragment.java
@@ -72,7 +72,9 @@
                 .setIconAttribute(android.R.attr.alertDialogIcon)
                 .setPositiveButton(android.R.string.yes, this)
                 .setNegativeButton(android.R.string.no, this);
-        return builder.create();
+        AlertDialog dialog = builder.create();
+        dialog.setCanceledOnTouchOutside(false);
+        return dialog;
     }
 
     @Override
diff --git a/src/com/android/settings/security/ConfirmSimDeletionPreferenceController.java b/src/com/android/settings/security/ConfirmSimDeletionPreferenceController.java
index a7185e3..3bf1563 100644
--- a/src/com/android/settings/security/ConfirmSimDeletionPreferenceController.java
+++ b/src/com/android/settings/security/ConfirmSimDeletionPreferenceController.java
@@ -19,6 +19,7 @@
 import android.app.KeyguardManager;
 import android.app.settings.SettingsEnums;
 import android.content.Context;
+import android.os.UserManager;
 import android.provider.Settings;
 
 import androidx.preference.Preference;
@@ -39,6 +40,8 @@
             ConfirmationSimDeletionPredicate.KEY_CONFIRM_SIM_DELETION;
     private boolean mConfirmationDefaultOn;
     private MetricsFeatureProvider mMetricsFeatureProvider;
+    private UserManager mUserManager;
+    private KeyguardManager mKeyguardManager;
 
     public ConfirmSimDeletionPreferenceController(Context context, String key) {
         super(context, key);
@@ -46,6 +49,9 @@
                 context.getResources()
                         .getBoolean(R.bool.config_sim_deletion_confirmation_default_on);
         mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
+
+        mUserManager = context.getSystemService(UserManager.class);
+        mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
     }
 
     @Override
@@ -99,8 +105,7 @@
 
     @Override
     public void updateState(Preference preference) {
-        final KeyguardManager keyguardManager = mContext.getSystemService(KeyguardManager.class);
-        if (!keyguardManager.isKeyguardSecure()) {
+        if (!mKeyguardManager.isKeyguardSecure() && mUserManager.isGuestUser()) {
             preference.setEnabled(false);
             if (preference instanceof TwoStatePreference) {
                 ((TwoStatePreference) preference).setChecked(false);
diff --git a/src/com/android/settings/shortcut/CreateShortcutPreferenceController.java b/src/com/android/settings/shortcut/CreateShortcutPreferenceController.java
index c871e9f..89ee19b 100644
--- a/src/com/android/settings/shortcut/CreateShortcutPreferenceController.java
+++ b/src/com/android/settings/shortcut/CreateShortcutPreferenceController.java
@@ -46,6 +46,7 @@
 import com.android.settings.R;
 import com.android.settings.Settings;
 import com.android.settings.Settings.TetherSettingsActivity;
+import com.android.settings.activityembedding.ActivityEmbeddingUtils;
 import com.android.settings.core.BasePreferenceController;
 import com.android.settings.gestures.OneHandedSettingsUtils;
 import com.android.settings.overlay.FeatureFactory;
@@ -127,7 +128,7 @@
                     return false;
                 }
                 final Intent shortcutIntent = createResultIntent(
-                        buildShortcutIntent(info),
+                        buildShortcutIntent(uiContext, info),
                         info, clickTarget.getTitle());
                 mHost.setResult(Activity.RESULT_OK, shortcutIntent);
                 logCreateShortcut(info);
@@ -210,10 +211,14 @@
                 info.activityInfo.name);
     }
 
-    private static Intent buildShortcutIntent(ResolveInfo info) {
-        return new Intent(SHORTCUT_PROBE)
+    private static Intent buildShortcutIntent(Context context, ResolveInfo info) {
+        Intent intent = new Intent(SHORTCUT_PROBE)
                 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP)
                 .setClassName(info.activityInfo.packageName, info.activityInfo.name);
+        if (ActivityEmbeddingUtils.isEmbeddingActivityEnabled(context)) {
+            intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
+        }
+        return intent;
     }
 
     private static ShortcutInfo createShortcutInfo(Context context, Intent shortcutIntent,
@@ -277,8 +282,8 @@
                 ResolveInfo ri = context.getPackageManager().resolveActivity(si.getIntent(), 0);
 
                 if (ri != null) {
-                    updatedShortcuts.add(createShortcutInfo(context, buildShortcutIntent(ri), ri,
-                            si.getShortLabel()));
+                    updatedShortcuts.add(createShortcutInfo(context,
+                            buildShortcutIntent(context, ri), ri, si.getShortLabel()));
                 }
             }
         }
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilityButtonFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilityButtonFragmentTest.java
index 473b566..e34767e 100644
--- a/tests/robotests/src/com/android/settings/accessibility/AccessibilityButtonFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityButtonFragmentTest.java
@@ -16,26 +16,83 @@
 
 package com.android.settings.accessibility;
 
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
+
 import static com.google.common.truth.Truth.assertThat;
 
-import android.content.Context;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
 
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Bundle;
+
+import androidx.fragment.app.FragmentActivity;
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
 import androidx.test.core.app.ApplicationProvider;
 
 import com.android.settings.R;
 import com.android.settings.testutils.XmlTestUtils;
+import com.android.settings.testutils.shadow.ShadowFragment;
 
+import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
 
 import java.util.List;
 
 /** Tests for {@link AccessibilityButtonFragment}. */
+@Config(shadows = ShadowFragment.class)
 @RunWith(RobolectricTestRunner.class)
 public class AccessibilityButtonFragmentTest {
 
-    private Context mContext = ApplicationProvider.getApplicationContext();
+    @Rule
+    public MockitoRule mMockitoRule = MockitoJUnit.rule();
+    @Spy
+    private final Context mContext = ApplicationProvider.getApplicationContext();
+    @Spy
+    private Resources mResources = spy(mContext.getResources());
+    private AccessibilityButtonFragment mFragment;
+
+    @Before
+    public void setUp() {
+        mFragment = spy(new TestAccessibilityButtonFragment(mContext));
+        when(mFragment.getResources()).thenReturn(mResources);
+        when(mFragment.getActivity()).thenReturn(Robolectric.setupActivity(FragmentActivity.class));
+    }
+
+    @Test
+    public void onCreate_navigationGestureEnabled_setCorrectTitle() {
+        when(mResources.getInteger(com.android.internal.R.integer.config_navBarInteractionMode))
+                .thenReturn(NAV_BAR_MODE_GESTURAL);
+
+        mFragment.onAttach(mContext);
+        mFragment.onCreate(Bundle.EMPTY);
+
+        assertThat(mFragment.getActivity().getTitle().toString()).isEqualTo(
+                mContext.getString(R.string.accessibility_button_gesture_title));
+    }
+
+    @Test
+    public void onCreate_navigationGestureDisabled_setCorrectTitle() {
+        when(mResources.getInteger(com.android.internal.R.integer.config_navBarInteractionMode))
+                .thenReturn(NAV_BAR_MODE_2BUTTON);
+
+        mFragment.onAttach(mContext);
+        mFragment.onCreate(Bundle.EMPTY);
+
+        assertThat(mFragment.getActivity().getTitle().toString()).isEqualTo(
+                mContext.getString(R.string.accessibility_button_title));
+    }
 
     @Test
     public void getNonIndexableKeys_existInXmlLayout() {
@@ -47,4 +104,37 @@
 
         assertThat(keys).containsAtLeastElementsIn(niks);
     }
+
+    private static class TestAccessibilityButtonFragment extends AccessibilityButtonFragment {
+
+        private final Context mContext;
+        private final PreferenceManager mPreferenceManager;
+
+        TestAccessibilityButtonFragment(Context context) {
+            super();
+            mContext = context;
+            mPreferenceManager = new PreferenceManager(context);
+            mPreferenceManager.setPreferences(mPreferenceManager.createPreferenceScreen(context));
+        }
+
+        @Override
+        public int getPreferenceScreenResId() {
+            return R.xml.placeholder_prefs;
+        }
+
+        @Override
+        public PreferenceScreen getPreferenceScreen() {
+            return mPreferenceManager.getPreferenceScreen();
+        }
+
+        @Override
+        public PreferenceManager getPreferenceManager() {
+            return mPreferenceManager;
+        }
+
+        @Override
+        public Context getContext() {
+            return mContext;
+        }
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizardTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizardTest.java
new file mode 100644
index 0000000..508b229
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizardTest.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2022 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.accessibility;
+
+import static com.android.settings.accessibility.AccessibilitySettingsForSetupWizard.SCREEN_READER_PACKAGE_NAME;
+import static com.android.settings.accessibility.AccessibilitySettingsForSetupWizard.SCREEN_READER_SERVICE_NAME;
+import static com.android.settings.accessibility.AccessibilitySettingsForSetupWizard.SELECT_TO_SPEAK_PACKAGE_NAME;
+import static com.android.settings.accessibility.AccessibilitySettingsForSetupWizard.SELECT_TO_SPEAK_SERVICE_NAME;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.view.accessibility.AccessibilityManager;
+
+import androidx.fragment.app.FragmentActivity;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.R;
+import com.android.settingslib.RestrictedPreference;
+
+import com.google.android.setupdesign.GlifPreferenceLayout;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for {@link AccessibilitySettingsForSetupWizard}.
+ */
+@RunWith(RobolectricTestRunner.class)
+public class AccessibilitySettingsForSetupWizardTest {
+
+    private static final ComponentName TEST_SCREEN_READER_COMPONENT_NAME = new ComponentName(
+            SCREEN_READER_PACKAGE_NAME, SCREEN_READER_SERVICE_NAME);
+    private static final ComponentName TEST_SELECT_TO_SPEAK_COMPONENT_NAME = new ComponentName(
+            SELECT_TO_SPEAK_PACKAGE_NAME, SELECT_TO_SPEAK_SERVICE_NAME);
+    private final Context mContext = ApplicationProvider.getApplicationContext();
+    private final List<AccessibilityServiceInfo> mAccessibilityServices = new ArrayList<>();
+    @Rule
+    public MockitoRule mMockitoRule = MockitoJUnit.rule();
+    @Mock
+    private AccessibilityManager mAccessibilityManager;
+    @Mock
+    private FragmentActivity mActivity;
+    @Mock
+    private GlifPreferenceLayout mGlifLayoutView;
+    private AccessibilitySettingsForSetupWizard mFragment;
+
+    @Before
+    public void setUp() {
+        mFragment = spy(new TestAccessibilitySettingsForSetupWizard(mContext));
+        doReturn(mAccessibilityManager).when(mActivity).getSystemService(
+                AccessibilityManager.class);
+        when(mAccessibilityManager.getInstalledAccessibilityServiceList()).thenReturn(
+                mAccessibilityServices);
+        doReturn(mActivity).when(mFragment).getActivity();
+    }
+
+    @Test
+    public void onViewCreated_verifyAction() {
+        mFragment.onViewCreated(mGlifLayoutView, null);
+
+        verify(mGlifLayoutView).setHeaderText(
+                mContext.getString(R.string.vision_settings_title));
+        verify(mGlifLayoutView).setDescriptionText(
+                mContext.getString(R.string.vision_settings_description));
+    }
+
+    @Test
+    public void onResume_accessibilityServiceListInstalled_returnExpectedValue() {
+        addEnabledServiceInfo(TEST_SCREEN_READER_COMPONENT_NAME, true);
+        addEnabledServiceInfo(TEST_SELECT_TO_SPEAK_COMPONENT_NAME, true);
+        mFragment.onAttach(mContext);
+        mFragment.onViewCreated(mGlifLayoutView, null);
+
+        mFragment.onResume();
+
+        assertRestrictedPreferenceMatch(mFragment.mScreenReaderPreference,
+                TEST_SCREEN_READER_COMPONENT_NAME.getPackageName(),
+                TEST_SCREEN_READER_COMPONENT_NAME.flattenToString());
+        assertRestrictedPreferenceMatch(mFragment.mSelectToSpeakPreference,
+                TEST_SELECT_TO_SPEAK_COMPONENT_NAME.getPackageName(),
+                TEST_SELECT_TO_SPEAK_COMPONENT_NAME.flattenToString());
+    }
+
+    @Test
+    public void onResume_accessibilityServiceListNotInstalled_returnNull() {
+        mFragment.onAttach(mContext);
+        mFragment.onViewCreated(mGlifLayoutView, null);
+
+        mFragment.onResume();
+
+        assertThat(mFragment.mScreenReaderPreference.getKey()).isNull();
+        assertThat(mFragment.mSelectToSpeakPreference.getKey()).isNull();
+    }
+
+    private void addEnabledServiceInfo(ComponentName componentName, boolean isAccessibilityTool) {
+        final AccessibilityServiceInfo a11yServiceInfo = mock(AccessibilityServiceInfo.class);
+        when(a11yServiceInfo.getComponentName()).thenReturn(componentName);
+        when(a11yServiceInfo.isAccessibilityTool()).thenReturn(isAccessibilityTool);
+        final ResolveInfo resolveInfo = mock(ResolveInfo.class);
+        when(a11yServiceInfo.getResolveInfo()).thenReturn(resolveInfo);
+        resolveInfo.serviceInfo = mock(ServiceInfo.class);
+        resolveInfo.serviceInfo.packageName = componentName.getPackageName();
+        resolveInfo.serviceInfo.name = componentName.getClassName();
+        when(resolveInfo.loadLabel(mActivity.getPackageManager())).thenReturn(
+                componentName.getPackageName());
+        mAccessibilityServices.add(a11yServiceInfo);
+    }
+
+    private void assertRestrictedPreferenceMatch(RestrictedPreference preference, String title,
+            String key) {
+        assertThat(preference.getTitle().toString()).isEqualTo(title);
+        assertThat(preference.getKey()).isEqualTo(key);
+        assertThat(preference.getExtras().getString(AccessibilitySettings.EXTRA_TITLE))
+                .isEqualTo(title);
+        assertThat(preference.getExtras().getString(AccessibilitySettings.EXTRA_PREFERENCE_KEY))
+                .isEqualTo(key);
+    }
+
+    private static class TestAccessibilitySettingsForSetupWizard
+            extends AccessibilitySettingsForSetupWizard {
+
+        private final Context mContext;
+        private final PreferenceManager mPreferenceManager;
+
+        TestAccessibilitySettingsForSetupWizard(Context context) {
+            super();
+            mContext = context;
+            mPreferenceManager = new PreferenceManager(context);
+            mPreferenceManager.setPreferences(mPreferenceManager.createPreferenceScreen(context));
+            mDisplayMagnificationPreference = new Preference(context);
+            mScreenReaderPreference = new RestrictedPreference(context);
+            mSelectToSpeakPreference = new RestrictedPreference(context);
+        }
+
+        @Override
+        public int getPreferenceScreenResId() {
+            return R.xml.placeholder_prefs;
+        }
+
+        @Override
+        public PreferenceScreen getPreferenceScreen() {
+            return mPreferenceManager.getPreferenceScreen();
+        }
+
+        @Override
+        public PreferenceManager getPreferenceManager() {
+            return mPreferenceManager;
+        }
+
+        @Override
+        public Context getContext() {
+            return mContext;
+        }
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentForSetupWizardTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentForSetupWizardTest.java
new file mode 100644
index 0000000..b8bb8d2
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentForSetupWizardTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2022 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.accessibility;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.R;
+import com.android.settings.SettingsActivity;
+import com.android.settings.testutils.shadow.ShadowSettingsPreferenceFragment;
+import com.android.settings.widget.SettingsMainSwitchBar;
+import com.android.settingslib.widget.TopIntroPreference;
+
+import com.google.android.setupdesign.GlifPreferenceLayout;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+/**
+ * Tests for {@link ToggleScreenMagnificationPreferenceFragmentForSetupWizard}.
+ */
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowSettingsPreferenceFragment.class})
+public class ToggleScreenMagnificationPreferenceFragmentForSetupWizardTest {
+
+    private final Context mContext = ApplicationProvider.getApplicationContext();
+    @Rule
+    public MockitoRule mMockitoRule = MockitoJUnit.rule();
+    @Mock
+    private SettingsActivity mActivity;
+    @Mock
+    private GlifPreferenceLayout mGlifLayoutView;
+    @Mock
+    private SettingsMainSwitchBar mSwitchBar;
+    private ToggleScreenMagnificationPreferenceFragmentForSetupWizard mFragment;
+
+    @Before
+    public void setUp() {
+        mFragment =
+                spy(new TestToggleScreenMagnificationPreferenceFragmentForSetupWizard(mContext));
+        doReturn(mActivity).when(mFragment).getActivity();
+        when(mActivity.getSwitchBar()).thenReturn(mSwitchBar);
+    }
+
+    @Test
+    public void onViewCreated_verifyAction() {
+        mFragment.onViewCreated(mGlifLayoutView, null);
+
+        verify(mGlifLayoutView).setHeaderText(
+                mContext.getString(R.string.accessibility_screen_magnification_title));
+        verify(mGlifLayoutView).setDescriptionText(
+                mContext.getString(R.string.accessibility_screen_magnification_intro_text));
+        verify(mGlifLayoutView).setDividerInsets(Integer.MAX_VALUE, 0);
+        assertThat(mFragment.mTopIntroPreference.isVisible()).isFalse();
+        assertThat(mFragment.mSettingsPreference.isVisible()).isFalse();
+        assertThat(mFragment.mFollowingTypingSwitchPreference.isVisible()).isFalse();
+    }
+
+    private static class TestToggleScreenMagnificationPreferenceFragmentForSetupWizard
+            extends ToggleScreenMagnificationPreferenceFragmentForSetupWizard {
+
+        private final Context mContext;
+        private final PreferenceManager mPreferenceManager;
+
+        TestToggleScreenMagnificationPreferenceFragmentForSetupWizard(Context context) {
+            super();
+            mContext = context;
+            mPreferenceManager = new PreferenceManager(context);
+            mPreferenceManager.setPreferences(mPreferenceManager.createPreferenceScreen(context));
+            mTopIntroPreference = new TopIntroPreference(context);
+            mSettingsPreference = new Preference(context);
+            mFollowingTypingSwitchPreference = new SwitchPreference(context);
+        }
+
+        @Override
+        public int getPreferenceScreenResId() {
+            return R.xml.placeholder_prefs;
+        }
+
+        @Override
+        public PreferenceScreen getPreferenceScreen() {
+            return mPreferenceManager.getPreferenceScreen();
+        }
+
+        @Override
+        public PreferenceManager getPreferenceManager() {
+            return mPreferenceManager;
+        }
+
+        @Override
+        public Context getContext() {
+            return mContext;
+        }
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleScreenReaderPreferenceFragmentForSetupWizardTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleScreenReaderPreferenceFragmentForSetupWizardTest.java
new file mode 100644
index 0000000..017a781
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/ToggleScreenReaderPreferenceFragmentForSetupWizardTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2022 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.accessibility;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.Bundle;
+
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.R;
+import com.android.settings.SettingsActivity;
+import com.android.settings.widget.SettingsMainSwitchBar;
+import com.android.settings.widget.SettingsMainSwitchPreference;
+import com.android.settingslib.widget.TopIntroPreference;
+
+import com.google.android.setupdesign.GlifPreferenceLayout;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+
+/**
+ * Tests for {@link ToggleScreenReaderPreferenceFragmentForSetupWizard}.
+ */
+@RunWith(RobolectricTestRunner.class)
+public class ToggleScreenReaderPreferenceFragmentForSetupWizardTest {
+
+    private static final String TEST_TITLE = "test_title";
+    private final Context mContext = ApplicationProvider.getApplicationContext();
+    @Rule
+    public MockitoRule mMockitoRule = MockitoJUnit.rule();
+    @Mock
+    private SettingsActivity mActivity;
+    @Mock
+    private GlifPreferenceLayout mGlifLayoutView;
+    @Mock
+    private SettingsMainSwitchBar mSwitchBar;
+    private ToggleScreenReaderPreferenceFragmentForSetupWizard mFragment;
+
+    @Before
+    public void setUp() {
+        mFragment = spy(new TestToggleScreenReaderPreferenceFragmentForSetupWizard(mContext));
+        doReturn(mActivity).when(mFragment).getActivity();
+        when(mActivity.getSwitchBar()).thenReturn(mSwitchBar);
+    }
+
+    @Test
+    public void onViewCreated_verifyAction() {
+        mFragment.onViewCreated(mGlifLayoutView, null);
+
+        verify(mGlifLayoutView).setHeaderText(TEST_TITLE);
+        verify(mGlifLayoutView).setDescriptionText(
+                mContext.getString(R.string.talkback_summary));
+        verify(mGlifLayoutView).setDividerInsets(Integer.MAX_VALUE, 0);
+        assertThat(mFragment.mTopIntroPreference.isVisible()).isFalse();
+    }
+
+    private static class TestToggleScreenReaderPreferenceFragmentForSetupWizard
+            extends ToggleScreenReaderPreferenceFragmentForSetupWizard {
+
+        private final Context mContext;
+        private final PreferenceManager mPreferenceManager;
+
+        TestToggleScreenReaderPreferenceFragmentForSetupWizard(Context context) {
+            super();
+            mContext = context;
+            mPreferenceManager = new PreferenceManager(context);
+            mPreferenceManager.setPreferences(mPreferenceManager.createPreferenceScreen(context));
+            mTopIntroPreference = new TopIntroPreference(context);
+            mToggleServiceSwitchPreference = new SettingsMainSwitchPreference(context);
+            Bundle bundle = new Bundle();
+            bundle.putString(AccessibilitySettings.EXTRA_TITLE, TEST_TITLE);
+            setArguments(bundle);
+        }
+
+        @Override
+        public int getPreferenceScreenResId() {
+            return R.xml.placeholder_prefs;
+        }
+
+        @Override
+        public PreferenceScreen getPreferenceScreen() {
+            return mPreferenceManager.getPreferenceScreen();
+        }
+
+        @Override
+        public PreferenceManager getPreferenceManager() {
+            return mPreferenceManager;
+        }
+
+        @Override
+        public Context getContext() {
+            return mContext;
+        }
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleSelectToSpeakPreferenceFragmentForSetupWizardTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleSelectToSpeakPreferenceFragmentForSetupWizardTest.java
new file mode 100644
index 0000000..85abbd6
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/ToggleSelectToSpeakPreferenceFragmentForSetupWizardTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2022 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.accessibility;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.Bundle;
+
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.R;
+import com.android.settings.SettingsActivity;
+import com.android.settings.widget.SettingsMainSwitchBar;
+import com.android.settings.widget.SettingsMainSwitchPreference;
+import com.android.settingslib.widget.TopIntroPreference;
+
+import com.google.android.setupdesign.GlifPreferenceLayout;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+
+/**
+ * Tests for {@link ToggleSelectToSpeakPreferenceFragmentForSetupWizard}.
+ */
+@RunWith(RobolectricTestRunner.class)
+public class ToggleSelectToSpeakPreferenceFragmentForSetupWizardTest {
+
+    private static final String TEST_TITLE = "test_title";
+    private final Context mContext = ApplicationProvider.getApplicationContext();
+    @Rule
+    public MockitoRule mMockitoRule = MockitoJUnit.rule();
+    @Mock
+    private SettingsActivity mActivity;
+    @Mock
+    private GlifPreferenceLayout mGlifLayoutView;
+    @Mock
+    private SettingsMainSwitchBar mSwitchBar;
+    private ToggleSelectToSpeakPreferenceFragmentForSetupWizard mFragment;
+
+    @Before
+    public void setUp() {
+        mFragment = spy(new TestToggleSelectToSpeakPreferenceFragmentForSetupWizard(mContext));
+        doReturn(mActivity).when(mFragment).getActivity();
+        when(mActivity.getSwitchBar()).thenReturn(mSwitchBar);
+    }
+
+    @Test
+    public void onViewCreated_verifyAction() {
+        mFragment.onViewCreated(mGlifLayoutView, null);
+
+        verify(mGlifLayoutView).setHeaderText(TEST_TITLE);
+        verify(mGlifLayoutView).setDescriptionText(
+                mContext.getString(R.string.select_to_speak_summary));
+        verify(mGlifLayoutView).setDividerInsets(Integer.MAX_VALUE, 0);
+        assertThat(mFragment.mTopIntroPreference.isVisible()).isFalse();
+    }
+
+    private static class TestToggleSelectToSpeakPreferenceFragmentForSetupWizard
+            extends ToggleSelectToSpeakPreferenceFragmentForSetupWizard {
+
+        private final Context mContext;
+        private final PreferenceManager mPreferenceManager;
+
+        TestToggleSelectToSpeakPreferenceFragmentForSetupWizard(Context context) {
+            super();
+            mContext = context;
+            mPreferenceManager = new PreferenceManager(context);
+            mPreferenceManager.setPreferences(mPreferenceManager.createPreferenceScreen(context));
+            mToggleServiceSwitchPreference = new SettingsMainSwitchPreference(context);
+            mTopIntroPreference = new TopIntroPreference(context);
+            Bundle bundle = new Bundle();
+            bundle.putString(AccessibilitySettings.EXTRA_TITLE, TEST_TITLE);
+            setArguments(bundle);
+        }
+
+        @Override
+        public int getPreferenceScreenResId() {
+            return R.xml.placeholder_prefs;
+        }
+
+        @Override
+        public PreferenceScreen getPreferenceScreen() {
+            return mPreferenceManager.getPreferenceScreen();
+        }
+
+        @Override
+        public PreferenceManager getPreferenceManager() {
+            return mPreferenceManager;
+        }
+
+        @Override
+        public Context getContext() {
+            return mContext;
+        }
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/applications/AppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/AppsPreferenceControllerTest.java
index 75da4d8..d0bb754 100644
--- a/tests/robotests/src/com/android/settings/applications/AppsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/AppsPreferenceControllerTest.java
@@ -70,7 +70,7 @@
     private PreferenceScreen mScreen;
 
     private AppsPreferenceController mController;
-    private List<UsageStats> mUsageStats;
+    private List<RecentAppStatsMixin.UsageStatsWrapper> mUsageStats;
     private PreferenceCategory mRecentAppsCategory;
     private PreferenceCategory mGeneralCategory;
     private Preference mSeeAllPref;
@@ -147,15 +147,15 @@
         final UsageStats stat3 = new UsageStats();
         stat1.mLastTimeUsed = System.currentTimeMillis();
         stat1.mPackageName = "pkg.class";
-        mUsageStats.add(stat1);
+        mUsageStats.add(statsWrapperOf(stat1));
 
         stat2.mLastTimeUsed = System.currentTimeMillis();
         stat2.mPackageName = "pkg.class2";
-        mUsageStats.add(stat2);
+        mUsageStats.add(statsWrapperOf(stat2));
 
         stat3.mLastTimeUsed = System.currentTimeMillis();
         stat3.mPackageName = "pkg.class3";
-        mUsageStats.add(stat3);
+        mUsageStats.add(statsWrapperOf(stat3));
         when(mAppState.getEntry(stat1.mPackageName, UserHandle.myUserId()))
                 .thenReturn(mAppEntry);
         when(mAppState.getEntry(stat2.mPackageName, UserHandle.myUserId()))
@@ -164,4 +164,9 @@
                 .thenReturn(mAppEntry);
         mAppEntry.info = mApplicationInfo;
     }
+
+    private static RecentAppStatsMixin.UsageStatsWrapper statsWrapperOf(
+            UsageStats stats) {
+        return new RecentAppStatsMixin.UsageStatsWrapper(stats, /* userId= */ 0);
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/applications/RecentAppStatsMixinTest.java b/tests/robotests/src/com/android/settings/applications/RecentAppStatsMixinTest.java
index 0fb2a7e..6b94bce 100644
--- a/tests/robotests/src/com/android/settings/applications/RecentAppStatsMixinTest.java
+++ b/tests/robotests/src/com/android/settings/applications/RecentAppStatsMixinTest.java
@@ -21,6 +21,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
@@ -53,6 +54,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Optional;
 
 @RunWith(RobolectricTestRunner.class)
 public class RecentAppStatsMixinTest {
@@ -60,6 +62,8 @@
     @Mock
     private UsageStatsManager mUsageStatsManager;
     @Mock
+    private UsageStatsManager mWorkUsageStatsManager;
+    @Mock
     private UserManager mUserManager;
     @Mock
     private ApplicationsState mAppState;
@@ -87,6 +91,8 @@
         when(mUserManager.getProfileIdsWithDisabled(anyInt())).thenReturn(new int[]{});
 
         mRecentAppStatsMixin = new RecentAppStatsMixin(context, 3 /* maximumApps */);
+        ReflectionHelpers.setField(mRecentAppStatsMixin, "mWorkUsageStatsManager",
+                Optional.of(mWorkUsageStatsManager));
     }
 
     @Test
@@ -99,7 +105,7 @@
         // stat1 is valid app.
         when(mAppState.getEntry(stat1.mPackageName, UserHandle.myUserId()))
                 .thenReturn(mAppEntry);
-        when(mPackageManager.resolveActivity(any(Intent.class), anyInt()))
+        when(mPackageManager.resolveActivityAsUser(any(Intent.class), anyInt(), anyInt()))
                 .thenReturn(new ResolveInfo());
         when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
                 .thenReturn(stats);
@@ -134,7 +140,7 @@
                 .thenReturn(mAppEntry);
         when(mAppState.getEntry(stat3.mPackageName, UserHandle.myUserId()))
                 .thenReturn(mAppEntry);
-        when(mPackageManager.resolveActivity(any(Intent.class), anyInt()))
+        when(mPackageManager.resolveActivityAsUser(any(Intent.class), anyInt(), anyInt()))
                 .thenReturn(new ResolveInfo());
         when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
                 .thenReturn(stats);
@@ -170,7 +176,7 @@
                 .thenReturn(mAppEntry);
         when(mAppState.getEntry(stat3.mPackageName, UserHandle.myUserId()))
                 .thenReturn(null);
-        when(mPackageManager.resolveActivity(any(Intent.class), anyInt()))
+        when(mPackageManager.resolveActivityAsUser(any(Intent.class), anyInt(), anyInt()))
                 .thenReturn(new ResolveInfo());
         when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
                 .thenReturn(stats);
@@ -272,7 +278,7 @@
         when(mPackageManager.getInstalledModules(anyInt() /* flags */))
                 .thenReturn(modules);
 
-        when(mPackageManager.resolveActivity(any(Intent.class), anyInt()))
+        when(mPackageManager.resolveActivityAsUser(any(Intent.class), anyInt(), anyInt()))
                 .thenReturn(new ResolveInfo());
         when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
                 .thenReturn(stats);
@@ -296,7 +302,7 @@
         // stat1, stat2 are valid apps. stat3 is invalid.
         when(mAppState.getEntry(stat1.mPackageName, UserHandle.myUserId()))
                 .thenReturn(mAppEntry);
-        when(mPackageManager.resolveActivity(any(Intent.class), anyInt()))
+        when(mPackageManager.resolveActivityAsUser(any(Intent.class), anyInt(), anyInt()))
                 .thenReturn(new ResolveInfo());
         when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
                 .thenReturn(stats);
@@ -306,4 +312,97 @@
 
         assertThat(mRecentAppStatsMixin.mRecentApps).isEmpty();
     }
+
+    @Test
+    public void loadDisplayableRecentApps_usePersonalAndWorkApps_shouldBeSortedByLastTimeUse() {
+        final List<UsageStats> personalStats = new ArrayList<>();
+        final UsageStats stats1 = new UsageStats();
+        final UsageStats stats2 = new UsageStats();
+        stats1.mLastTimeUsed = System.currentTimeMillis();
+        stats1.mPackageName = "personal.pkg.class";
+        personalStats.add(stats1);
+
+        stats2.mLastTimeUsed = System.currentTimeMillis() - 5000;
+        stats2.mPackageName = "personal.pkg.class2";
+        personalStats.add(stats2);
+
+        final List<UsageStats> workStats = new ArrayList<>();
+        final UsageStats stat3 = new UsageStats();
+        stat3.mLastTimeUsed = System.currentTimeMillis() - 2000;
+        stat3.mPackageName = "work.pkg.class3";
+        workStats.add(stat3);
+
+        when(mAppState.getEntry(anyString(), anyInt()))
+                .thenReturn(mAppEntry);
+        when(mPackageManager.resolveActivityAsUser(any(Intent.class), anyInt(), anyInt()))
+                .thenReturn(new ResolveInfo());
+        // personal app stats
+        when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
+                .thenReturn(personalStats);
+        // work app stats
+        when(mWorkUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
+                .thenReturn(workStats);
+        mAppEntry.info = mApplicationInfo;
+
+        mRecentAppStatsMixin.loadDisplayableRecentApps(3);
+
+        assertThat(mRecentAppStatsMixin.mRecentApps.size()).isEqualTo(3);
+        assertThat(mRecentAppStatsMixin.mRecentApps.get(0).mUsageStats.mPackageName).isEqualTo(
+                "personal.pkg.class");
+        assertThat(mRecentAppStatsMixin.mRecentApps.get(1).mUsageStats.mPackageName).isEqualTo(
+                "work.pkg.class3");
+        assertThat(mRecentAppStatsMixin.mRecentApps.get(2).mUsageStats.mPackageName).isEqualTo(
+                "personal.pkg.class2");
+    }
+
+    @Test
+    public void loadDisplayableRecentApps_usePersonalAndWorkApps_shouldBeUniquePerProfile() {
+        final String firstAppPackageName = "app1.pkg.class";
+        final String secondAppPackageName = "app2.pkg.class";
+        final List<UsageStats> personalStats = new ArrayList<>();
+        final UsageStats personalStatsFirstApp = new UsageStats();
+        final UsageStats personalStatsFirstAppOlderUse = new UsageStats();
+        final UsageStats personalStatsSecondApp = new UsageStats();
+        personalStatsFirstApp.mLastTimeUsed = System.currentTimeMillis();
+        personalStatsFirstApp.mPackageName = firstAppPackageName;
+        personalStats.add(personalStatsFirstApp);
+
+        personalStatsFirstAppOlderUse.mLastTimeUsed = System.currentTimeMillis() - 5000;
+        personalStatsFirstAppOlderUse.mPackageName = firstAppPackageName;
+        personalStats.add(personalStatsFirstAppOlderUse);
+
+        personalStatsSecondApp.mLastTimeUsed = System.currentTimeMillis() - 2000;
+        personalStatsSecondApp.mPackageName = secondAppPackageName;
+        personalStats.add(personalStatsSecondApp);
+
+        final List<UsageStats> workStats = new ArrayList<>();
+        final UsageStats workStatsSecondApp = new UsageStats();
+        workStatsSecondApp.mLastTimeUsed = System.currentTimeMillis() - 1000;
+        workStatsSecondApp.mPackageName = secondAppPackageName;
+        workStats.add(workStatsSecondApp);
+
+        when(mAppState.getEntry(anyString(), anyInt()))
+                .thenReturn(mAppEntry);
+        when(mPackageManager.resolveActivityAsUser(any(Intent.class), anyInt(), anyInt()))
+                .thenReturn(new ResolveInfo());
+        // personal app stats
+        when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
+                .thenReturn(personalStats);
+        // work app stats
+        when(mWorkUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
+                .thenReturn(workStats);
+        mAppEntry.info = mApplicationInfo;
+
+        mRecentAppStatsMixin.loadDisplayableRecentApps(3);
+
+        // The output should have the first app once since the duplicate use in the personal profile
+        // is filtered out, and the second app twice - once for each profile.
+        assertThat(mRecentAppStatsMixin.mRecentApps.size()).isEqualTo(3);
+        assertThat(mRecentAppStatsMixin.mRecentApps.get(0).mUsageStats.mPackageName).isEqualTo(
+                firstAppPackageName);
+        assertThat(mRecentAppStatsMixin.mRecentApps.get(1).mUsageStats.mPackageName).isEqualTo(
+                secondAppPackageName);
+        assertThat(mRecentAppStatsMixin.mRecentApps.get(2).mUsageStats.mPackageName).isEqualTo(
+                secondAppPackageName);
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java
index 3cdff6e..4427127 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java
@@ -86,6 +86,7 @@
         mShadowCachedBluetoothDeviceManager = Shadow.extract(
                 Utils.getLocalBtManager(mContext).getCachedDeviceManager());
         mCachedDevices = new ArrayList<>();
+        mCachedDevices.add(mCachedBluetoothDevice);
         mShadowCachedBluetoothDeviceManager.setCachedDevicesCopy(mCachedDevices);
         Pair<Drawable, String> pairs = new Pair<>(mDrawable, "fake_device");
 
@@ -109,7 +110,6 @@
         when(mBluetoothDeviceUpdater.
                 isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
         when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true);
-        mCachedDevices.add(mCachedBluetoothDevice);
 
         mBluetoothDeviceUpdater.onAudioModeChanged();
 
@@ -122,7 +122,6 @@
         when(mBluetoothDeviceUpdater.
                 isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
         when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true);
-        mCachedDevices.add(mCachedBluetoothDevice);
 
         mBluetoothDeviceUpdater.onAudioModeChanged();
 
@@ -135,7 +134,6 @@
         when(mBluetoothDeviceUpdater.
                 isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
         when(mCachedBluetoothDevice.isConnectedA2dpDevice()).thenReturn(true);
-        mCachedDevices.add(mCachedBluetoothDevice);
 
         mBluetoothDeviceUpdater.onAudioModeChanged();
 
@@ -148,7 +146,6 @@
         when(mBluetoothDeviceUpdater.
                 isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
         when(mCachedBluetoothDevice.isConnectedA2dpDevice()).thenReturn(true);
-        mCachedDevices.add(mCachedBluetoothDevice);
 
         mBluetoothDeviceUpdater.onAudioModeChanged();
 
@@ -261,6 +258,35 @@
     }
 
     @Test
+    public void
+            onProfileConnectionStateChanged_deviceIsNotInList_notInCall_invokesRemovePreference() {
+        mAudioManager.setMode(AudioManager.MODE_NORMAL);
+        when(mBluetoothDeviceUpdater
+                .isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
+        when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true);
+        mCachedDevices.clear();
+
+        mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice,
+                BluetoothProfile.STATE_CONNECTED, BluetoothProfile.LE_AUDIO);
+
+        verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice);
+    }
+
+    @Test
+    public void onProfileConnectionStateChanged_deviceIsNotInList_inCall_invokesRemovePreference() {
+        mAudioManager.setMode(AudioManager.MODE_IN_CALL);
+        when(mBluetoothDeviceUpdater
+                .isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
+        when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true);
+        mCachedDevices.clear();
+
+        mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice,
+                BluetoothProfile.STATE_CONNECTED, BluetoothProfile.LE_AUDIO);
+
+        verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice);
+    }
+
+    @Test
     public void onProfileConnectionStateChanged_deviceDisconnected_removePreference() {
         mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice,
                 BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.A2DP);
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsCompanionAppsControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsCompanionAppsControllerTest.java
index 3fa306f..86829b4 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsCompanionAppsControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsCompanionAppsControllerTest.java
@@ -109,6 +109,7 @@
                 /* deviceProfile */ "",
                 /* selfManaged */ false,
                 /* notifyOnDeviceNearby */ true,
+                /* revoked */ false,
                 /* timeApprovedMs */ System.currentTimeMillis(),
                 /* lastTimeConnected */ Long.MAX_VALUE);
 
diff --git a/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java
index 98f1fe3..7472dc1 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java
@@ -90,6 +90,7 @@
                 Utils.getLocalBtManager(mContext).getCachedDeviceManager());
         doReturn(mContext).when(mDashboardFragment).getContext();
         mCachedDevices = new ArrayList<>();
+        mCachedDevices.add(mCachedBluetoothDevice);
 
         when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
         when(mCachedBluetoothDevice.getAddress()).thenReturn(MAC_ADDRESS);
@@ -108,7 +109,6 @@
         when(mBluetoothDeviceUpdater.
                 isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
         when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true);
-        mCachedDevices.add(mCachedBluetoothDevice);
 
         mBluetoothDeviceUpdater.onAudioModeChanged();
 
@@ -121,7 +121,6 @@
         when(mBluetoothDeviceUpdater.
                 isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
         when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true);
-        mCachedDevices.add(mCachedBluetoothDevice);
 
         mBluetoothDeviceUpdater.onAudioModeChanged();
 
@@ -134,7 +133,6 @@
         when(mBluetoothDeviceUpdater.
                 isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
         when(mCachedBluetoothDevice.isConnectedA2dpDevice()).thenReturn(true);
-        mCachedDevices.add(mCachedBluetoothDevice);
 
         mBluetoothDeviceUpdater.onAudioModeChanged();
 
@@ -147,7 +145,6 @@
         when(mBluetoothDeviceUpdater.
                 isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
         when(mCachedBluetoothDevice.isConnectedA2dpDevice()).thenReturn(true);
-        mCachedDevices.add(mCachedBluetoothDevice);
 
         mBluetoothDeviceUpdater.onAudioModeChanged();
 
@@ -168,6 +165,20 @@
     }
 
     @Test
+    public void onProfileConnectionStateChanged_deviceIsNotInList_inCall_invokesRemovePreference() {
+        mAudioManager.setMode(AudioManager.MODE_IN_CALL);
+        when(mBluetoothDeviceUpdater.
+                isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
+        when(mCachedBluetoothDevice.isConnectedA2dpDevice()).thenReturn(true);
+        mCachedDevices.clear();
+
+        mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice,
+                BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP);
+
+        verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice);
+    }
+
+    @Test
     public void onProfileConnectionStateChanged_a2dpDeviceConnected_notInCall_removePreference() {
         mAudioManager.setMode(AudioManager.MODE_NORMAL);
         when(mBluetoothDeviceUpdater.
@@ -260,6 +271,35 @@
 
         verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice);
     }
+    @Test
+    public void onProfileConnectionStateChanged_deviceIsNotInList_inCall_invokesRemovesPreference()
+    {
+        mAudioManager.setMode(AudioManager.MODE_IN_CALL);
+        when(mBluetoothDeviceUpdater
+                .isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
+        when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true);
+        mCachedDevices.clear();
+
+        mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice,
+                BluetoothProfile.STATE_CONNECTED, BluetoothProfile.LE_AUDIO);
+
+        verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice);
+    }
+
+    @Test
+    public void onProfileConnectionStateChanged_deviceIsNotInList_notInCall_invokesRemovesPreference
+            () {
+        mAudioManager.setMode(AudioManager.MODE_NORMAL);
+        when(mBluetoothDeviceUpdater
+                .isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
+        when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true);
+        mCachedDevices.clear();
+
+        mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice,
+                BluetoothProfile.STATE_CONNECTED, BluetoothProfile.LE_AUDIO);
+
+        verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice);
+    }
 
     @Test
     public void onProfileConnectionStateChanged_deviceDisconnected_removePreference() {
diff --git a/tests/robotests/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdaterTest.java
index da7516b..255a0be 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdaterTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdaterTest.java
@@ -77,6 +77,7 @@
     private Context mContext;
     private SavedBluetoothDeviceUpdater mBluetoothDeviceUpdater;
     private BluetoothDevicePreference mPreference;
+    private List<CachedBluetoothDevice> mCachedDevices = new ArrayList<>();
 
     @Before
     public void setUp() {
@@ -99,6 +100,10 @@
                 false, BluetoothDevicePreference.SortType.TYPE_DEFAULT);
         doNothing().when(mBluetoothDeviceUpdater).addPreference(any());
         doNothing().when(mBluetoothDeviceUpdater).removePreference(any());
+        mCachedDevices.add(mCachedBluetoothDevice);
+        when(mBluetoothManager.getCachedDeviceManager()).thenReturn(mDeviceManager);
+        when(mDeviceManager.getCachedDevicesCopy()).thenReturn(mCachedDevices);
+
     }
 
     @Test
@@ -144,6 +149,31 @@
     }
 
     @Test
+    public void
+            onProfileConnectionStateChanged_leDeviceDisconnected_inDeviceList_invokesAddPreference()
+    {
+        when(mBluetoothDevice.isConnected()).thenReturn(false);
+
+        mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice,
+                BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.LE_AUDIO);
+
+        verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice,
+                BluetoothDevicePreference.SortType.TYPE_NO_SORT);
+    }
+
+    @Test
+    public void
+    onProfileConnectionStateChanged_deviceDisconnected_notInDeviceList_invokesRemovePreference() {
+        when(mBluetoothDevice.isConnected()).thenReturn(false);
+        mCachedDevices.clear();
+
+        mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice,
+                BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.LE_AUDIO);
+
+        verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice);
+    }
+
+    @Test
     public void onClick_Preference_setConnect() {
         mBluetoothDeviceUpdater.onPreferenceClick(mPreference);
 
diff --git a/tests/robotests/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceControllerTest.java
index b9c4edc..1f50bed 100644
--- a/tests/robotests/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceControllerTest.java
@@ -150,7 +150,8 @@
                 new TimeZoneCapabilitiesAndConfig(capabilities, configuration);
 
         when(mTimeManager.getTimeZoneCapabilitiesAndConfig()).thenReturn(capabilitiesAndConfig);
-        assertThat(mController.getSummary().toString()).isEmpty();
+        assertThat(mController.getSummary()).isEqualTo(
+                mContext.getString(R.string.location_time_zone_detection_auto_is_on));
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/development/BluetoothMaxConnectedAudioDevicesPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/BluetoothMaxConnectedAudioDevicesPreferenceControllerTest.java
index 53494ab..72477b9 100644
--- a/tests/robotests/src/com/android/settings/development/BluetoothMaxConnectedAudioDevicesPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/BluetoothMaxConnectedAudioDevicesPreferenceControllerTest.java
@@ -70,8 +70,8 @@
     mPreference.setEntryValues(R.array.bluetooth_max_connected_audio_devices_values);
     // Retrieve default max connected audio devices to a test controlled value
     try {
-      Resources res = mSpyContext.getPackageManager().getResourcesForApplication("com.android.bluetooth.services");
-      TEST_MAX_CONNECTED_AUDIO_DEVICES = res.getInteger(res.getIdentifier("config_bluetooth_max_connected_audio_devices", "integer", "com.android.bluetooth.services"));
+      Resources res = mSpyContext.getPackageManager().getResourcesForApplication("com.android.bluetooth");
+      TEST_MAX_CONNECTED_AUDIO_DEVICES = res.getInteger(res.getIdentifier("config_bluetooth_max_connected_audio_devices", "integer", "com.android.bluetooth"));
     } catch (PackageManager.NameNotFoundException e) {
       e.printStackTrace();
     }
diff --git a/tests/robotests/src/com/android/settings/enterprise/EnterprisePrivacySettingsTest.java b/tests/robotests/src/com/android/settings/enterprise/EnterprisePrivacySettingsTest.java
index e028c62..b3de184 100644
--- a/tests/robotests/src/com/android/settings/enterprise/EnterprisePrivacySettingsTest.java
+++ b/tests/robotests/src/com/android/settings/enterprise/EnterprisePrivacySettingsTest.java
@@ -17,18 +17,21 @@
 package com.android.settings.enterprise;
 
 import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
+import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
 import android.content.Context;
+import android.os.Bundle;
 import android.provider.SearchIndexableResource;
+import android.widget.FrameLayout;
 
+import androidx.appcompat.app.AppCompatActivity;
 import androidx.test.core.app.ApplicationProvider;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -42,9 +45,10 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.android.controller.ActivityController;
 
-import java.util.ArrayList;
 import java.util.List;
 
 @RunWith(RobolectricTestRunner.class)
@@ -54,33 +58,33 @@
 
     @Mock
     private DevicePolicyManager mDevicePolicyManager;
-    @Mock
-    private PrivacySettingsPreference mPrivacySettingsPreference;
     private FakeFeatureFactory mFeatureFactory;
     private EnterprisePrivacySettings mSettings;
     private Context mContext;
+    private TestActivity mActivity;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mContext = spy(ApplicationProvider.getApplicationContext());
+        mContext = ApplicationProvider.getApplicationContext();
         mFeatureFactory = FakeFeatureFactory.setupForTest();
         mSettings = new EnterprisePrivacySettings();
-        mSettings.mPrivacySettingsPreference = mPrivacySettingsPreference;
+        mSettings.mPrivacySettingsPreference = new PrivacySettingsEnterprisePreference(mContext);
 
-        when(mContext.getSystemService(DevicePolicyManager.class)).thenReturn(mDevicePolicyManager);
-        when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
-        when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser())
-                .thenReturn(DEVICE_OWNER_COMPONENT);
-        when(mDevicePolicyManager.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
-                .thenReturn(DEVICE_OWNER_TYPE_DEFAULT);
+        ActivityController<TestActivity> controller = Robolectric.buildActivity(
+                TestActivity.class).create();
+        mActivity = controller.get();
+
+        mActivity
+                .getSupportFragmentManager()
+                .beginTransaction()
+                .add(TestActivity.CONTAINER_VIEW_ID, mSettings)
+                .commit();
+        controller.start();
     }
 
     @Test
     public void verifyConstants() {
-        when(mPrivacySettingsPreference.getPreferenceScreenResId())
-                .thenReturn(R.xml.enterprise_privacy_settings);
-
         assertThat(mSettings.getMetricsCategory())
                 .isEqualTo(MetricsEvent.ENTERPRISE_PRIVACY_SETTINGS);
         assertThat(mSettings.getLogTag()).isEqualTo("EnterprisePrivacySettings");
@@ -90,7 +94,7 @@
     }
 
     @Test
-    public void isPageEnabled_hasDeviceOwner_shouldReturnTrue() {
+    public void isPageEnabled_hasDeviceOwner_returnsTrue() {
         when(mFeatureFactory.enterprisePrivacyFeatureProvider.hasDeviceOwner())
                 .thenReturn(true);
 
@@ -99,7 +103,7 @@
     }
 
     @Test
-    public void isPageEnabled_noDeviceOwner_shouldReturnFalse() {
+    public void isPageEnabled_noDeviceOwner_returnsFalse() {
         when(mDevicePolicyManager.isDeviceManaged()).thenReturn(false);
         when(mFeatureFactory.enterprisePrivacyFeatureProvider.hasDeviceOwner())
                 .thenReturn(false);
@@ -109,36 +113,105 @@
     }
 
     @Test
-    public void getPreferenceControllers() {
-        final List<AbstractPreferenceController> controllers = new ArrayList<>();
-        controllers.add(new NetworkLogsPreferenceController(mContext));
-        when(mPrivacySettingsPreference.createPreferenceControllers(anyBoolean()))
-                .thenReturn(controllers);
-
+    public void getPreferenceControllers_returnsEnterprisePreferenceControllers() {
         final List<AbstractPreferenceController> privacyControllers =
                 mSettings.createPreferenceControllers(mContext);
 
-        assertThat(privacyControllers).isNotNull();
-        assertThat(privacyControllers.size()).isEqualTo(1);
-        assertThat(controllers.get(0)).isInstanceOf(NetworkLogsPreferenceController.class);
+        verifyEnterprisePreferenceControllers(privacyControllers);
     }
 
     @Test
     public void
             getSearchIndexProviderPreferenceControllers_returnsEnterpriseSearchIndexPreferenceControllers() {
+        Context context = spy(ApplicationProvider.getApplicationContext());
+        setupPrivacyPreference(context, DEVICE_OWNER_TYPE_DEFAULT);
+
         final List<AbstractPreferenceController> controllers =
             EnterprisePrivacySettings.SEARCH_INDEX_DATA_PROVIDER
-                .getPreferenceControllers(mContext);
+                .getPreferenceControllers(context);
 
         verifyEnterprisePreferenceControllers(controllers);
     }
 
     @Test
+    public void
+            getSearchIndexProviderPreferenceControllers_returnsFinancedSearchIndexPreferenceControllers() {
+        Context context = spy(ApplicationProvider.getApplicationContext());
+        setupPrivacyPreference(context, DEVICE_OWNER_TYPE_FINANCED);
+
+        final List<AbstractPreferenceController> controllers =
+                EnterprisePrivacySettings.SEARCH_INDEX_DATA_PROVIDER
+                        .getPreferenceControllers(context);
+
+        verifyFinancedPreferenceControllers(controllers);
+    }
+
+    @Test
     public void getXmlResourcesToIndex_returnsEnterpriseXmlResources() {
+        Context context = spy(ApplicationProvider.getApplicationContext());
+        setupPrivacyPreference(context, DEVICE_OWNER_TYPE_DEFAULT);
+
         final List<SearchIndexableResource> searchIndexableResources =
                 EnterprisePrivacySettings.SEARCH_INDEX_DATA_PROVIDER
-                        .getXmlResourcesToIndex(mContext, true);
+                        .getXmlResourcesToIndex(context, true);
 
         verifyEnterpriseSearchIndexableResources(searchIndexableResources);
     }
+
+    @Test
+    public void getXmlResourcesToIndex_returnsFinancedXmlResources() {
+        Context context = spy(ApplicationProvider.getApplicationContext());
+        setupPrivacyPreference(context, DEVICE_OWNER_TYPE_FINANCED);
+
+        final List<SearchIndexableResource> searchIndexableResources =
+                EnterprisePrivacySettings.SEARCH_INDEX_DATA_PROVIDER
+                        .getXmlResourcesToIndex(context, true);
+
+        verifyFinancedSearchIndexableResources(searchIndexableResources);
+    }
+
+    @Test
+    public void onCreate_enterprisePrivacyPreference_updatesTitle() {
+        mSettings.onCreate(new Bundle());
+
+        assertThat(mActivity.getTitle())
+                .isEqualTo(mContext.getText(R.string.enterprise_privacy_settings));
+    }
+
+    @Test
+    public void onCreate_financedPrivacyPreference_doesNotUpdateTitle() {
+        mSettings.mPrivacySettingsPreference = new PrivacySettingsFinancedPreference(mContext);
+
+        mSettings.onCreate(new Bundle());
+
+        assertThat(mActivity.getTitle())
+                .isEqualTo(mContext.getText(R.string.financed_privacy_settings));
+    }
+
+    private void setupPrivacyPreference(Context context, int deviceOwnerType) {
+        when(context.getSystemService(DevicePolicyManager.class)).thenReturn(mDevicePolicyManager);
+        when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
+        when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser())
+                .thenReturn(DEVICE_OWNER_COMPONENT);
+        when(mDevicePolicyManager.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
+                .thenReturn(deviceOwnerType);
+    }
+
+    private static final class TestActivity extends AppCompatActivity {
+
+        private static final int CONTAINER_VIEW_ID = 1234;
+
+        @Override
+        protected void onCreate(Bundle bundle) {
+            super.onCreate(bundle);
+
+            FrameLayout frameLayout = new FrameLayout(this);
+            frameLayout.setId(CONTAINER_VIEW_ID);
+
+            // Need to set the Theme.AppCompat theme (or descendant) with this activity, otherwise
+            // a {@link IllegalStateException} is thrown when setting the content view.
+            setTheme(R.style.Theme_AppCompat_Light);
+            setContentView(frameLayout);
+        }
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSliceTest.java
index cbd4390..2d5a0e9 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSliceTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSliceTest.java
@@ -46,8 +46,10 @@
 import androidx.slice.widget.SliceLiveData;
 
 import com.android.settings.R;
+import com.android.settings.bluetooth.Utils;
 import com.android.settings.testutils.SliceTester;
 import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
+import com.android.settings.testutils.shadow.ShadowCachedBluetoothDeviceManager;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 
 import org.junit.After;
@@ -67,7 +69,7 @@
 import java.util.List;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = ShadowBluetoothAdapter.class)
+@Config(shadows = {ShadowBluetoothAdapter.class, ShadowCachedBluetoothDeviceManager.class})
 public class BluetoothDevicesSliceTest {
 
     private static final String BLUETOOTH_MOCK_ADDRESS = "00:11:00:11:00:11";
@@ -111,6 +113,9 @@
             mShadowBluetoothAdapter.setEnabled(true);
             mShadowBluetoothAdapter.setState(BluetoothAdapter.STATE_ON);
         }
+        final ShadowCachedBluetoothDeviceManager shadowCachedBluetoothDeviceManager =
+                Shadow.extract(Utils.getLocalBtManager(mContext).getCachedDeviceManager());
+        shadowCachedBluetoothDeviceManager.setCachedDevicesCopy(mBluetoothDeviceList);
     }
 
     @After
diff --git a/tests/unit/src/com/android/settings/network/MobileNetworkIntentConverterTest.java b/tests/unit/src/com/android/settings/network/MobileNetworkIntentConverterTest.java
new file mode 100644
index 0000000..1800156
--- /dev/null
+++ b/tests/unit/src/com/android/settings/network/MobileNetworkIntentConverterTest.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2022 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.network;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.telephony.ims.ImsRcsManager;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settings.Settings.MobileNetworkActivity;
+import com.android.settings.SettingsActivity;
+import com.android.settings.Utils;
+import com.android.settings.network.telephony.MobileNetworkSettings;
+
+import java.util.Arrays;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class MobileNetworkIntentConverterTest {
+
+    private static final String ACTIONS_ALLOWED [] = {
+        Intent.ACTION_MAIN,
+        Settings.ACTION_NETWORK_OPERATOR_SETTINGS,
+        Settings.ACTION_DATA_ROAMING_SETTINGS,
+        Settings.ACTION_MMS_MESSAGE_SETTING,
+        ImsRcsManager.ACTION_SHOW_CAPABILITY_DISCOVERY_OPT_IN
+    };
+
+    private static final int TEST_SUBSCRIPTION_ID = 3;
+
+    private static final CharSequence TEST_TITLE_CHAR_SEQUENCE =
+            "Test Title".subSequence(0, 10);
+
+    @Mock
+    private Activity mActivity;
+
+    private MobileNetworkIntentConverter mIntentConverter;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        Context context = spy(ApplicationProvider.getApplicationContext());
+        ComponentName componentName = ComponentName.createRelative(Utils.SETTINGS_PACKAGE_NAME,
+                MobileNetworkActivity.class.getTypeName());
+
+        doReturn(context).when(mActivity).getApplicationContext();
+        doReturn(componentName).when(mActivity).getComponentName();
+
+        mIntentConverter = new MobileNetworkIntentConverter(mActivity) {
+            @Override
+            protected boolean isAttachedToExposedComponents() {
+                return false;
+            }
+        };
+    }
+
+    @Test
+    public void converter_returnNull_whenNotInterested() {
+        Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE);
+        assertThat(mIntentConverter.apply(intent)).isEqualTo(null);
+    }
+
+    @Test
+    public void converter_acceptableIntent_whenInterested() {
+        Arrays.stream(ACTIONS_ALLOWED).forEach(action -> {
+            Intent intent = new Intent(action);
+            assertThat(mIntentConverter.apply(intent)).isNotEqualTo(null);
+        });
+    }
+
+    @Test
+    public void convertSubscriptionId_fromIntentExtra_copyToBundleArgument() {
+        Intent intent = new Intent(ACTIONS_ALLOWED[0]);
+        intent.putExtra(Settings.EXTRA_SUB_ID, TEST_SUBSCRIPTION_ID);
+
+        Intent convertedIntent = mIntentConverter.apply(intent);
+
+        Bundle args = convertedIntent.getBundleExtra(
+                SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS);
+        assertThat(args.getInt(Settings.EXTRA_SUB_ID)).isEqualTo(TEST_SUBSCRIPTION_ID);
+
+        int intExtra = convertedIntent.getIntExtra(
+                Settings.EXTRA_SUB_ID, TEST_SUBSCRIPTION_ID - 1);
+        assertThat(intExtra).isEqualTo(TEST_SUBSCRIPTION_ID);
+    }
+
+    @Test
+    public void supportMms_addExtra_whenIntentForMms() {
+        Intent intent = new Intent(Settings.ACTION_MMS_MESSAGE_SETTING);
+
+        Intent convertedIntent = mIntentConverter.apply(intent);
+
+        Bundle args = convertedIntent.getBundleExtra(
+                    SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS);
+        assertThat(args).isNotEqualTo(null);
+        assertThat(args.getString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY)).isEqualTo(
+                    MobileNetworkActivity.EXTRA_MMS_MESSAGE);
+    }
+
+    @Test
+    public void supportContacts_addExtra_whenIntentForContacts() {
+        Intent intent = new Intent(ImsRcsManager.ACTION_SHOW_CAPABILITY_DISCOVERY_OPT_IN);
+        MobileNetworkIntentConverter converter = new MobileNetworkIntentConverter(mActivity) {
+            @Override
+            protected boolean isAttachedToExposedComponents() {
+                return false;
+            }
+            @Override
+            protected boolean mayShowContactDiscoveryDialog(Context context, int subId) {
+                return true;
+            }
+        };
+
+        Intent convertedIntent = converter.apply(intent);
+
+        Bundle args = convertedIntent.getBundleExtra(
+                    SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS);
+        assertThat(args).isNotEqualTo(null);
+        assertThat(args.getBoolean(MobileNetworkActivity.EXTRA_SHOW_CAPABILITY_DISCOVERY_OPT_IN))
+                .isEqualTo(true);
+    }
+
+    @Test
+    public void convertFormat_forSettings_fragmentPresentation() {
+        MobileNetworkIntentConverter converter = new MobileNetworkIntentConverter(mActivity) {
+            @Override
+            protected boolean isAttachedToExposedComponents() {
+                return false;
+            }
+            @Override
+            protected CharSequence getFragmentTitle(Context context, int subId) {
+                return TEST_TITLE_CHAR_SEQUENCE;
+            }
+        };
+
+        Intent intent = new Intent(ACTIONS_ALLOWED[0]);
+
+        Intent convertedIntent = converter.apply(intent);
+
+        assertThat(convertedIntent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE))
+                .isEqualTo(TEST_TITLE_CHAR_SEQUENCE.toString());
+        assertThat(convertedIntent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT))
+                .isEqualTo(MobileNetworkSettings.class.getTypeName());
+    }
+
+    @Test
+    public void convertFormat_deepLink_unwrapIntent() {
+        MobileNetworkIntentConverter converter = new MobileNetworkIntentConverter(mActivity) {
+            @Override
+            protected boolean isAttachedToExposedComponents() {
+                return true;
+            }
+        };
+
+        Intent intent = new Intent(ACTIONS_ALLOWED[0]);
+        String intentUri = intent.toUri(Intent.URI_INTENT_SCHEME);
+
+        Intent deepLinkIntent = new Intent(Settings.ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY);
+        deepLinkIntent.putExtra(Settings.EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI, intentUri);
+
+        assertThat(converter.apply(deepLinkIntent)).isNotEqualTo(null);
+    }
+}