Merge "Support the managed profile deep links for large screen" into tm-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index ae87edb..71c07a0 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -4474,6 +4474,16 @@
             </intent-filter>
         </receiver>
 
+        <activity
+            android:name="com.android.settings.bluetooth.QrCodeScanModeActivity"
+            android:permission="android.permission.BLUETOOTH_CONNECT"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.settings.BLUETOOTH_LE_AUDIO_QR_CODE_SCANNER"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+        </activity>
+
         <!-- This is the longest AndroidManifest.xml ever. -->
     </application>
 </manifest>
diff --git a/res/drawable/ic_qr_code_scanner.xml b/res/drawable/ic_qr_code_scanner.xml
new file mode 100644
index 0000000..f6f63c5
--- /dev/null
+++ b/res/drawable/ic_qr_code_scanner.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp"
+        android:height="24dp" android:viewportWidth="24" android:viewportHeight="24"
+        android:tint="?attr/colorControlNormal">
+    <path android:fillColor="@android:color/white"
+          android:pathData="M2,7V2H7V4H4V7ZM2,22V17H4V20H7V22ZM17,22V20H20V17H22V22ZM20,7V4H17V2H22V7ZM17.5,17.5H19V19H17.5ZM17.5,14.5H19V16H17.5ZM16,16H17.5V17.5H16ZM14.5,17.5H16V19H14.5ZM13,16H14.5V17.5H13ZM16,13H17.5V14.5H16ZM14.5,14.5H16V16H14.5ZM13,13H14.5V14.5H13ZM19,5V11H13V5ZM11,13V19H5V13ZM11,5V11H5V5ZM9.5,17.5V14.5H6.5V17.5ZM9.5,9.5V6.5H6.5V9.5ZM17.5,9.5V6.5H14.5V9.5Z"/>
+</vector>
\ No newline at end of file
diff --git a/res/layout/qrcode_scan_mode_activity.xml b/res/layout/qrcode_scan_mode_activity.xml
new file mode 100644
index 0000000..f0a182b
--- /dev/null
+++ b/res/layout/qrcode_scan_mode_activity.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/root"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:id="@+id/fragment_container"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+
+</LinearLayout>
diff --git a/res/layout/qrcode_scanner_fragment.xml b/res/layout/qrcode_scanner_fragment.xml
new file mode 100644
index 0000000..2c543f2
--- /dev/null
+++ b/res/layout/qrcode_scanner_fragment.xml
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:id="@+id/sud_layout_icon_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="3"
+        android:layout_marginBottom="35dp">
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="bottom"
+            android:gravity="center"
+            android:orientation="vertical">
+            <ImageView
+                android:id="@+id/sud_layout_icon"
+                android:src="@drawable/ic_qr_code_scanner"
+                android:tint="?androidprv:attr/colorAccentPrimaryVariant"
+                android:layout_width="@dimen/qrcode_icon_size"
+                android:layout_height="@dimen/qrcode_icon_size"
+                android:contentDescription="@null"/>
+
+            <TextView
+                android:id="@+id/sud_layout_title"
+                style="@style/QrCodeScanner"
+                android:textSize="24sp"
+                android:text="@string/bluetooth_find_broadcast_button_scan"
+                android:gravity="center"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="19dp"/>
+
+            <TextView
+                android:id="@+id/sud_layout_subtitle"
+                style="@style/QrCodeScanner"
+                android:text="@string/bt_le_audio_scan_qr_code_scanner"
+                android:gravity="center"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="8dp"/>
+        </LinearLayout>
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="7"
+        android:orientation="vertical">
+
+        <FrameLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="top"
+            android:gravity="center"
+            android:clipChildren="true">
+            <TextureView
+                android:id="@+id/preview_view"
+                android:layout_marginStart="@dimen/qrcode_preview_margin"
+                android:layout_marginEnd="@dimen/qrcode_preview_margin"
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/qrcode_preview_size"/>
+        </FrameLayout>
+
+        <TextView
+            android:id="@+id/error_message"
+            style="@style/TextAppearance.ErrorText"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="16dp"
+            android:layout_marginStart="?attr/sudMarginStart"
+            android:layout_marginEnd="?attr/sudMarginEnd"
+            android:gravity="center"
+            android:layout_gravity="center"
+            android:visibility="invisible"/>
+
+    </LinearLayout>
+
+
+</LinearLayout>
+
diff --git a/res/layout/wifi_calling_settings_preferences.xml b/res/layout/wifi_calling_settings_preferences.xml
index 9a6cbe6..bad90ad 100644
--- a/res/layout/wifi_calling_settings_preferences.xml
+++ b/res/layout/wifi_calling_settings_preferences.xml
@@ -21,12 +21,6 @@
     android:layout_height="match_parent"
     android:orientation="vertical">
 
-    <com.android.settings.widget.SettingsMainSwitchBar
-        android:id="@+id/switch_bar"
-        android:title="@string/wifi_calling_main_switch_title"
-        android:layout_height="wrap_content"
-        android:layout_width="match_parent" />
-
     <FrameLayout
         android:id="@android:id/tabcontent"
         android:layout_width="match_parent"
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 1582d21..3d616a8 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -485,4 +485,9 @@
     <!-- Sims/Data mobile/Calls/SMS select dialog-->
     <dimen name="sims_select_margin_bottom">24dp</dimen>
     <dimen name="sims_select_margin_top">8dp</dimen>
+
+    <!-- QR code picture size -->
+    <dimen name="qrcode_preview_margin">40dp</dimen>
+    <dimen name="qrcode_preview_radius">30dp</dimen>
+    <dimen name="qrcode_icon_size">27dp</dimen>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 9ab0cc2..1d685ef 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1297,7 +1297,10 @@
     <string name="security_advanced_settings_no_work_profile_settings_summary">Encryption, credentials, and more</string>
     <!-- Search keywords for the "More security settings" section in security settings. [CHAR_LIMIT=NONE] -->
     <string name="security_advanced_settings_keywords">security, more security settings, more settings, advanced security settings</string>
-
+    <!-- Title for the section that has additional privacy settings. [CHAR LIMIT=60] -->
+    <string name="privacy_advanced_settings">More privacy settings</string>
+    <!-- Title for the section that has additional privacy settings. [CHAR LIMIT=60] -->
+    <string name="privacy_advanced_settings_summary">Autofill, activity controls, and more</string>
 
     <!-- Text shown when "Add fingerprint" button is disabled -->
     <string name="fingerprint_add_max">You can add up to <xliff:g id="count" example="5">%d</xliff:g> fingerprints</string>
@@ -8973,6 +8976,9 @@
     <!-- Configure Notifications: Work profile section header [CHAR LIMIT=30] -->
     <string name="profile_section_header">Work notifications</string>
 
+    <!-- Configure Notifications: Work profile section header [CHAR LIMIT=30] -->
+    <string name="profile_section_header_for_advanced_privacy">Work profile</string>
+
     <!-- Configure Notifications: section header for prioritizer settings  [CHAR LIMIT=80] -->
     <string name="smart_notifications_title">Adaptive notifications</string>
 
@@ -13649,7 +13655,9 @@
     <string name="default_active_sim_mobile_data">mobile data</string>
     <!-- Provider Model: Message to describe "Wi-Fi scan always available feature" when Wi-Fi is off and Wi-Fi
     scanning is on. To mark a link to bring the user to "scanning settings" screen. [CHAR LIMIT=NONE]-->
-    <string name="wifi_scan_notify_message">To improve device experience, apps and services can still scan for Wi\u2011Fi networks at any time, even when Wi\u2011Fi is off. This can be used, for example, to improve location-based features and services. You can change this in Wi\u2011Fi scanning settings. <annotation id="link">Change</annotation></string>
+    <string name="wifi_scan_notify_message">To improve device experience, apps and services can still scan for Wi\u2011Fi networks at any time, even when Wi\u2011Fi is off. This can be used, for example, to improve location-based features and services. You can change this in Wi\u2011Fi scanning settings.</string>
+    <!-- Provider Model: Link text to bring the user to "scanning settings" screen. [CHAR LIMIT=NONE]-->
+    <string name="wifi_scan_change">Change</string>
 
     <!-- Summary text separator for preferences including a short description
          (eg. "Connected / 5G"). [CHAR LIMIT=50] -->
@@ -14163,4 +14171,11 @@
     <string name="find_broadcast_password_dialog_connection_error">Can\u2019t connect. Try again.</string>
     <!-- The error message of enter password dialog in bluetooth find broadcast page [CHAR LIMIT=none] -->
     <string name="find_broadcast_password_dialog_password_error">Wrong password</string>
+
+
+    <!-- [CHAR LIMIT=NONE] Le audio QR code scanner sub-title -->
+    <string name="bt_le_audio_scan_qr_code_scanner">To start listening, center the QR code below</string>
+    <!-- [CHAR LIMIT=NONE] Hint for QR code process failure -->
+    <string name="bt_le_audio_qr_code_is_not_valid_format">QR code isn\u0027t a valid format</string>
+
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 7a87993..f147ce9 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -962,4 +962,11 @@
         <item name="android:minWidth">0dp</item>
         <item name="android:textAllCaps">false</item>
     </style>
+
+    <style name="QrCodeScanner">
+        <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+        <item name="android:textSize">16sp</item>
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
+        <item name="android:textDirection">locale</item>
+    </style>
 </resources>
diff --git a/res/xml/privacy_advanced_settings.xml b/res/xml/privacy_advanced_settings.xml
new file mode 100644
index 0000000..9f465d4
--- /dev/null
+++ b/res/xml/privacy_advanced_settings.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    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.
+-->
+
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:settings="http://schemas.android.com/apk/res-auto"
+    android:key="privacy_dashboard_page"
+    android:title="@string/privacy_advanced_settings">
+
+    <!-- Work Policy info -->
+    <Preference
+        android:key="work_policy_info"
+        android:title="@string/work_policy_privacy_settings"
+        android:summary="@string/work_policy_privacy_settings_summary"
+        settings:controller="com.android.settings.privacy.WorkPolicyInfoPreferenceController"/>
+
+    <!-- Connected work and personal apps -->
+    <Preference
+        android:key="interact_across_profiles_privacy"
+        android:title="@string/interact_across_profiles_title"
+        android:fragment="com.android.settings.applications.specialaccess.interactacrossprofiles.InteractAcrossProfilesSettings"
+        settings:searchable="false"
+        settings:controller="com.android.settings.applications.specialaccess.interactacrossprofiles.InteractAcrossProfilesController" />
+
+    <!-- Accessibility usage -->
+    <Preference
+        android:key="privacy_accessibility_usage"
+        android:title="@string/accessibility_usage_title"
+        settings:controller="com.android.settings.privacy.AccessibilityUsagePreferenceController">
+        <intent android:action="android.intent.action.REVIEW_ACCESSIBILITY_SERVICES"/>
+    </Preference>
+
+    <!-- On lock screen notifications -->
+    <com.android.settings.RestrictedListPreference
+        android:key="privacy_lock_screen_notifications"
+        android:title="@string/lock_screen_notifs_title"
+        android:summary="@string/summary_placeholder"
+        settings:searchable="false"/>
+
+    <!-- Privacy Service -->
+    <PreferenceCategory
+        android:key="privacy_services"
+        android:layout="@layout/preference_category_no_label"/>
+
+    <PreferenceCategory
+        android:key="dashboard_tile_placeholder"/>
+
+    <!-- Work profile settings are at the bottom with high order value to avoid users thinking that
+         any of the above settings (including dynamic) are specific to the work profile. -->
+    <PreferenceCategory
+        android:key="privacy_work_profile_notifications_category"
+        android:title="@string/profile_section_header_for_advanced_privacy"
+        android:order="998">
+
+        <com.android.settings.RestrictedListPreference
+            android:key="privacy_lock_screen_work_profile_notifications"
+            android:title="@string/locked_work_profile_notification_title"
+            android:summary="@string/summary_placeholder"
+            android:order="999"
+            settings:searchable="false"/>
+    </PreferenceCategory>
+
+    <!-- Content Capture -->
+
+    <!-- NOTE: content capture has a different preference, depending whether or not the
+         ContentCaptureService implementations defines a custom settings activitiy on its manifest.
+         Hence, we show both here, but the controller itself will decide if it's available or not.
+    -->
+
+    <SwitchPreference
+        android:key="content_capture"
+        android:title="@string/content_capture"
+        android:summary="@string/content_capture_summary"
+        settings:controller="com.android.settings.privacy.EnableContentCapturePreferenceController"/>
+
+    <com.android.settingslib.PrimarySwitchPreference
+        android:key="content_capture_custom_settings"
+        android:title="@string/content_capture"
+        android:summary="@string/content_capture_summary"
+        settings:controller="com.android.settings.privacy.EnableContentCaptureWithServiceSettingsPreferenceController"/>
+
+</PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/wifi_calling_settings.xml b/res/xml/wifi_calling_settings.xml
index 902ff1a..c45f702 100644
--- a/res/xml/wifi_calling_settings.xml
+++ b/res/xml/wifi_calling_settings.xml
@@ -19,6 +19,10 @@
                   android:key="wifi_calling_settings"
                   android:title="@string/wifi_calling_settings_title">
 
+    <com.android.settings.widget.SettingsMainSwitchPreference
+            android:key="wifi_calling_switch_bar"
+            android:title="@string/wifi_calling_main_switch_title" />
+
     <com.android.settings.wifi.calling.ListWithEntrySummaryPreference
             android:key="wifi_calling_mode"
             isPreferenceVisible="false"
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 9f191f6..ee0743a 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -16,6 +16,8 @@
 
 package com.android.settings;
 
+import static android.provider.Settings.ACTION_PRIVACY_SETTINGS;
+
 import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
@@ -214,7 +216,8 @@
         /** Redirects to SafetyCenter if enabled. */
         @VisibleForTesting
         public void handleSafetyCenterRedirection() {
-            if (SafetyCenterManagerWrapper.get().isEnabled(this)) {
+            if (ACTION_PRIVACY_SETTINGS.equals(getIntent().getAction())
+                    && SafetyCenterManagerWrapper.get().isEnabled(this)) {
                 try {
                     startActivity(new Intent(Intent.ACTION_SAFETY_CENTER));
                     finish();
diff --git a/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizard.java b/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizard.java
index 930fbe4..6ead390 100644
--- a/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizard.java
+++ b/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizard.java
@@ -27,8 +27,11 @@
 
 import com.android.settings.R;
 import com.android.settingslib.Utils;
+import com.android.settingslib.widget.LayoutPreference;
 
 import com.google.android.setupdesign.GlifPreferenceLayout;
+import com.google.android.setupdesign.util.LayoutStyler;
+
 
 /**
  * A {@link androidx.preference.PreferenceFragmentCompat} that displays the settings page related
@@ -47,6 +50,8 @@
         icon.setTintList(Utils.getColorAttr(getContext(), android.R.attr.colorPrimary));
         AccessibilitySetupWizardUtils.updateGlifPreferenceLayout(getContext(), layout, title,
                 /* description= */ null, icon);
+
+        updateResetButtonPadding();
     }
 
     @Override
@@ -66,4 +71,14 @@
         // Hides help center in action bar and footer bar in SuW
         return 0;
     }
+
+    /**
+     * Updates the padding of the reset button to meet for SetupWizard style.
+     */
+    private void updateResetButtonPadding() {
+        final LayoutPreference resetPreference = (LayoutPreference) findPreference(RESET_KEY);
+        final ViewGroup parentView =
+                (ViewGroup) resetPreference.findViewById(R.id.reset_button).getParent();
+        LayoutStyler.applyPartnerCustomizationLayoutPaddingStyle(parentView);
+    }
 }
diff --git a/src/com/android/settings/accessibility/ToggleScreenReaderPreferenceFragmentForSetupWizard.java b/src/com/android/settings/accessibility/ToggleScreenReaderPreferenceFragmentForSetupWizard.java
index f9a1113..0af8aa1 100644
--- a/src/com/android/settings/accessibility/ToggleScreenReaderPreferenceFragmentForSetupWizard.java
+++ b/src/com/android/settings/accessibility/ToggleScreenReaderPreferenceFragmentForSetupWizard.java
@@ -49,6 +49,8 @@
         if (mTopIntroPreference != null) {
             mTopIntroPreference.setVisible(false);
         }
+
+        mToggleServiceSwitchPreference.applyPartnerCustomizationPaddingStyle();
     }
 
     @Override
diff --git a/src/com/android/settings/bluetooth/BluetoothBroadcastSourcePreference.java b/src/com/android/settings/bluetooth/BluetoothBroadcastSourcePreference.java
index 17b604c..733a4a9 100644
--- a/src/com/android/settings/bluetooth/BluetoothBroadcastSourcePreference.java
+++ b/src/com/android/settings/bluetooth/BluetoothBroadcastSourcePreference.java
@@ -16,7 +16,9 @@
 
 package com.android.settings.bluetooth;
 
+import android.bluetooth.BluetoothLeAudioContentMetadata;
 import android.bluetooth.BluetoothLeBroadcastMetadata;
+import android.bluetooth.BluetoothLeBroadcastReceiveState;
 import android.bluetooth.BluetoothLeBroadcastSubgroup;
 import android.content.Context;
 import android.graphics.drawable.Drawable;
@@ -43,16 +45,15 @@
     private static final int RESOURCE_ID_ICON = R.drawable.settings_input_antenna;
 
     private BluetoothLeBroadcastMetadata mBluetoothLeBroadcastMetadata;
+    private BluetoothLeBroadcastReceiveState mBluetoothLeBroadcastReceiveState;
     private ImageView mFrictionImageView;
     private String mTitle;
     private boolean mStatus;
     private boolean mIsEncrypted;
 
-    BluetoothBroadcastSourcePreference(@NonNull Context context,
-            @NonNull BluetoothLeBroadcastMetadata source) {
+    BluetoothBroadcastSourcePreference(@NonNull Context context) {
         super(context);
         initUi();
-        updateMetadataAndRefreshUi(source, false);
     }
 
     @Override
@@ -68,7 +69,7 @@
     private void initUi() {
         setLayoutResource(R.layout.preference_access_point);
         setWidgetLayoutResource(R.layout.access_point_friction_widget);
-
+        mTitle = getContext().getString(RESOURCE_ID_UNKNOWN_PROGRAM_INFO);
         mStatus = false;
         final Drawable drawable = getContext().getDrawable(RESOURCE_ID_ICON);
         if (drawable != null) {
@@ -105,9 +106,20 @@
      */
     public void updateMetadataAndRefreshUi(BluetoothLeBroadcastMetadata source, boolean status) {
         mBluetoothLeBroadcastMetadata = source;
-        mTitle = getBroadcastMetadataProgramInfo();
+        mTitle = getProgramInfo();
         mIsEncrypted = mBluetoothLeBroadcastMetadata.isEncrypted();
-        mStatus = status;
+        mStatus = status || mBluetoothLeBroadcastReceiveState != null;
+
+        refresh();
+    }
+
+    /**
+     * Updates the title and status from BluetoothLeBroadcastReceiveState.
+     */
+    public void updateReceiveStateAndRefreshUi(BluetoothLeBroadcastReceiveState receiveState) {
+        mBluetoothLeBroadcastReceiveState = receiveState;
+        mTitle = getProgramInfo();
+        mStatus = true;
 
         refresh();
     }
@@ -124,7 +136,17 @@
         updateStatusButton();
     }
 
-    private String getBroadcastMetadataProgramInfo() {
+    private String getProgramInfo() {
+        if (mBluetoothLeBroadcastReceiveState != null) {
+            List<BluetoothLeAudioContentMetadata> bluetoothLeAudioContentMetadata =
+                    mBluetoothLeBroadcastReceiveState.getSubgroupMetadata();
+            if (!bluetoothLeAudioContentMetadata.isEmpty()) {
+                return bluetoothLeAudioContentMetadata.stream()
+                        .map(i -> i.getProgramInfo())
+                        .findFirst().orElse(
+                                getContext().getString(RESOURCE_ID_UNKNOWN_PROGRAM_INFO));
+            }
+        }
         if (mBluetoothLeBroadcastMetadata == null) {
             return getContext().getString(RESOURCE_ID_UNKNOWN_PROGRAM_INFO);
         }
@@ -138,4 +160,24 @@
                 .filter(i -> !TextUtils.isEmpty(i))
                 .findFirst().orElse(getContext().getString(RESOURCE_ID_UNKNOWN_PROGRAM_INFO));
     }
+
+    /**
+     * Whether the broadcast source is encrypted or not.
+     * @return If true, the broadcast source needs the broadcast code. If false, the broadcast
+     * source does not need the broadcast code.
+     */
+    public boolean isEncrypted() {
+        return mIsEncrypted;
+    }
+
+    /**
+     * Clear the BluetoothLeBroadcastReceiveState and reset the state when the user clicks the
+     * "leave broadcast" button.
+     */
+    public void clearReceiveState() {
+        mBluetoothLeBroadcastReceiveState = null;
+        mTitle = getProgramInfo();
+        mStatus = false;
+        refresh();
+    }
 }
diff --git a/src/com/android/settings/bluetooth/BluetoothFindBroadcastsFragment.java b/src/com/android/settings/bluetooth/BluetoothFindBroadcastsFragment.java
index 07a3156..13388b3 100644
--- a/src/com/android/settings/bluetooth/BluetoothFindBroadcastsFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothFindBroadcastsFragment.java
@@ -86,9 +86,7 @@
                 @Override
                 public void onSearchStarted(int reason) {
                     Log.d(TAG, "onSearchStarted: " + reason);
-
-                    getActivity().runOnUiThread(
-                            () -> cacheRemoveAllPrefs(mBroadcastSourceListCategory));
+                    getActivity().runOnUiThread(() -> handleSearchStarted());
                 }
 
                 @Override
@@ -109,7 +107,8 @@
                 @Override
                 public void onSourceFound(@NonNull BluetoothLeBroadcastMetadata source) {
                     Log.d(TAG, "onSourceFound:");
-                    getActivity().runOnUiThread(() -> updateListCategory(source, false));
+                    getActivity().runOnUiThread(
+                            () -> updateListCategoryFromBroadcastMetadata(source, false));
                 }
 
                 @Override
@@ -119,7 +118,7 @@
                         Log.w(TAG, "onSourceAdded: mSelectedPreference == null!");
                         return;
                     }
-                    getActivity().runOnUiThread(() -> updateListCategory(
+                    getActivity().runOnUiThread(() -> updateListCategoryFromBroadcastMetadata(
                             mSelectedPreference.getBluetoothLeBroadcastMetadata(), true));
                 }
 
@@ -144,6 +143,7 @@
                 public void onSourceRemoved(@NonNull BluetoothDevice sink, int sourceId,
                         int reason) {
                     Log.d(TAG, "onSourceRemoved:");
+                    getActivity().runOnUiThread(() -> handleSourceRemoved());
                 }
 
                 @Override
@@ -215,6 +215,8 @@
         //check assistant status. Start searching...
         if (mLeBroadcastAssistant != null && !mLeBroadcastAssistant.isSearchInProgress()) {
             mLeBroadcastAssistant.startSearchingForSources(getScanFilter());
+        } else {
+            addConnectedSourcePreference();
         }
     }
 
@@ -310,11 +312,13 @@
         return Collections.emptyList();
     }
 
-    private void updateListCategory(BluetoothLeBroadcastMetadata source, boolean isConnected) {
+    private void updateListCategoryFromBroadcastMetadata(BluetoothLeBroadcastMetadata source,
+            boolean isConnected) {
         BluetoothBroadcastSourcePreference item = mBroadcastSourceListCategory.findPreference(
                 Integer.toString(source.getBroadcastId()));
         if (item == null) {
-            item = createBluetoothBroadcastSourcePreference(source);
+            item = createBluetoothBroadcastSourcePreference();
+            item.setKey(Integer.toString(source.getBroadcastId()));
             mBroadcastSourceListCategory.addPreference(item);
         }
         item.updateMetadataAndRefreshUi(source, isConnected);
@@ -326,13 +330,36 @@
         }
     }
 
-    private BluetoothBroadcastSourcePreference createBluetoothBroadcastSourcePreference(
-            BluetoothLeBroadcastMetadata source) {
+    private void updateListCategoryFromBroadcastReceiveState(
+            BluetoothLeBroadcastReceiveState receiveState) {
+        BluetoothBroadcastSourcePreference item = mBroadcastSourceListCategory.findPreference(
+                Integer.toString(receiveState.getBroadcastId()));
+        if (item == null) {
+            item = createBluetoothBroadcastSourcePreference();
+            item.setKey(Integer.toString(receiveState.getBroadcastId()));
+            mBroadcastSourceListCategory.addPreference(item);
+        }
+        item.updateReceiveStateAndRefreshUi(receiveState);
+        item.setOrder(0);
+
+        setSourceId(receiveState.getSourceId());
+        mSelectedPreference = item;
+
+        //refresh the header
+        if (mBluetoothFindBroadcastsHeaderController != null) {
+            mBluetoothFindBroadcastsHeaderController.refreshUi();
+        }
+    }
+
+    private BluetoothBroadcastSourcePreference createBluetoothBroadcastSourcePreference() {
         BluetoothBroadcastSourcePreference pref = new BluetoothBroadcastSourcePreference(
-                getContext(), source);
-        pref.setKey(Integer.toString(source.getBroadcastId()));
+                getContext());
         pref.setOnPreferenceClickListener(preference -> {
-            if (source.isEncrypted()) {
+            if (pref.getBluetoothLeBroadcastMetadata() == null) {
+                Log.d(TAG, "BluetoothLeBroadcastMetadata is null, do nothing.");
+                return false;
+            }
+            if (pref.isEncrypted()) {
                 launchBroadcastCodeDialog(pref);
             } else {
                 addSource(pref);
@@ -383,6 +410,10 @@
                 .setPositiveButton(R.string.bluetooth_connect_access_dialog_positive,
                         (d, w) -> {
                             Log.d(TAG, "setPositiveButton: clicked");
+                            if (pref.getBluetoothLeBroadcastMetadata() == null) {
+                                Log.d(TAG, "BluetoothLeBroadcastMetadata is null, do nothing.");
+                                return;
+                            }
                             addBroadcastCodeIntoPreference(pref, editText.getText().toString());
                             addSource(pref);
                         })
@@ -392,6 +423,30 @@
         alertDialog.show();
     }
 
+    private void handleSearchStarted() {
+        cacheRemoveAllPrefs(mBroadcastSourceListCategory);
+        addConnectedSourcePreference();
+    }
+
+    private void handleSourceRemoved() {
+        if (mSelectedPreference != null) {
+            if (mSelectedPreference.getBluetoothLeBroadcastMetadata() == null) {
+                mBroadcastSourceListCategory.removePreference(mSelectedPreference);
+            } else {
+                mSelectedPreference.clearReceiveState();
+            }
+        }
+        mSelectedPreference = null;
+    }
+
+    private void addConnectedSourcePreference() {
+        List<BluetoothLeBroadcastReceiveState> receiveStateList =
+                mLeBroadcastAssistant.getAllSources(mCachedDevice.getDevice());
+        if (!receiveStateList.isEmpty()) {
+            updateListCategoryFromBroadcastReceiveState(receiveStateList.get(0));
+        }
+    }
+
     public int getSourceId() {
         return mSourceId;
     }
diff --git a/src/com/android/settings/bluetooth/BluetoothFindBroadcastsHeaderController.java b/src/com/android/settings/bluetooth/BluetoothFindBroadcastsHeaderController.java
index 1527f21..6aaa1b8 100644
--- a/src/com/android/settings/bluetooth/BluetoothFindBroadcastsHeaderController.java
+++ b/src/com/android/settings/bluetooth/BluetoothFindBroadcastsHeaderController.java
@@ -33,7 +33,6 @@
 import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.core.lifecycle.Lifecycle;
-import com.android.settingslib.qrcode.QrCodeScanModeActivity;
 import com.android.settingslib.widget.LayoutPreference;
 
 /**
diff --git a/src/com/android/settings/bluetooth/QrCodeScanModeActivity.java b/src/com/android/settings/bluetooth/QrCodeScanModeActivity.java
new file mode 100644
index 0000000..5c5b61f
--- /dev/null
+++ b/src/com/android/settings/bluetooth/QrCodeScanModeActivity.java
@@ -0,0 +1,111 @@
+/**
+ * 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.bluetooth;
+
+import static com.android.settingslib.bluetooth.BluetoothBroadcastUtils.EXTRA_BLUETOOTH_DEVICE_SINK;
+import static com.android.settingslib.bluetooth.BluetoothBroadcastUtils.EXTRA_BLUETOOTH_SINK_IS_GROUP;
+
+import android.bluetooth.BluetoothDevice;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+import androidx.fragment.app.FragmentTransaction;
+
+import com.android.settingslib.R;
+import com.android.settingslib.bluetooth.BluetoothBroadcastUtils;
+import com.android.settingslib.bluetooth.BluetoothUtils;
+
+//TODO (b/232365943): Add test case for tthe QrCode UI.
+public class QrCodeScanModeActivity extends QrCodeScanModeBaseActivity {
+    private static final boolean DEBUG = BluetoothUtils.D;
+    private static final String TAG = "QrCodeScanModeActivity";
+
+    private boolean mIsGroupOp;
+    private BluetoothDevice mSink;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    protected void handleIntent(Intent intent) {
+        String action = intent != null ? intent.getAction() : null;
+        if (DEBUG) {
+            Log.d(TAG, "handleIntent(), action = " + action);
+        }
+
+        if (action == null) {
+            finish();
+            return;
+        }
+
+        switch (action) {
+            case BluetoothBroadcastUtils.ACTION_BLUETOOTH_LE_AUDIO_QR_CODE_SCANNER:
+                showQrCodeScannerFragment(intent);
+                break;
+            default:
+                if (DEBUG) {
+                    Log.e(TAG, "Launch with an invalid action");
+                }
+                finish();
+        }
+    }
+
+    protected void showQrCodeScannerFragment(Intent intent) {
+        if (intent == null) {
+            if (DEBUG) {
+                Log.d(TAG, "intent is null, can not get bluetooth information from intent.");
+            }
+            return;
+        }
+
+        if (DEBUG) {
+            Log.d(TAG, "showQrCodeScannerFragment");
+        }
+
+        mSink = intent.getParcelableExtra(EXTRA_BLUETOOTH_DEVICE_SINK);
+        mIsGroupOp = intent.getBooleanExtra(EXTRA_BLUETOOTH_SINK_IS_GROUP, false);
+        if (DEBUG) {
+            Log.d(TAG, "get extra from intent");
+        }
+
+        QrCodeScanModeFragment fragment =
+                (QrCodeScanModeFragment) mFragmentManager.findFragmentByTag(
+                        BluetoothBroadcastUtils.TAG_FRAGMENT_QR_CODE_SCANNER);
+
+        if (fragment == null) {
+            fragment = new QrCodeScanModeFragment(mIsGroupOp, mSink);
+        } else {
+            if (fragment.isVisible()) {
+                return;
+            }
+
+            // When the fragment in back stack but not on top of the stack, we can simply pop
+            // stack because current fragment transactions are arranged in an order
+            mFragmentManager.popBackStackImmediate();
+            return;
+        }
+        final FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
+
+        fragmentTransaction.replace(R.id.fragment_container, fragment,
+                BluetoothBroadcastUtils.TAG_FRAGMENT_QR_CODE_SCANNER);
+        fragmentTransaction.commit();
+    }
+}
+
diff --git a/src/com/android/settings/bluetooth/QrCodeScanModeBaseActivity.java b/src/com/android/settings/bluetooth/QrCodeScanModeBaseActivity.java
new file mode 100644
index 0000000..af8a6e9
--- /dev/null
+++ b/src/com/android/settings/bluetooth/QrCodeScanModeBaseActivity.java
@@ -0,0 +1,46 @@
+/**
+ * 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.bluetooth;
+
+import android.content.Intent;
+import android.os.Bundle;
+
+import androidx.fragment.app.FragmentManager;
+
+import com.android.settingslib.R;
+import com.android.settingslib.core.lifecycle.ObservableActivity;
+
+public abstract class QrCodeScanModeBaseActivity extends ObservableActivity {
+
+    protected FragmentManager mFragmentManager;
+
+    protected abstract void handleIntent(Intent intent);
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setTheme(R.style.SudThemeGlifV3_DayNight);
+
+        setContentView(R.layout.qrcode_scan_mode_activity);
+        mFragmentManager = getSupportFragmentManager();
+
+        if (savedInstanceState == null) {
+            handleIntent(getIntent());
+        }
+    }
+}
diff --git a/src/com/android/settings/bluetooth/QrCodeScanModeController.java b/src/com/android/settings/bluetooth/QrCodeScanModeController.java
new file mode 100644
index 0000000..4504b4b
--- /dev/null
+++ b/src/com/android/settings/bluetooth/QrCodeScanModeController.java
@@ -0,0 +1,63 @@
+/**
+ * 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.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothLeBroadcastMetadata;
+import android.content.Context;
+import android.util.Log;
+
+import com.android.settingslib.bluetooth.BluetoothUtils;
+import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastMetadata;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+
+public class QrCodeScanModeController {
+
+    private static final boolean DEBUG = BluetoothUtils.D;
+    private static final String TAG = "QrCodeScanModeController";
+
+    private LocalBluetoothLeBroadcastMetadata mLocalBroadcastMetadata;
+    private LocalBluetoothLeBroadcastAssistant mLocalBroadcastAssistant;
+    private LocalBluetoothManager mLocalBluetoothManager;
+    private LocalBluetoothProfileManager mProfileManager;
+
+    public QrCodeScanModeController(Context context) {
+        if (DEBUG) {
+            Log.d(TAG, "QrCodeScanModeController constructor.");
+        }
+        mLocalBluetoothManager = Utils.getLocalBtManager(context);
+        mProfileManager = mLocalBluetoothManager.getProfileManager();
+        mLocalBroadcastMetadata = new LocalBluetoothLeBroadcastMetadata();
+        CachedBluetoothDeviceManager cachedDeviceManager = new CachedBluetoothDeviceManager(context,
+                mLocalBluetoothManager);
+        mLocalBroadcastAssistant = new LocalBluetoothLeBroadcastAssistant(context,
+                cachedDeviceManager, mProfileManager);
+    }
+
+    private BluetoothLeBroadcastMetadata convertToBroadcastMetadata(String qrCodeString) {
+        return mLocalBroadcastMetadata.convertToBroadcastMetadata(qrCodeString);
+    }
+
+    public void addSource(BluetoothDevice sink, String sourceMetadata,
+            boolean isGroupOp) {
+        mLocalBroadcastAssistant.addSource(sink,
+                convertToBroadcastMetadata(sourceMetadata), isGroupOp);
+    }
+}
diff --git a/src/com/android/settings/bluetooth/QrCodeScanModeFragment.java b/src/com/android/settings/bluetooth/QrCodeScanModeFragment.java
new file mode 100644
index 0000000..dcf89ca
--- /dev/null
+++ b/src/com/android/settings/bluetooth/QrCodeScanModeFragment.java
@@ -0,0 +1,243 @@
+/**
+ * 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.bluetooth;
+
+import android.app.settings.SettingsEnums;
+import android.bluetooth.BluetoothDevice;
+import android.content.Context;
+import android.graphics.Matrix;
+import android.graphics.Outline;
+import android.graphics.Rect;
+import android.graphics.SurfaceTexture;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.util.Size;
+import android.view.LayoutInflater;
+import android.view.TextureView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewOutlineProvider;
+import android.view.accessibility.AccessibilityEvent;
+import android.widget.TextView;
+
+import com.android.settings.core.InstrumentedFragment;
+import com.android.settingslib.R;
+import com.android.settingslib.bluetooth.BluetoothBroadcastUtils;
+import com.android.settingslib.bluetooth.BluetoothUtils;
+import com.android.settingslib.core.lifecycle.ObservableFragment;
+import com.android.settingslib.qrcode.QrCamera;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
+
+public class QrCodeScanModeFragment extends InstrumentedFragment implements
+        TextureView.SurfaceTextureListener,
+        QrCamera.ScannerCallback {
+    private static final boolean DEBUG = BluetoothUtils.D;
+    private static final String TAG = "QrCodeScanModeFragment";
+
+    /** Message sent to hide error message */
+    private static final int MESSAGE_HIDE_ERROR_MESSAGE = 1;
+    /** Message sent to show error message */
+    private static final int MESSAGE_SHOW_ERROR_MESSAGE = 2;
+    /** Message sent to broadcast QR code */
+    private static final int MESSAGE_SCAN_BROADCAST_SUCCESS = 3;
+
+    private static final long SHOW_ERROR_MESSAGE_INTERVAL = 10000;
+    private static final long SHOW_SUCCESS_SQUARE_INTERVAL = 1000;
+
+    private boolean mIsGroupOp;
+    private int mCornerRadius;
+    private BluetoothDevice mSink;
+    private String mBroadcastMetadata;
+    private Context mContext;
+    private QrCamera mCamera;
+    private QrCodeScanModeController mController;
+    private TextureView mTextureView;
+    private TextView mSummary;
+    private TextView mErrorMessage;
+
+    public QrCodeScanModeFragment(boolean isGroupOp, BluetoothDevice sink) {
+        mIsGroupOp = isGroupOp;
+        mSink = sink;
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mContext = getContext();
+        mController = new QrCodeScanModeController(mContext);
+    }
+
+    @Override
+    public final View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.qrcode_scanner_fragment, container,
+                /* attachToRoot */ false);
+    }
+
+    @Override
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        mTextureView = view.findViewById(R.id.preview_view);
+        mCornerRadius = mContext.getResources().getDimensionPixelSize(
+                R.dimen.qrcode_preview_radius);
+        mTextureView.setSurfaceTextureListener(this);
+        mTextureView.setOutlineProvider(new ViewOutlineProvider() {
+            @Override
+            public void getOutline(View view, Outline outline) {
+                outline.setRoundRect(0,0, view.getWidth(), view.getHeight(), mCornerRadius);
+            }
+        });
+        mTextureView.setClipToOutline(true);
+        mErrorMessage = view.findViewById(R.id.error_message);
+    }
+
+    private void initCamera(SurfaceTexture surface) {
+        // Check if the camera has already created.
+        if (mCamera == null) {
+            mCamera = new QrCamera(mContext, this);
+            mCamera.start(surface);
+        }
+    }
+
+    private void destroyCamera() {
+        if (mCamera != null) {
+            mCamera.stop();
+            mCamera = null;
+        }
+    }
+
+    @Override
+    public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {
+        initCamera(surface);
+    }
+
+    @Override
+    public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width,
+            int height) {
+    }
+
+    @Override
+    public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
+        destroyCamera();
+        return true;
+    }
+
+    @Override
+    public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {
+    }
+
+    @Override
+    public void handleSuccessfulResult(String qrCode) {
+        if (DEBUG) {
+            Log.d(TAG, "handleSuccessfulResult(), get the qr code string.");
+        }
+        mBroadcastMetadata = qrCode;
+        handleBtLeAudioScanner();
+    }
+
+    @Override
+    public void handleCameraFailure() {
+        destroyCamera();
+    }
+
+    @Override
+    public Size getViewSize() {
+        return new Size(mTextureView.getWidth(), mTextureView.getHeight());
+    }
+
+    @Override
+    public Rect getFramePosition(Size previewSize, int cameraOrientation) {
+        return new Rect(0, 0, previewSize.getHeight(), previewSize.getHeight());
+    }
+
+    @Override
+    public void setTransform(Matrix transform) {
+        mTextureView.setTransform(transform);
+    }
+
+    @Override
+    public boolean isValid(String qrCode) {
+        if (qrCode.startsWith(BluetoothBroadcastUtils.SCHEME_BT_BROADCAST_METADATA)) {
+            return true;
+        } else {
+            showErrorMessage(R.string.bt_le_audio_qr_code_is_not_valid_format);
+            return false;
+        }
+    }
+
+    protected boolean isDecodeTaskAlive() {
+        return mCamera != null && mCamera.isDecodeTaskAlive();
+    }
+
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MESSAGE_HIDE_ERROR_MESSAGE:
+                    mErrorMessage.setVisibility(View.INVISIBLE);
+                    break;
+
+                case MESSAGE_SHOW_ERROR_MESSAGE:
+                    final String errorMessage = (String) msg.obj;
+
+                    mErrorMessage.setVisibility(View.VISIBLE);
+                    mErrorMessage.setText(errorMessage);
+                    mErrorMessage.sendAccessibilityEvent(
+                            AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+
+                    // Cancel any pending messages to hide error view and requeue the message so
+                    // user has time to see error
+                    removeMessages(MESSAGE_HIDE_ERROR_MESSAGE);
+                    sendEmptyMessageDelayed(MESSAGE_HIDE_ERROR_MESSAGE,
+                            SHOW_ERROR_MESSAGE_INTERVAL);
+                    break;
+
+                case MESSAGE_SCAN_BROADCAST_SUCCESS:
+                    mController.addSource(mSink, mBroadcastMetadata, mIsGroupOp);
+                    updateSummary();
+                    mSummary.sendAccessibilityEvent(
+                            AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+                    break;
+                default:
+            }
+        }
+    };
+
+    private void showErrorMessage(@StringRes int messageResId) {
+        final Message message = mHandler.obtainMessage(MESSAGE_SHOW_ERROR_MESSAGE,
+                getString(messageResId));
+        message.sendToTarget();
+    }
+
+    private void handleBtLeAudioScanner() {
+        Message message = mHandler.obtainMessage(MESSAGE_SCAN_BROADCAST_SUCCESS);
+        mHandler.sendMessageDelayed(message, SHOW_SUCCESS_SQUARE_INTERVAL);
+    }
+
+    private void updateSummary() {
+        mSummary.setText(getString(R.string.bt_le_audio_scan_qr_code_scanner,
+                null /* broadcast_name*/));;
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return SettingsEnums.LE_AUDIO_BROADCAST_SCAN_QR_CODE;
+    }
+}
diff --git a/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragment.java b/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragment.java
index 57988c5..1473dd1 100644
--- a/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragment.java
+++ b/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragment.java
@@ -84,10 +84,19 @@
             }
 
             final StorageEntry changedStorageEntry = new StorageEntry(getContext(), volumeInfo);
-            switch (volumeInfo.getState()) {
+            final int volumeState = volumeInfo.getState();
+            switch (volumeState) {
+                case VolumeInfo.STATE_REMOVED:
+                case VolumeInfo.STATE_BAD_REMOVAL:
+                    // Remove removed storage from list and don't show it on spinner.
+                    if (!mStorageEntries.remove(changedStorageEntry)) {
+                        break;
+                    }
                 case VolumeInfo.STATE_MOUNTED:
                 case VolumeInfo.STATE_MOUNTED_READ_ONLY:
                 case VolumeInfo.STATE_UNMOUNTABLE:
+                case VolumeInfo.STATE_UNMOUNTED:
+                case VolumeInfo.STATE_EJECTING:
                     // Add mounted or unmountable storage in the list and show it on spinner.
                     // Unmountable storages are the storages which has a problem format and android
                     // is not able to mount it automatically.
@@ -95,25 +104,15 @@
                     mStorageEntries.removeIf(storageEntry -> {
                         return storageEntry.equals(changedStorageEntry);
                     });
-                    mStorageEntries.add(changedStorageEntry);
+                    if (volumeState != VolumeInfo.STATE_REMOVED
+                            && volumeState != VolumeInfo.STATE_BAD_REMOVAL) {
+                        mStorageEntries.add(changedStorageEntry);
+                    }
                     if (changedStorageEntry.equals(mSelectedStorageEntry)) {
                         mSelectedStorageEntry = changedStorageEntry;
                     }
                     refreshUi();
                     break;
-                case VolumeInfo.STATE_REMOVED:
-                case VolumeInfo.STATE_UNMOUNTED:
-                case VolumeInfo.STATE_BAD_REMOVAL:
-                case VolumeInfo.STATE_EJECTING:
-                    // Remove removed storage from list and don't show it on spinner.
-                    if (mStorageEntries.remove(changedStorageEntry)) {
-                        if (changedStorageEntry.equals(mSelectedStorageEntry)) {
-                            mSelectedStorageEntry =
-                                    StorageEntry.getDefaultInternalStorageEntry(getContext());
-                        }
-                        refreshUi();
-                    }
-                    break;
                 default:
                     // Do nothing.
             }
diff --git a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java
index 77d4072..a4809c9 100644
--- a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java
+++ b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java
@@ -115,10 +115,19 @@
             }
 
             final StorageEntry changedStorageEntry = new StorageEntry(getContext(), volumeInfo);
-            switch (volumeInfo.getState()) {
+            final int volumeState = volumeInfo.getState();
+            switch (volumeState) {
+                case VolumeInfo.STATE_REMOVED:
+                case VolumeInfo.STATE_BAD_REMOVAL:
+                    // Remove removed storage from list and don't show it on spinner.
+                    if (!mStorageEntries.remove(changedStorageEntry)) {
+                        break;
+                    }
                 case VolumeInfo.STATE_MOUNTED:
                 case VolumeInfo.STATE_MOUNTED_READ_ONLY:
                 case VolumeInfo.STATE_UNMOUNTABLE:
+                case VolumeInfo.STATE_UNMOUNTED:
+                case VolumeInfo.STATE_EJECTING:
                     // Add mounted or unmountable storage in the list and show it on spinner.
                     // Unmountable storages are the storages which has a problem format and android
                     // is not able to mount it automatically.
@@ -126,25 +135,15 @@
                     mStorageEntries.removeIf(storageEntry -> {
                         return storageEntry.equals(changedStorageEntry);
                     });
-                    mStorageEntries.add(changedStorageEntry);
+                    if (volumeState != VolumeInfo.STATE_REMOVED
+                            && volumeState != VolumeInfo.STATE_BAD_REMOVAL) {
+                        mStorageEntries.add(changedStorageEntry);
+                    }
                     if (changedStorageEntry.equals(mSelectedStorageEntry)) {
                         mSelectedStorageEntry = changedStorageEntry;
                     }
                     refreshUi();
                     break;
-                case VolumeInfo.STATE_REMOVED:
-                case VolumeInfo.STATE_UNMOUNTED:
-                case VolumeInfo.STATE_BAD_REMOVAL:
-                case VolumeInfo.STATE_EJECTING:
-                    // Remove removed storage from list and don't show it on spinner.
-                    if (mStorageEntries.remove(changedStorageEntry)) {
-                        if (changedStorageEntry.equals(mSelectedStorageEntry)) {
-                            mSelectedStorageEntry =
-                                    StorageEntry.getDefaultInternalStorageEntry(getContext());
-                        }
-                        refreshUi();
-                    }
-                    break;
                 default:
                     // Do nothing.
             }
diff --git a/src/com/android/settings/deviceinfo/VolumeOptionMenuController.java b/src/com/android/settings/deviceinfo/VolumeOptionMenuController.java
index 42a3a16..4b87e42 100644
--- a/src/com/android/settings/deviceinfo/VolumeOptionMenuController.java
+++ b/src/com/android/settings/deviceinfo/VolumeOptionMenuController.java
@@ -26,6 +26,7 @@
 import android.os.storage.DiskInfo;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
+import android.util.Log;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
@@ -53,6 +54,8 @@
 public class VolumeOptionMenuController implements LifecycleObserver, OnCreateOptionsMenu,
         OnPrepareOptionsMenu, OnOptionsItemSelected {
 
+    private static final String TAG = "VolumeOptionMenuController";
+
     @VisibleForTesting
     MenuItem mRename;
     @VisibleForTesting
@@ -103,6 +106,17 @@
         mFree = menu.findItem(R.id.storage_free);
         mForget = menu.findItem(R.id.storage_forget);
 
+        updateOptionsMenu();
+    }
+
+    private void updateOptionsMenu() {
+        if (mRename == null || mMount == null || mUnmount == null || mFormat == null
+                || mFormatAsPortable == null || mFormatAsInternal == null || mMigrate == null
+                || mFree == null || mForget == null) {
+            Log.d(TAG, "Menu items are not available");
+            return;
+        }
+
         mRename.setVisible(false);
         mMount.setVisible(false);
         mUnmount.setVisible(false);
@@ -252,5 +266,7 @@
 
     public void setSelectedStorageEntry(StorageEntry storageEntry) {
         mStorageEntry = storageEntry;
+
+        updateOptionsMenu();
     }
 }
diff --git a/src/com/android/settings/localepicker/AppLocalePickerActivity.java b/src/com/android/settings/localepicker/AppLocalePickerActivity.java
index 791a4e8..377a076 100644
--- a/src/com/android/settings/localepicker/AppLocalePickerActivity.java
+++ b/src/com/android/settings/localepicker/AppLocalePickerActivity.java
@@ -118,6 +118,7 @@
 
     /** Sets the app's locale to the supplied language tag */
     private void setAppDefaultLocale(String languageTag) {
+        Log.d(TAG, "setAppDefaultLocale: " + languageTag);
         LocaleManager localeManager = mContextAsUser.getSystemService(LocaleManager.class);
         if (localeManager == null) {
             Log.w(TAG, "LocaleManager is null, cannot set default app locale");
diff --git a/src/com/android/settings/network/NetworkProviderSettings.java b/src/com/android/settings/network/NetworkProviderSettings.java
index de4d127..ec17dd3 100644
--- a/src/com/android/settings/network/NetworkProviderSettings.java
+++ b/src/com/android/settings/network/NetworkProviderSettings.java
@@ -67,7 +67,6 @@
 import com.android.settings.datausage.DataUsageUtils;
 import com.android.settings.location.WifiScanningFragment;
 import com.android.settings.search.BaseSearchIndexProvider;
-import com.android.settings.utils.AnnotationSpan;
 import com.android.settings.wifi.AddNetworkFragment;
 import com.android.settings.wifi.AddWifiNetworkPreference;
 import com.android.settings.wifi.ConfigureWifiEntryFragment;
@@ -829,12 +828,10 @@
             return;
         }
         if (TextUtils.isEmpty(mWifiStatusMessagePreference.getTitle())) {
-            AnnotationSpan.LinkInfo info = new AnnotationSpan.LinkInfo(
-                AnnotationSpan.LinkInfo.DEFAULT_ANNOTATION,
-                v -> launchWifiScanningFragment());
-            CharSequence text = AnnotationSpan.linkify(
-                context.getText(R.string.wifi_scan_notify_message), info);
-            mWifiStatusMessagePreference.setTitle(text);
+            mWifiStatusMessagePreference.setTitle(R.string.wifi_scan_notify_message);
+            mWifiStatusMessagePreference.setLearnMoreText(
+                    context.getString(R.string.wifi_scan_change));
+            mWifiStatusMessagePreference.setLearnMoreAction(v -> launchWifiScanningFragment());
         }
         mWifiStatusMessagePreference.setVisible(true);
     }
diff --git a/src/com/android/settings/privacy/PrivacyDashboardFragment.java b/src/com/android/settings/privacy/PrivacyDashboardFragment.java
index df59bd5..75ed225 100644
--- a/src/com/android/settings/privacy/PrivacyDashboardFragment.java
+++ b/src/com/android/settings/privacy/PrivacyDashboardFragment.java
@@ -25,6 +25,7 @@
 import android.app.settings.SettingsEnums;
 import android.content.Context;
 import android.os.Bundle;
+import android.provider.SearchIndexableResource;
 
 import com.android.settings.R;
 import com.android.settings.dashboard.DashboardFragment;
@@ -36,6 +37,7 @@
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 @SearchIndexable
@@ -72,12 +74,6 @@
         replaceEnterpriseStringSummary("work_policy_info",
                 WORK_PROFILE_PRIVACY_POLICY_INFO_SUMMARY,
                 R.string.work_policy_privacy_settings_summary);
-
-    }
-
-    @Override
-    protected int getPreferenceScreenResId() {
-        return R.xml.privacy_dashboard_settings;
     }
 
     @Override
@@ -90,6 +86,19 @@
         return buildPreferenceControllers(context, getSettingsLifecycle());
     }
 
+    @Override
+    protected int getPreferenceScreenResId() {
+        return getPreferenceScreenResId(getContext());
+    }
+
+    private static int getPreferenceScreenResId(Context context) {
+        if (SafetyCenterManagerWrapper.get().isEnabled(context)) {
+            return R.xml.privacy_advanced_settings;
+        } else {
+            return R.xml.privacy_dashboard_settings;
+        }
+    }
+
     private static List<AbstractPreferenceController> buildPreferenceControllers(
             Context context, Lifecycle lifecycle) {
         final List<AbstractPreferenceController> controllers = new ArrayList<>();
@@ -108,17 +117,19 @@
     }
 
     public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
-            new BaseSearchIndexProvider(R.xml.privacy_dashboard_settings) {
+            new BaseSearchIndexProvider() {
+                @Override
+                public List<SearchIndexableResource> getXmlResourcesToIndex(
+                        Context context, boolean enabled) {
+                    final SearchIndexableResource sir = new SearchIndexableResource(context);
+                    sir.xmlResId = getPreferenceScreenResId(context);
+                    return Arrays.asList(sir);
+                }
 
                 @Override
                 public List<AbstractPreferenceController> createPreferenceControllers(
                         Context context) {
                     return buildPreferenceControllers(context, null);
                 }
-
-                @Override
-                protected boolean isPageSearchEnabled(Context context) {
-                    return !SafetyCenterManagerWrapper.get().isEnabled(context);
-                }
             };
 }
diff --git a/src/com/android/settings/widget/SettingsMainSwitchPreference.java b/src/com/android/settings/widget/SettingsMainSwitchPreference.java
index b7c6901..9264911 100644
--- a/src/com/android/settings/widget/SettingsMainSwitchPreference.java
+++ b/src/com/android/settings/widget/SettingsMainSwitchPreference.java
@@ -22,6 +22,7 @@
 import android.content.res.TypedArray;
 import android.text.TextUtils;
 import android.util.AttributeSet;
+import android.view.ViewGroup;
 import android.widget.Switch;
 
 import androidx.core.content.res.TypedArrayUtils;
@@ -33,6 +34,8 @@
 import com.android.settingslib.RestrictedPreferenceHelper;
 import com.android.settingslib.widget.OnMainSwitchChangeListener;
 
+import com.google.android.setupdesign.util.LayoutStyler;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -48,6 +51,7 @@
             new ArrayList<>();
     private final List<OnMainSwitchChangeListener> mSwitchChangeListeners = new ArrayList<>();
 
+    private boolean mApplyPartnerCustomizationPaddingStyle;
     private SettingsMainSwitchBar mMainSwitchBar;
     private CharSequence mTitle;
     private EnforcedAdmin mEnforcedAdmin;
@@ -95,6 +99,12 @@
         } else {
             mMainSwitchBar.hide();
         }
+
+        if (mApplyPartnerCustomizationPaddingStyle) {
+            // TODO(b/232494666): Replace all margins of the root view with the padding
+            final ViewGroup parentView = (ViewGroup) mMainSwitchBar.getParent();
+            LayoutStyler.applyPartnerCustomizationLayoutPaddingStyle(parentView);
+        }
     }
 
     private void init(Context context, AttributeSet attrs) {
@@ -241,6 +251,14 @@
         }
     }
 
+    /**
+     * Apples the padding style of the partner's customization. It's used in the SetupWizard.
+     */
+    public void applyPartnerCustomizationPaddingStyle() {
+        mApplyPartnerCustomizationPaddingStyle = true;
+        notifyChanged();
+    }
+
     private void initMainSwitchBar() {
         if (mMainSwitchBar != null) {
             mMainSwitchBar.setTitle(mTitle);
diff --git a/src/com/android/settings/wifi/WifiScanModeActivity.java b/src/com/android/settings/wifi/WifiScanModeActivity.java
index 9d50281..d372135 100644
--- a/src/com/android/settings/wifi/WifiScanModeActivity.java
+++ b/src/com/android/settings/wifi/WifiScanModeActivity.java
@@ -20,26 +20,30 @@
 import android.app.settings.SettingsEnums;
 import android.content.DialogInterface;
 import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
 import android.net.wifi.WifiManager;
 import android.os.Bundle;
 import android.text.TextUtils;
 import android.view.WindowManager;
 
+import androidx.annotation.VisibleForTesting;
 import androidx.appcompat.app.AlertDialog;
 import androidx.fragment.app.DialogFragment;
 import androidx.fragment.app.FragmentActivity;
 
 import com.android.settings.R;
+import com.android.settings.Utils;
 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+import com.android.settingslib.wifi.WifiPermissionChecker;
 
 /**
  * This activity requests users permission to allow scanning even when Wi-Fi is turned off
  */
 public class WifiScanModeActivity extends FragmentActivity {
     private DialogFragment mDialog;
-    private String mApp;
+    @VisibleForTesting
+    String mApp;
+    @VisibleForTesting
+    WifiPermissionChecker mWifiPermissionChecker;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -50,13 +54,7 @@
         if (savedInstanceState == null) {
             if (intent != null && WifiManager.ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE
                     .equals(intent.getAction())) {
-                ApplicationInfo ai;
-                mApp = getCallingPackage();
-                try {
-                    PackageManager pm = getPackageManager();
-                    ai = pm.getApplicationInfo(mApp, 0);
-                    mApp = (String)pm.getApplicationLabel(ai);
-                } catch (PackageManager.NameNotFoundException e) { }
+                refreshAppLabel();
             } else {
                 finish();
                 return;
@@ -67,6 +65,19 @@
         createDialog();
     }
 
+    @VisibleForTesting
+    void refreshAppLabel() {
+        if (mWifiPermissionChecker == null) {
+            mWifiPermissionChecker = new WifiPermissionChecker(this);
+        }
+        String packageName = mWifiPermissionChecker.getLaunchedPackage();
+        if (TextUtils.isEmpty(packageName)) {
+            mApp = null;
+            return;
+        }
+        mApp = Utils.getApplicationLabel(getApplicationContext(), packageName).toString();
+    }
+
     private void createDialog() {
         if (mDialog == null) {
             mDialog = AlertDialogFragment.newInstance(mApp);
diff --git a/src/com/android/settings/wifi/calling/WifiCallingSettings.java b/src/com/android/settings/wifi/calling/WifiCallingSettings.java
index 25508f7..b4951bf 100644
--- a/src/com/android/settings/wifi/calling/WifiCallingSettings.java
+++ b/src/com/android/settings/wifi/calling/WifiCallingSettings.java
@@ -30,13 +30,12 @@
 
 import androidx.annotation.VisibleForTesting;
 import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentActivity;
 import androidx.fragment.app.FragmentManager;
 import androidx.fragment.app.FragmentPagerAdapter;
 
 import com.android.internal.util.CollectionUtils;
 import com.android.settings.R;
-import com.android.settings.core.InstrumentedFragment;
+import com.android.settings.SettingsPreferenceFragment;
 import com.android.settings.network.ActiveSubscriptionsListener;
 import com.android.settings.network.SubscriptionUtil;
 import com.android.settings.network.ims.WifiCallingQueryImsState;
@@ -54,7 +53,8 @@
  * "Wi-Fi Calling settings" screen. This is the container fragment which holds
  * {@link WifiCallingSettingsForSub} fragments.
  */
-public class WifiCallingSettings extends InstrumentedFragment implements HelpResourceProvider {
+public class WifiCallingSettings extends SettingsPreferenceFragment
+        implements HelpResourceProvider {
     private static final String TAG = "WifiCallingSettings";
     private int mConstructionSubId;
     private List<SubscriptionInfo> mSil;
@@ -317,17 +317,7 @@
         }
 
         // close this fragment
-        finish();
-    }
-
-    protected void finish() {
-        FragmentActivity activity = getActivity();
-        if (activity == null) return;
-        if (getFragmentManager().getBackStackEntryCount() > 0) {
-            getFragmentManager().popBackStack();
-        } else {
-            activity.finish();
-        }
+        finishFragment();
     }
 
     protected int [] subscriptionIdList(List<SubscriptionInfo> subInfoList) {
diff --git a/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java b/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java
index 749af3e..492a228 100644
--- a/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java
+++ b/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java
@@ -27,7 +27,6 @@
 import android.os.Bundle;
 import android.os.PersistableBundle;
 import android.telephony.CarrierConfigManager;
-import android.telephony.PhoneStateListener;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyCallback;
 import android.telephony.TelephonyManager;
@@ -40,7 +39,6 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Switch;
-import android.widget.TextView;
 
 import androidx.appcompat.app.AlertDialog;
 import androidx.preference.Preference;
@@ -56,8 +54,7 @@
 import com.android.settings.Utils;
 import com.android.settings.core.SubSettingLauncher;
 import com.android.settings.network.ims.WifiCallingQueryImsState;
-import com.android.settings.widget.SettingsMainSwitchBar;
-import com.android.settings.wifi.calling.LinkifyDescriptionPreference;
+import com.android.settings.widget.SettingsMainSwitchPreference;
 import com.android.settingslib.widget.OnMainSwitchChangeListener;
 
 import java.util.List;
@@ -72,6 +69,7 @@
     private static final String TAG = "WifiCallingForSub";
 
     //String keys for preference lookup
+    private static final String SWITCH_BAR = "wifi_calling_switch_bar";
     private static final String BUTTON_WFC_MODE = "wifi_calling_mode";
     private static final String BUTTON_WFC_ROAMING_MODE = "wifi_calling_roaming_mode";
     private static final String PREFERENCE_EMERGENCY_ADDRESS = "emergency_address_key";
@@ -91,7 +89,7 @@
     public static final int LAUCH_APP_UPDATE = 1;
 
     //UI objects
-    private SettingsMainSwitchBar mSwitchBar;
+    private SettingsMainSwitchPreference mSwitchBar;
     private ListWithEntrySummaryPreference mButtonWfcMode;
     private ListWithEntrySummaryPreference mButtonWfcRoamingMode;
     private Preference mUpdateAddress;
@@ -119,41 +117,57 @@
         @Override
         public void onCallStateChanged(int state) {
             final SettingsActivity activity = (SettingsActivity) getActivity();
-            final boolean isNonTtyOrTtyOnVolteEnabled =
-                    queryImsState(WifiCallingSettingsForSub.this.mSubId).isAllowUserControl();
-            final boolean isWfcEnabled = mSwitchBar.isChecked()
-                    && isNonTtyOrTtyOnVolteEnabled;
-            boolean isCallStateIdle = getTelephonyManagerForSub(
-                    WifiCallingSettingsForSub.this.mSubId).getCallState()
-                    == TelephonyManager.CALL_STATE_IDLE;
-            mSwitchBar.setEnabled(isCallStateIdle
-                    && isNonTtyOrTtyOnVolteEnabled);
+
+            boolean isWfcEnabled = false;
+            boolean isCallStateIdle = false;
+
+            final SettingsMainSwitchPreference prefSwitch = (SettingsMainSwitchPreference)
+                    getPreferenceScreen().findPreference(SWITCH_BAR);
+            if (prefSwitch != null) {
+                isWfcEnabled = prefSwitch.isChecked();
+                isCallStateIdle = getTelephonyManagerForSub(
+                        WifiCallingSettingsForSub.this.mSubId).getCallState()
+                        == TelephonyManager.CALL_STATE_IDLE;
+
+                boolean isNonTtyOrTtyOnVolteEnabled = true;
+                if (isWfcEnabled || isCallStateIdle) {
+                    isNonTtyOrTtyOnVolteEnabled =
+                            queryImsState(WifiCallingSettingsForSub.this.mSubId)
+                            .isAllowUserControl();
+                }
+
+                isWfcEnabled = isWfcEnabled && isNonTtyOrTtyOnVolteEnabled;
+                prefSwitch.setEnabled(isCallStateIdle && isNonTtyOrTtyOnVolteEnabled);
+            }
 
             boolean isWfcModeEditable = true;
             boolean isWfcRoamingModeEditable = false;
-            final CarrierConfigManager configManager = (CarrierConfigManager)
-                    activity.getSystemService(Context.CARRIER_CONFIG_SERVICE);
-            if (configManager != null) {
-                PersistableBundle b =
-                        configManager.getConfigForSubId(WifiCallingSettingsForSub.this.mSubId);
-                if (b != null) {
-                    isWfcModeEditable = b.getBoolean(
-                            CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL);
-                    isWfcRoamingModeEditable = b.getBoolean(
-                            CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL);
+            if (isWfcEnabled && isCallStateIdle) {
+                final CarrierConfigManager configManager = (CarrierConfigManager)
+                        activity.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+                if (configManager != null) {
+                    PersistableBundle b = configManager.getConfigForSubId(
+                            WifiCallingSettingsForSub.this.mSubId);
+                    if (b != null) {
+                        isWfcModeEditable = b.getBoolean(
+                                CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL);
+                        isWfcRoamingModeEditable = b.getBoolean(
+                                CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL);
+                    }
                 }
+            } else {
+                isWfcModeEditable = false;
+                isWfcRoamingModeEditable = false;
             }
 
             final Preference pref = getPreferenceScreen().findPreference(BUTTON_WFC_MODE);
             if (pref != null) {
-                pref.setEnabled(isWfcEnabled && isWfcModeEditable
-                        && isCallStateIdle);
+                pref.setEnabled(isWfcModeEditable);
             }
             final Preference pref_roam =
                     getPreferenceScreen().findPreference(BUTTON_WFC_ROAMING_MODE);
             if (pref_roam != null) {
-                pref_roam.setEnabled(isWfcEnabled && isWfcRoamingModeEditable
-                        && isCallStateIdle);
+                pref_roam.setEnabled(isWfcRoamingModeEditable);
             }
         }
     }
@@ -184,20 +198,6 @@
                 }
             };
 
-    @Override
-    public void onActivityCreated(Bundle savedInstanceState) {
-        super.onActivityCreated(savedInstanceState);
-
-        mSwitchBar = getView().findViewById(R.id.switch_bar);
-        mSwitchBar.show();
-    }
-
-    @Override
-    public void onDestroyView() {
-        super.onDestroyView();
-        mSwitchBar.hide();
-    }
-
     @VisibleForTesting
     void showAlert(Intent intent) {
         final Context context = getActivity();
@@ -292,6 +292,8 @@
         mProvisioningManager = getImsProvisioningManager();
         mImsMmTelManager = getImsMmTelManager();
 
+        mSwitchBar = (SettingsMainSwitchPreference) findPreference(SWITCH_BAR);
+
         mButtonWfcMode = findPreference(BUTTON_WFC_MODE);
         mButtonWfcMode.setOnPreferenceChangeListener(this);
 
diff --git a/src/com/android/settings/wifi/p2p/WifiP2pSettings.java b/src/com/android/settings/wifi/p2p/WifiP2pSettings.java
index 5d28bcc..10ee241 100644
--- a/src/com/android/settings/wifi/p2p/WifiP2pSettings.java
+++ b/src/com/android/settings/wifi/p2p/WifiP2pSettings.java
@@ -522,7 +522,7 @@
             final LayoutInflater layoutInflater = LayoutInflater.from(getPrefContext());
             final View root = layoutInflater.inflate(R.layout.dialog_edittext, null /* root */);
             mDeviceNameText = root.findViewById(R.id.edittext);
-            mDeviceNameText.setFilters(new InputFilter[] {new InputFilter.LengthFilter(30)});
+            mDeviceNameText.setFilters(new InputFilter[] {new InputFilter.LengthFilter(22)});
             if (mSavedDeviceName != null) {
                 mDeviceNameText.setText(mSavedDeviceName);
                 mDeviceNameText.setSelection(mSavedDeviceName.length());
diff --git a/src/com/android/settings/wifi/tether/TetherService.java b/src/com/android/settings/wifi/tether/TetherService.java
index 8a557ba..b0e8fd8 100644
--- a/src/com/android/settings/wifi/tether/TetherService.java
+++ b/src/com/android/settings/wifi/tether/TetherService.java
@@ -256,6 +256,7 @@
     }
 
     private void disableTethering(final int tetheringType) {
+        Log.w(TAG, "Disable tethering, type:" + tetheringType);
         final TetheringManager tm = (TetheringManager) getSystemService(Context.TETHERING_SERVICE);
         tm.stopTethering(tetheringType);
     }
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java b/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java
index 580bc39..e88931c 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java
@@ -31,6 +31,7 @@
 import android.net.wifi.WifiManager;
 import android.os.Handler;
 import android.os.Looper;
+import android.util.Log;
 import android.widget.Switch;
 
 import androidx.annotation.VisibleForTesting;
@@ -47,6 +48,8 @@
  */
 public class WifiTetherSwitchBarController implements
         LifecycleObserver, OnStart, OnStop, DataSaverBackend.Listener, OnMainSwitchChangeListener {
+
+    private static final String TAG = "WifiTetherSBC";
     private static final IntentFilter WIFI_INTENT_FILTER;
 
     private final Context mContext;
@@ -63,8 +66,8 @@
                 @Override
                 public void onTetheringFailed() {
                     super.onTetheringFailed();
-                    mSwitchBar.setChecked(false);
-                    updateWifiSwitch();
+                    Log.e(TAG, "Failed to start Wi-Fi Tethering.");
+                    handleWifiApStateChanged(mWifiManager.getWifiApState());
                 }
             };
 
@@ -111,16 +114,28 @@
     }
 
     void stopTether() {
+        if (!isWifiApActivated()) return;
+
         mSwitchBar.setEnabled(false);
         mConnectivityManager.stopTethering(TETHERING_WIFI);
     }
 
     void startTether() {
+        if (isWifiApActivated()) return;
+
         mSwitchBar.setEnabled(false);
         mConnectivityManager.startTethering(TETHERING_WIFI, true /* showProvisioningUi */,
                 mOnStartTetheringCallback, new Handler(Looper.getMainLooper()));
     }
 
+    private boolean isWifiApActivated() {
+        final int wifiApState = mWifiManager.getWifiApState();
+        if (wifiApState == WIFI_AP_STATE_ENABLED || wifiApState == WIFI_AP_STATE_ENABLING) {
+            return true;
+        }
+        return false;
+    }
+
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
diff --git a/tests/robotests/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizardTest.java b/tests/robotests/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizardTest.java
index 0418906..bddaed5 100644
--- a/tests/robotests/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizardTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizardTest.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.accessibility;
 
+import static com.android.settings.accessibility.TextReadingPreferenceFragment.RESET_KEY;
+
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
@@ -25,6 +27,7 @@
 import androidx.test.core.app.ApplicationProvider;
 
 import com.android.settings.R;
+import com.android.settingslib.widget.LayoutPreference;
 
 import com.google.android.setupdesign.GlifPreferenceLayout;
 
@@ -51,6 +54,9 @@
         MockitoAnnotations.initMocks(this);
 
         mFragment = spy(new TextReadingPreferenceFragmentForSetupWizard());
+        final LayoutPreference resetPreference =
+                new LayoutPreference(mContext, R.layout.accessibility_text_reading_reset_button);
+        doReturn(resetPreference).when(mFragment).findPreference(RESET_KEY);
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiScanModeActivityTest.java b/tests/robotests/src/com/android/settings/wifi/WifiScanModeActivityTest.java
index 3e6ba00..1e3afdb 100644
--- a/tests/robotests/src/com/android/settings/wifi/WifiScanModeActivityTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/WifiScanModeActivityTest.java
@@ -16,16 +16,75 @@
 
 package com.android.settings.wifi;
 
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.text.TextUtils;
+
+import com.android.settings.testutils.shadow.ShadowUtils;
+import com.android.settingslib.wifi.WifiPermissionChecker;
+
+import org.junit.After;
+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.Robolectric;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowUtils.class})
 public class WifiScanModeActivityTest {
+
+    static final String LAUNCHED_PACKAGE = "launched_package";
+    static final String APP_LABEL = "app_label";
+
+    @Rule
+    public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+    @Mock
+    WifiPermissionChecker mWifiPermissionChecker;
+
+    WifiScanModeActivity mActivity;
+
+    @Before
+    public void setUp() {
+        mActivity = spy(Robolectric.setupActivity(WifiScanModeActivity.class));
+        mActivity.mWifiPermissionChecker = mWifiPermissionChecker;
+    }
+
+    @After
+    public void tearDown() {
+        ShadowUtils.reset();
+    }
+
     @Test
     public void launchActivity_noIntentAction_shouldNotFatalException() {
         WifiScanModeActivity wifiScanModeActivity =
                 Robolectric.setupActivity(WifiScanModeActivity.class);
     }
+
+    @Test
+    public void refreshAppLabel_noPackageName_shouldNotFatalException() {
+        when(mWifiPermissionChecker.getLaunchedPackage()).thenReturn(null);
+
+        mActivity.refreshAppLabel();
+
+        assertThat(TextUtils.isEmpty(mActivity.mApp)).isTrue();
+    }
+
+    @Test
+    public void refreshAppLabel_hasPackageName_shouldHasAppLabel() {
+        ShadowUtils.setApplicationLabel(LAUNCHED_PACKAGE, APP_LABEL);
+        when(mWifiPermissionChecker.getLaunchedPackage()).thenReturn(LAUNCHED_PACKAGE);
+
+        mActivity.refreshAppLabel();
+
+        assertThat(mActivity.mApp).isEqualTo(APP_LABEL);
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java
index 74bddda..e2c5ca3 100644
--- a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java
@@ -55,6 +55,7 @@
 import com.android.settings.network.ims.WifiCallingQueryImsState;
 import com.android.settings.testutils.shadow.ShadowFragment;
 import com.android.settings.widget.SettingsMainSwitchBar;
+import com.android.settings.widget.SettingsMainSwitchPreference;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -72,6 +73,7 @@
 public class WifiCallingSettingsForSubTest {
     private static final int SUB_ID = 2;
 
+    private static final String SWITCH_BAR = "wifi_calling_switch_bar";
     private static final String BUTTON_WFC_MODE = "wifi_calling_mode";
     private static final String BUTTON_WFC_ROAMING_MODE = "wifi_calling_roaming_mode";
     private static final String PREFERENCE_NO_OPTIONS_DESC = "no_options_description";
@@ -100,6 +102,8 @@
     @Mock
     private View mView;
     @Mock
+    private SettingsMainSwitchPreference mSwitchBarPreference;
+    @Mock
     private LinkifyDescriptionPreference mDescriptionView;
     @Mock
     private ListWithEntrySummaryPreference mButtonWfcMode;
@@ -116,6 +120,7 @@
         doReturn(mContext.getTheme()).when(mActivity).getTheme();
 
         mFragment = spy(new TestFragment());
+        mFragment.setSwitchBar(mSwitchBarPreference);
         doReturn(mActivity).when(mFragment).getActivity();
         doReturn(mContext).when(mFragment).getContext();
         doReturn(mock(Intent.class)).when(mActivity).getIntent();
@@ -125,10 +130,6 @@
         final Bundle bundle = new Bundle();
         when(mFragment.getArguments()).thenReturn(bundle);
         doNothing().when(mFragment).addPreferencesFromResource(anyInt());
-        doReturn(mock(ListWithEntrySummaryPreference.class)).when(mFragment).findPreference(any());
-        doReturn(mButtonWfcMode).when(mFragment).findPreference(BUTTON_WFC_MODE);
-        doReturn(mButtonWfcRoamingMode).when(mFragment).findPreference(BUTTON_WFC_ROAMING_MODE);
-        doReturn(mDescriptionView).when(mFragment).findPreference(PREFERENCE_NO_OPTIONS_DESC);
         doNothing().when(mFragment).finish();
         doReturn(mView).when(mFragment).getView();
 
@@ -344,6 +345,29 @@
     }
 
     protected class TestFragment extends WifiCallingSettingsForSub {
+        private SettingsMainSwitchPreference mSwitchPref;
+
+        protected void setSwitchBar(SettingsMainSwitchPreference switchPref) {
+            mSwitchPref = switchPref;
+        }
+
+        @Override
+        public <T extends Preference> T findPreference(CharSequence key) {
+            if (SWITCH_BAR.equals(key)) {
+                return (T) mSwitchPref;
+            }
+            if (BUTTON_WFC_MODE.equals(key)) {
+                return (T) mButtonWfcMode;
+            }
+            if (BUTTON_WFC_ROAMING_MODE.equals(key)) {
+                return (T) mButtonWfcRoamingMode;
+            }
+            if (PREFERENCE_NO_OPTIONS_DESC.equals(key)) {
+                return (T) mDescriptionView;
+            }
+            return (T) mock(ListWithEntrySummaryPreference.class);
+        }
+
         @Override
         protected Object getSystemService(final String name) {
             switch (name) {
diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSwitchBarControllerTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSwitchBarControllerTest.java
index 7c17c5f..ca0247f 100644
--- a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSwitchBarControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSwitchBarControllerTest.java
@@ -84,7 +84,44 @@
     }
 
     @Test
+    public void startTether_wifiApIsActivated_doNothing() {
+        when(mWifiManager.getWifiApState()).thenReturn(WIFI_AP_STATE_ENABLED);
+
+        mController.startTether();
+
+        verify(mConnectivityManager, never()).startTethering(anyInt(), anyBoolean(), any(), any());
+    }
+
+    @Test
+    public void startTether_wifiApNotActivated_startTethering() {
+        when(mWifiManager.getWifiApState()).thenReturn(WIFI_AP_STATE_DISABLED);
+
+        mController.startTether();
+
+        verify(mConnectivityManager).startTethering(anyInt(), anyBoolean(), any(), any());
+    }
+
+    @Test
+    public void stopTether_wifiApIsActivated_stopTethering() {
+        when(mWifiManager.getWifiApState()).thenReturn(WIFI_AP_STATE_ENABLED);
+
+        mController.stopTether();
+
+        verify(mConnectivityManager).stopTethering(anyInt());
+    }
+
+    @Test
+    public void stopTether_wifiApNotActivated_doNothing() {
+        when(mWifiManager.getWifiApState()).thenReturn(WIFI_AP_STATE_DISABLED);
+
+        mController.stopTether();
+
+        verify(mConnectivityManager, never()).stopTethering(anyInt());
+    }
+
+    @Test
     public void startTether_fail_resetSwitchBar() {
+        when(mWifiManager.getWifiApState()).thenReturn(WIFI_AP_STATE_DISABLED);
         when(mDataSaverBackend.isDataSaverEnabled()).thenReturn(false);
 
         mController.startTether();
@@ -130,6 +167,7 @@
 
     @Test
     public void onSwitchChanged_isNotChecked_stopTethering() {
+        when(mWifiManager.getWifiApState()).thenReturn(WIFI_AP_STATE_ENABLED);
         when(mSwitch.isChecked()).thenReturn(false);
 
         mController.onSwitchChanged(mSwitch, mSwitch.isChecked());
diff --git a/tests/unit/src/com/android/settings/privacy/PrivacyDashboardActivityTest.java b/tests/unit/src/com/android/settings/privacy/PrivacyDashboardActivityTest.java
index 1cfee0f..ae42c84 100644
--- a/tests/unit/src/com/android/settings/privacy/PrivacyDashboardActivityTest.java
+++ b/tests/unit/src/com/android/settings/privacy/PrivacyDashboardActivityTest.java
@@ -44,54 +44,79 @@
 
 @RunWith(AndroidJUnit4.class)
 public class PrivacyDashboardActivityTest {
-
     private static final String DEFAULT_FRAGMENT_CLASSNAME = "DefaultFragmentClassname";
-
     @Mock
     private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper;
     private Settings.PrivacyDashboardActivity mActivity;
+    private static final String ACTION_PRIVACY_ADVANCED_SETTINGS =
+            "android.settings.PRIVACY_ADVANCED_SETTINGS";
 
     @Before
-    public void setUp() throws Exception {
+    public void setUp() {
         MockitoAnnotations.initMocks(this);
-
         SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper;
-        final Intent intent = new Intent();
-        intent.setAction(android.provider.Settings.ACTION_PRIVACY_SETTINGS);
-        intent.setClass(InstrumentationRegistry.getInstrumentation().getTargetContext(),
-                Settings.PrivacyDashboardActivity.class);
-        intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT, DEFAULT_FRAGMENT_CLASSNAME);
-        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
-            try {
-                mActivity =
-                        spy((Settings.PrivacyDashboardActivity) InstrumentationRegistry
-                                .getInstrumentation().newActivity(
-                                        getClass().getClassLoader(),
-                                        Settings.PrivacyDashboardActivity.class.getName(),
-                                        intent));
-            } catch (Exception e) {
-                throw new RuntimeException(e); // nothing to do
-            }
-        });
-        doNothing().when(mActivity).startActivity(any(Intent.class));
     }
 
     @Test
-    public void onCreate_whenSafetyCenterEnabled_redirectsToSafetyCenter() {
+    public void onCreate_whenSafetyCenterEnabled_redirectsToSafetyCenter() throws Exception {
+        startActivityUsingIntent(android.provider.Settings.ACTION_PRIVACY_SETTINGS);
         when(mSafetyCenterManagerWrapper.isEnabled(any(Context.class))).thenReturn(true);
         final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
-
         mActivity.handleSafetyCenterRedirection();
-
         verify(mActivity).startActivity(intentCaptor.capture());
         assertThat(intentCaptor.getValue().getAction()).isEqualTo(Intent.ACTION_SAFETY_CENTER);
     }
 
     @Test
-    public void onCreate_whenSafetyCenterDisabled_doesntRedirectToSafetyCenter() {
+    public void onCreateWithAdvancedIntent_whenSafetyCenterEnabled_doesntRedirectToSafetyCenter()
+            throws Exception {
+        startActivityUsingIntent(ACTION_PRIVACY_ADVANCED_SETTINGS);
+        when(mSafetyCenterManagerWrapper.isEnabled(any(Context.class))).thenReturn(true);
+        final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+        mActivity.handleSafetyCenterRedirection();
+        verify(mActivity, times(0)).startActivity(any());
+    }
+
+    @Test
+    public void onCreate_whenSafetyCenterDisabled_doesntRedirectToSafetyCenter() throws Exception {
+        startActivityUsingIntent(android.provider.Settings.ACTION_PRIVACY_SETTINGS);
         when(mSafetyCenterManagerWrapper.isEnabled(any(Context.class))).thenReturn(false);
         mActivity.handleSafetyCenterRedirection();
-
         verify(mActivity, times(0)).startActivity(any());
     }
+
+    @Test
+    public void onCreateWithAdvancedIntent_whenSafetyCenterDisabled_doesntRedirectToSafetyCenter()
+            throws Exception {
+        startActivityUsingIntent(ACTION_PRIVACY_ADVANCED_SETTINGS);
+        when(mSafetyCenterManagerWrapper.isEnabled(any(Context.class))).thenReturn(true);
+        final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+        mActivity.handleSafetyCenterRedirection();
+        verify(mActivity, times(0)).startActivity(any());
+    }
+
+    private void startActivityUsingIntent(String intentAction) throws Exception {
+        MockitoAnnotations.initMocks(this);
+        SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper;
+        final Intent intent = new Intent();
+        intent.setAction(intentAction);
+        intent.setClass(InstrumentationRegistry.getInstrumentation().getTargetContext(),
+                Settings.PrivacyDashboardActivity.class);
+        intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT, DEFAULT_FRAGMENT_CLASSNAME);
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            try {
+                Settings.PrivacyDashboardActivity activity =
+                        (Settings.PrivacyDashboardActivity) InstrumentationRegistry
+                                .getInstrumentation().newActivity(
+                                        getClass().getClassLoader(),
+                                        Settings.PrivacyDashboardActivity.class.getName(),
+                                        intent);
+                activity.setIntent(intent);
+                mActivity = spy(activity);
+            } catch (Exception e) {
+                throw new RuntimeException(e); // nothing to do
+            }
+        });
+        doNothing().when(mActivity).startActivity(any(Intent.class));
+    }
 }