Merge "Redirect AdvancedSecuritySettings to MoreSettings"
diff --git a/res/drawable/ic_fast_pair_24dp.xml b/res/drawable/ic_fast_pair_24dp.xml
deleted file mode 100644
index 17bfdd9..0000000
--- a/res/drawable/ic_fast_pair_24dp.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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="?android:attr/colorControlNormal">
-
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M20.65,19.27c-0.35,0-0.69-0.13-0.96-0.4l-8.66-8.66c-0.53-0.53-0.53-1.38,0-1.91 c0.53-0.53,1.38-0.53,1.91,0l8.66,8.66c0.53,0.53,0.53,1.38,0,1.91C21.34,19.14,20.99,19.27,20.65,19.27z" />
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M12.01,16.09c-0.35,0-0.69-0.13-0.96-0.4L2.4,7.04c-0.53-0.53-0.53-1.38,0-1.91s1.38-0.53,1.91,0l8.66,8.66 c0.53,0.53,0.53,1.38,0,1.91C12.7,15.96,12.36,16.09,12.01,16.09z" />
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M6.32,19.06c0-0.34,0.13-0.69,0.4-0.95l1.85-1.85c0.53-0.53,1.38-0.53,1.91,0c0.53,0.53,0.53,1.38,0,1.91 l-1.85,1.85c-0.53,0.53-1.38,0.53-1.91,0C6.45,19.75,6.32,19.4,6.32,19.06z" />
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M13.13,6.79c0-0.34,0.13-0.69,0.4-0.95l1.85-1.85c0.53-0.53,1.38-0.53,1.91,0c0.53,0.53,0.53,1.38,0,1.91 l-1.85,1.85c-0.53,0.53-1.38,0.53-1.91,0C13.27,7.48,13.13,7.13,13.13,6.79z" />
-</vector>
\ No newline at end of file
diff --git a/res/values/config.xml b/res/values/config.xml
index df2bae3..628699a 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -689,4 +689,7 @@
         58.0001 29.2229,56.9551 26.8945,55.195
     </string>
 
+    <!-- Whether auto data switching on secondary SIM enables cross-SIM calling on both SIMs. -->
+    <bool name="config_auto_data_switch_enables_cross_sim_calling">false</bool>
+
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 5d32022..23f7a9f 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -4080,6 +4080,18 @@
     <string name="experimental_category_title">Experimental</string>
     <!-- Title for feature flags dashboard where developers can turn on experimental features [CHAR LIMIT=50] -->
     <string name="feature_flags_dashboard_title">Feature flags</string>
+    <!-- Title for snoop logger filters dashboard where developers can turn on filters [CHAR LIMIT=50] -->
+    <string name="snoop_logger_filters_dashboard_title">Snoop Logger Filters</string>
+    <!-- Summary for the snoop logger filters [CHAR LIMIT=50] -->
+    <string name="bt_hci_snoop_log_filters_dashboard_summary">Set filters (Toggle Bluetooth after changing this setting)</string>
+    <!-- Title for the snoop logger pbap filter [CHAR LIMIT=50] -->
+    <string name="bt_hci_snoop_log_filter_pbap_title">Snoop Logger Filter PBAP</string>
+    <!-- Title for the snoop logger map filter [CHAR LIMIT=50] -->
+    <string name="bt_hci_snoop_log_filter_map_title">Snoop Logger Filter MAP</string>
+    <!-- Summary for the snoop logger filters [CHAR LIMIT=50] -->
+    <string name="bt_hci_snoop_log_filter_summary">Set filtering mode. (Toggle Bluetooth after changing this setting)</string>
+    <!-- Summary for the snoop logger profile filters while disabled [CHAR LIMIT=50] -->
+    <string name="bt_hci_snoop_log_filtered_mode_disabled_summary">Enable Snoop Log Mode Filtered to change this option.</string>
     <!-- Title for the Talkback Accessibility Service. Displayed on the Accessibility Settings screen in Setup Wizard. [CHAR_LIMIT=25] -->
     <string name="talkback_title">Talkback</string>
     <!-- Summary for the Talkback Accessibility Service. Lets the user know that Talkback is a screenreader and that it is usually most helpful to blind and low vision users and whether the service is on. [CHAR_LIMIT=none] -->
@@ -4828,19 +4840,6 @@
     <!-- List of synonyms used in the settings search bar to find the “Voice Access”. [CHAR LIMIT=NONE] -->
     <string name="keywords_voice_access"></string>
 
-    <!-- Fast Pair settings -->
-    <skip />
-
-    <!-- Title in main settings screen for Fast Pair settings [CHAR LIMIT=15] -->
-    <string name="fast_pair_settings">Fast Pair</string>
-
-    <!-- Fast Pair setting summary in settings screen [CHAR LIMIT=50] -->
-    <string name="fast_pair_settings_summary">Nearby detection of Fast Pair bluetooth devices.</string>
-    <!-- Title for Fast Pair main switch preferences. [CHAR LIMIT=50] -->
-    <string name="fast_pair_main_switch_title">Scan for nearby devices</string>
-    <!-- Title for Fast Pair saved devices preferences. [CHAR LIMIT=50] -->
-    <string name="fast_pair_saved_devices_title">Saved devices</string>
-    <!-- Printing settings -->
     <skip />
 
     <!-- Title in main settings screen for printing settings [CHAR LIMIT=15] -->
@@ -6457,6 +6456,7 @@
     <string name="help_url_privacy_dashboard" translatable="false"></string>
 
     <string name="help_url_memtag" translatable="false"></string>
+    <string name="help_url_development_memtag" translatable="false"></string>
     <string name="help_url_network_dashboard" translatable="false"></string>
     <string name="help_url_connected_devices" translatable="false"></string>
     <string name="help_url_apps_and_notifications" translatable="false"></string>
@@ -6885,9 +6885,6 @@
     <!-- List of synonyms for the Bluetooth setting, used to match in settings search [CHAR LIMIT=NONE] -->
     <string name="keywords_bluetooth_settings">connected, device, headphones, headset, speaker, wireless, pair, earbuds, music, media </string>
 
-    <!-- List of synonyms for the Fast Pair setting, used to match in settings search [CHAR LIMIT=NONE] -->
-    <string name="keywords_fast_pair">pair, earbuds, bluetooth</string>
-
     <!-- List of synonyms for the Wallpaper picker setting, used to match in settings search [CHAR LIMIT=NONE] -->
     <string name="keywords_wallpaper">background, theme, grid, customize, personalize</string>
 
@@ -8583,11 +8580,11 @@
     <!-- Label for list that shows all permissions -->
     <string name="app_permissions">Permission manager</string>
 
-    <!-- Label for the list that shows all data sharing updates. TODO b/261914980 finalize string [CHAR LIMIT=30]-->
-    <string name="app_data_sharing_updates_title">Data sharing updates</string>
+    <!-- Title for the entrypoint that navigates to the App Data Sharing Updates page. [CHAR LIMIT=70]-->
+    <string name="app_data_sharing_updates_title">Data sharing updates for location</string>
 
-    <!-- Label for the list that shows all data sharing updates TODO b/261914980 finalize string [CHAR LIMIT=NONE]-->
-    <string name="app_data_sharing_updates_summary">Show which apps recently updated data sharing policy</string>
+    <!-- Summary for the entrypoint that navigates to the App Data Sharing Updates page. [CHAR LIMIT=130]-->
+    <string name="app_data_sharing_updates_summary">Review apps that changed the way they may share your location data</string>
 
     <!-- Label for tap to wake setting [CHAR LIMIT=30] -->
     <string name="tap_to_wake">Tap to wake</string>
@@ -10871,14 +10868,26 @@
 
     <!-- Title for the button to initiate a heap dump for the system server. [CHAR LIMIT=NONE] -->
     <string name="capture_system_heap_dump_title">Capture system heap dump</string>
+
+    <!-- [CHAR LIMIT=32] Name of MTE page in "Developer Options" and heading of page. -->
+    <string name="development_memtag_page_title">Memory Tagging Extension</string>
+    <!-- [CHAR LIMIT=52] Label for button to turn on / off MTE protection.-->
+    <string name="development_memtag_intro">Memory Tagging Extension (MTE) makes it easier to find memory safety issues in your app and make native code in it more secure.</string>
+    <string name="development_memtag_footer">Turning on MTE might cause slower device performance.</string>
+    <string name="development_memtag_learn_more">Learn more about MTE</string>
+    <string name="development_memtag_toggle">Enable MTE until you turn it off</string>
+    <!-- [CHAR LIMIT=NONE] Message shown in dialog prompting user to reboot device to turn on MTE.-->
+    <string name="development_memtag_reboot_message_on">You\u0027ll need to restart your device to turn on MTE.</string>
+    <!-- [CHAR LIMIT=NONE] Message shown in dialog prompting user to reboot device to turn off MTE.-->
+    <string name="development_memtag_reboot_message_off">You\u0027ll need to restart your device to turn off MTE.</string>
     <!-- Title for the button to reboot with MTE enabled. [CHAR LIMIT=NONE] -->
-    <string name="reboot_with_mte_title">Reboot with MTE</string>
-    <string name="reboot_with_mte_message">System will reboot and allow to experiment with Memory Tagging Extension (MTE). MTE may negatively impact system performance and stability. Will be reset on next subsequent reboot.</string>
+    <string name="reboot_with_mte_title">Enable MTE for a single session</string>
+    <string name="reboot_with_mte_message">System will restart and allow to experiment with Memory Tagging Extension (MTE). MTE may negatively impact system performance and stability. Will be reset on next subsequent reboot.</string>
     <!-- Subtext for button if MTE is not enabled through Advanced memory protection. -->
-    <string name="reboot_with_mte_summary">Try MTE for a single boot for app development</string>
+    <string name="reboot_with_mte_summary">Restart for a single session with MTE enabled</string>
     <!-- Subtext for button if MTE is already enabled through Advanced memory protection.
          The string for "Advanced memory protection" needs to match "memtag_toggle" above -->
-    <string name="reboot_with_mte_already_enabled">MTE is enabled through Advanced memory protection</string>
+    <string name="reboot_with_mte_already_enabled">MTE is already enabled</string>
     <!-- Toast that is shown when the user initiates capturing a heap dump for the system server. [CHAR LIMIT=NONE] -->
     <string name="capturing_system_heap_dump_message">Capturing system heap dump</string>
     <!-- Toast that is shown if there's an error capturing the user initiated heap dump. [CHAR LIMIT=NONE] -->
diff --git a/res/xml/bluetooth_audio_routing_fragment.xml b/res/xml/bluetooth_audio_routing_fragment.xml
index 18f18f2..79494c4 100644
--- a/res/xml/bluetooth_audio_routing_fragment.xml
+++ b/res/xml/bluetooth_audio_routing_fragment.xml
@@ -30,7 +30,8 @@
         android:summary="%s"
         android:key="audio_routing_ringtone"
         android:persistent="false"
-        android:title="@string/bluetooth_ringtone_title" />
+        android:title="@string/bluetooth_ringtone_title"
+        settings:controller="com.android.settings.bluetooth.HearingDeviceRingtoneRoutingPreferenceController" />
 
     <ListPreference
         android:entries="@array/bluetooth_audio_routing_titles"
@@ -38,7 +39,8 @@
         android:summary="%s"
         android:key="audio_routing_call"
         android:persistent="false"
-        android:title="@string/bluetooth_call_title" />
+        android:title="@string/bluetooth_call_title"
+        settings:controller="com.android.settings.bluetooth.HearingDeviceCallRoutingPreferenceController" />
 
     <ListPreference
         android:entries="@array/bluetooth_audio_routing_titles"
@@ -46,7 +48,8 @@
         android:summary="%s"
         android:key="audio_routing_media"
         android:persistent="false"
-        android:title="@string/bluetooth_media_title" />
+        android:title="@string/bluetooth_media_title"
+        settings:controller="com.android.settings.bluetooth.HearingDeviceMediaRoutingPreferenceController" />
 
     <ListPreference
         android:entries="@array/bluetooth_audio_routing_titles"
@@ -54,6 +57,7 @@
         android:summary="%s"
         android:key="audio_routing_system_sounds"
         android:persistent="false"
-        android:title="@string/bluetooth_system_sounds_title" />
+        android:title="@string/bluetooth_system_sounds_title"
+        settings:controller="com.android.settings.bluetooth.HearingDeviceSystemSoundsRoutingPreferenceController" />
 
 </PreferenceScreen>
diff --git a/res/xml/connected_devices_advanced.xml b/res/xml/connected_devices_advanced.xml
index bd8eafb..46d1a0a 100644
--- a/res/xml/connected_devices_advanced.xml
+++ b/res/xml/connected_devices_advanced.xml
@@ -69,15 +69,6 @@
         settings:userRestriction="no_ultra_wideband_radio"
         settings:useAdminDisabledSummary="true"/>
 
-    <Preference
-        android:key="connected_device_fast_pair"
-        android:title="@string/fast_pair_settings"
-        android:summary="@string/fast_pair_settings_summary"
-        android:icon="@drawable/ic_fast_pair_24dp"
-        android:fragment="com.android.settings.nearby.FastPairSettingsFragment"
-        settings:controller="com.android.settings.nearby.FastPairPreferenceController"
-        android:order="-2"/>
-
     <PreferenceCategory
         android:key="dashboard_tile_placeholder"
         android:order="-8"/>
diff --git a/res/xml/development_memtag_page.xml b/res/xml/development_memtag_page.xml
new file mode 100644
index 0000000..e230821
--- /dev/null
+++ b/res/xml/development_memtag_page.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 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:title="@string/development_memtag_page_title">
+
+    <com.android.settingslib.widget.TopIntroPreference
+        android:title="@string/development_memtag_intro"
+        settings:searchable="false"/>
+
+    <com.android.settingslib.RestrictedSwitchPreference
+        android:key="development_memtag"
+        android:title="@string/development_memtag_toggle"
+        settings:controller="com.android.settings.development.DevelopmentMemtagPreferenceController" />
+
+    <Preference
+        android:key="reboot_with_mte"
+        android:title="@string/reboot_with_mte_title"
+        settings:controller="com.android.settings.development.RebootWithMtePreferenceController" />
+
+    <com.android.settingslib.widget.FooterPreference
+        android:title="@string/development_memtag_footer"
+        android:key="memtag_footer"
+        settings:searchable="false"
+        settings:controller="com.android.settings.development.DevelopmentMemtagFooterPreferenceController" />
+</PreferenceScreen>
diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml
index 82d7e43..ae93eed 100644
--- a/res/xml/development_settings.xml
+++ b/res/xml/development_settings.xml
@@ -45,8 +45,9 @@
             android:title="@string/capture_system_heap_dump_title" />
 
         <Preference
-            android:key="reboot_with_mte"
-            android:title="@string/reboot_with_mte_title" />
+            android:key="development_memtag_page"
+            android:title="@string/development_memtag_page_title"
+            android:fragment="com.android.settings.development.DevelopmentMemtagPage" />
 
         <Preference
             android:key="local_backup_password"
@@ -80,6 +81,26 @@
             android:entries="@array/bt_hci_snoop_log_entries"
             android:entryValues="@array/bt_hci_snoop_log_values" />
 
+        <Preference
+            android:key="snoop_logger_filters_dashboard"
+            android:title="@string/snoop_logger_filters_dashboard_title"
+            android:fragment=
+                "com.android.settings.development.snooplogger.SnoopLoggerFiltersDashboard" />
+
+        <ListPreference
+            android:key="bt_hci_snoop_log_filter_pbap"
+            android:title="@string/bt_hci_snoop_log_filter_pbap_title"
+            android:dialogTitle="@string/bt_hci_snoop_log_filter_summary"
+            android:entries="@array/bt_hci_snoop_log_profile_filter_entries"
+            android:entryValues="@array/bt_hci_snoop_log_profile_filter_values" />
+
+        <ListPreference
+            android:key="bt_hci_snoop_log_filter_map"
+            android:title="@string/bt_hci_snoop_log_filter_map_title"
+            android:dialogTitle="@string/bt_hci_snoop_log_filter_summary"
+            android:entries="@array/bt_hci_snoop_log_profile_filter_entries"
+            android:entryValues="@array/bt_hci_snoop_log_profile_filter_values" />
+
         <com.android.settingslib.RestrictedSwitchPreference
             android:key="oem_unlock_enable"
             android:title="@string/oem_unlock_enable"
diff --git a/res/xml/fast_pair_settings.xml b/res/xml/fast_pair_settings.xml
deleted file mode 100644
index 95662fc..0000000
--- a/res/xml/fast_pair_settings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?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:title="@string/fast_pair_settings"
-    settings:keywords="@string/keywords_fast_pair">
-
-    <com.android.settingslib.widget.MainSwitchPreference
-        android:key="fast_pair_scan_switch"
-        android:title="@string/fast_pair_main_switch_title" />
-
-    <Preference
-        android:key="saved_devices"
-        android:title="@string/fast_pair_saved_devices_title" />
-
-</PreferenceScreen>
diff --git a/res/xml/more_security_privacy_settings.xml b/res/xml/more_security_privacy_settings.xml
index 00957f7..5fce68f 100644
--- a/res/xml/more_security_privacy_settings.xml
+++ b/res/xml/more_security_privacy_settings.xml
@@ -22,9 +22,10 @@
     android:title="@string/more_security_privacy_settings">
 
     <!-- work profile security section. See also: security_advanced_settings.xml and
-    privacy_advanced_settings.xml. That page also has some duplicate entries -->
+    privacy_advanced_settings.xml. That page also has these same entries.
+     The order is -10 to make sure it is always at the top. -->
     <PreferenceCategory
-        android:order="10"
+        android:order="-10"
         android:key="work_profile_category"
         android:title="@string/work_profile_category_header">
 
@@ -45,141 +46,27 @@
             android:key="visiblepattern_profile"
             android:title="@string/lockpattern_settings_enable_visible_pattern_title_profile" />
 
-        <com.android.settingslib.RestrictedPreference
-            android:key="fingerprint_settings_profile"
-            android:title="@string/security_settings_work_fingerprint_preference_title"
-            android:summary="@string/summary_placeholder" />
-
-        <com.android.settingslib.RestrictedPreference
-            android:key="face_settings_profile"
-            android:title="@string/security_settings_face_profile_preference_title"
-            android:summary="@string/summary_placeholder" />
-
-        <com.android.settingslib.RestrictedPreference
-            android:key="biometric_settings_profile"
-            android:title="@string/security_settings_work_biometric_preference_title"
-            android:summary="@string/summary_placeholder" />
-
-    </PreferenceCategory>
-
-    <PreferenceCategory
-        android:key="privacy_work_profile_notifications_category"
-        android:title="@string/profile_section_header_for_advanced_privacy"
-        android:layout="@layout/preference_category_no_label"
-        android:order="20">
-
         <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="21"
             settings:searchable="false"/>
-    </PreferenceCategory>
 
-    <!-- Connected work and personal apps -->
-    <Preference
-        android:key="interact_across_profiles_privacy"
-        android:title="@string/interact_across_profiles_title"
-        android:order="25"
-        android:fragment="com.android.settings.applications.specialaccess.interactacrossprofiles.InteractAcrossProfilesSettings"
-        settings:searchable="false"
-        settings:controller="com.android.settings.applications.specialaccess.interactacrossprofiles.InteractAcrossProfilesController" />
-
-    <!-- Main security section - for trust agents added in code. -->
-    <PreferenceCategory
-        android:order="30"
-        android:key="security_category"
-        android:title="@string/security_header" />
-
-    <PreferenceCategory
-        android:order="40"
-        android:key="security_settings_device_admin_category"
-        android:layout="@layout/preference_category_no_label">
-
+        <!-- Connected work and personal apps -->
         <Preference
-            android:key="manage_device_admin"
-            android:title="@string/manage_device_admin"
-            android:summary="@string/summary_placeholder"
-            android:fragment=
-                "com.android.settings.applications.specialaccess.deviceadmin.DeviceAdminSettings"
-            settings:controller=
-                "com.android.settings.enterprise.ManageDeviceAdminPreferenceController" />
-
-        <Preference
-            android:key="enterprise_privacy"
-            android:title="@string/enterprise_privacy_settings"
-            android:summary="@string/summary_placeholder"
-            android:fragment="com.android.settings.enterprise.EnterprisePrivacySettings"
-            settings:controller="com.android.settings.enterprise.EnterprisePrivacyPreferenceController"/>
-
-        <Preference
-            android:key="financed_privacy"
-            android:title="@string/financed_privacy_settings"
-            android:summary="@string/summary_placeholder"
-            android:fragment="com.android.settings.enterprise.EnterprisePrivacySettings"
-            settings:controller="com.android.settings.enterprise.FinancedPrivacyPreferenceController"/>
+            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" />
 
     </PreferenceCategory>
 
-    <Preference
-        android:order="50"
-        android:key="sim_lock_settings"
-        android:title="@string/sim_lock_settings_category"
-        settings:isPreferenceVisible="@bool/config_show_sim_info"
-        settings:controller="com.android.settings.security.SimLockPreferenceController">
-
-        <intent
-            android:action="android.intent.action.MAIN"
-            android:targetPackage="com.android.settings"
-            android:targetClass="com.android.settings.Settings$IccLockSettingsActivity" />
-
-    </Preference>
-
-    <Preference
-        android:order="60"
-        android:key="encryption_and_credential"
-        android:title="@string/encryption_and_credential_settings_title"
-        android:summary="@string/encryption_and_credential_settings_summary"
-        android:fragment="com.android.settings.security.EncryptionAndCredential"
-        settings:controller="com.android.settings.security.EncryptionStatusPreferenceController" />
-
-    <Preference
-        android:order="70"
-        android:key="manage_trust_agents"
-        android:title="@string/manage_trust_agents"
-        android:summary="@string/summary_placeholder"
-        android:fragment="com.android.settings.security.trustagent.TrustAgentSettings"
-        settings:controller="com.android.settings.security.trustagent.ManageTrustAgentsPreferenceController" />
-
-    <Preference
-        android:order="80"
-        android:key="screen_pinning_settings"
-        android:title="@string/screen_pinning_title"
-        android:summary="@string/summary_placeholder"
-        android:fragment="com.android.settings.security.ScreenPinningSettings"
-        settings:keywords="@string/keywords_app_pinning"
-        settings:controller="com.android.settings.security.ScreenPinningPreferenceController" />
-
-    <SwitchPreference
-        android:order="90"
-        android:key="confirm_sim_deletion"
-        android:title="@string/confirm_sim_deletion_title"
-        android:summary="@string/confirm_sim_deletion_description"
-        settings:isPreferenceVisible="@bool/config_show_sim_info"
-        settings:controller="com.android.settings.security.ConfirmSimDeletionPreferenceController" />
-
-    <Preference
-        android:order="100"
-        android:id="@+id/memtag_page"
-        android:key="memtag_page"
-        android:title="@string/memtag_title"
-        android:fragment="com.android.settings.security.MemtagPage"
-        settings:controller="com.android.settings.security.MemtagPagePreferenceController" />
-
 
     <!-- Privacy section -->
+    <!-- The order is -1 to make sure it is above all the privacy entries. Some dynamically injected entries have order 0. -->
     <PreferenceCategory
-        android:order="200"
+        android:order="-1"
         android:key="privacy_category"
         android:title="@string/privacy_header">
         <!-- Accessibility usage -->
@@ -224,4 +111,98 @@
 
     </PreferenceCategory>
 
+    <!-- Security section. -->
+    <!-- "security_category" is used to add trust agents by TrustAgentListPreferenceController -->
+    <PreferenceCategory
+        android:order="200"
+        android:key="security_category"
+        android:title="@string/security_header" />
+
+    <PreferenceCategory
+        android:order="240"
+        android:key="security_settings_device_admin_category"
+        android:layout="@layout/preference_category_no_label">
+
+        <Preference
+            android:key="manage_device_admin"
+            android:title="@string/manage_device_admin"
+            android:summary="@string/summary_placeholder"
+            android:fragment=
+                "com.android.settings.applications.specialaccess.deviceadmin.DeviceAdminSettings"
+            settings:controller=
+                "com.android.settings.enterprise.ManageDeviceAdminPreferenceController" />
+
+        <Preference
+            android:key="enterprise_privacy"
+            android:title="@string/enterprise_privacy_settings"
+            android:summary="@string/summary_placeholder"
+            android:fragment="com.android.settings.enterprise.EnterprisePrivacySettings"
+            settings:controller="com.android.settings.enterprise.EnterprisePrivacyPreferenceController"/>
+
+        <Preference
+            android:key="financed_privacy"
+            android:title="@string/financed_privacy_settings"
+            android:summary="@string/summary_placeholder"
+            android:fragment="com.android.settings.enterprise.EnterprisePrivacySettings"
+            settings:controller="com.android.settings.enterprise.FinancedPrivacyPreferenceController"/>
+
+    </PreferenceCategory>
+
+    <Preference
+        android:order="250"
+        android:key="sim_lock_settings"
+        android:title="@string/sim_lock_settings_category"
+        settings:isPreferenceVisible="@bool/config_show_sim_info"
+        settings:controller="com.android.settings.security.SimLockPreferenceController">
+
+        <intent
+            android:action="android.intent.action.MAIN"
+            android:targetPackage="com.android.settings"
+            android:targetClass="com.android.settings.Settings$IccLockSettingsActivity" />
+
+    </Preference>
+
+    <Preference
+        android:order="260"
+        android:key="encryption_and_credential"
+        android:title="@string/encryption_and_credential_settings_title"
+        android:summary="@string/encryption_and_credential_settings_summary"
+        android:fragment="com.android.settings.security.EncryptionAndCredential"
+        settings:controller="com.android.settings.security.EncryptionStatusPreferenceController" />
+
+    <Preference
+        android:order="270"
+        android:key="manage_trust_agents"
+        android:title="@string/manage_trust_agents"
+        android:summary="@string/summary_placeholder"
+        android:fragment="com.android.settings.security.trustagent.TrustAgentSettings"
+        settings:controller="com.android.settings.security.trustagent.ManageTrustAgentsPreferenceController" />
+
+    <Preference
+        android:order="280"
+        android:key="screen_pinning_settings"
+        android:title="@string/screen_pinning_title"
+        android:summary="@string/summary_placeholder"
+        android:fragment="com.android.settings.security.ScreenPinningSettings"
+        settings:keywords="@string/keywords_app_pinning"
+        settings:controller="com.android.settings.security.ScreenPinningPreferenceController" />
+
+    <SwitchPreference
+        android:order="290"
+        android:key="confirm_sim_deletion"
+        android:title="@string/confirm_sim_deletion_title"
+        android:summary="@string/confirm_sim_deletion_description"
+        settings:isPreferenceVisible="@bool/config_show_sim_info"
+        settings:controller="com.android.settings.security.ConfirmSimDeletionPreferenceController" />
+
+    <Preference
+        android:order="300"
+        android:id="@+id/memtag_page"
+        android:key="memtag_page"
+        android:title="@string/memtag_title"
+        android:fragment="com.android.settings.security.MemtagPage"
+        settings:controller="com.android.settings.security.MemtagPagePreferenceController" />
+
+
+
 </PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/snoop_logger_filters_settings.xml b/res/xml/snoop_logger_filters_settings.xml
new file mode 100644
index 0000000..c804ec6
--- /dev/null
+++ b/res/xml/snoop_logger_filters_settings.xml
@@ -0,0 +1,29 @@
+<?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:title="@string/snoop_logger_filters_dashboard_title" >
+
+    <PreferenceCategory
+        android:key="snoop_logger_filters_category"
+        android:layout="@layout/preference_category_no_label"
+        android:title="@string/bt_hci_snoop_log_filters_dashboard_summary"
+        settings:controller=
+          "com.android.settings.development.snooplogger.SnoopLoggerFiltersPreferenceController" />
+</PreferenceScreen>
diff --git a/src/com/android/settings/TestingSettings.java b/src/com/android/settings/TestingSettings.java
index c1df705..48b5be3 100644
--- a/src/com/android/settings/TestingSettings.java
+++ b/src/com/android/settings/TestingSettings.java
@@ -17,27 +17,41 @@
 package com.android.settings;
 
 import android.app.settings.SettingsEnums;
+import android.content.Context;
 import android.os.Bundle;
 import android.os.UserManager;
 
+import androidx.annotation.VisibleForTesting;
 import androidx.preference.PreferenceScreen;
 
+import com.android.settings.network.telephony.MobileNetworkUtils;
+
 public class TestingSettings extends SettingsPreferenceFragment {
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        
+
         addPreferencesFromResource(R.xml.testing_settings);
 
-        final UserManager um = UserManager.get(getContext());
-        if (!um.isAdminUser()) {
+        if (!isRadioInfoVisible(getContext())) {
             PreferenceScreen preferenceScreen = (PreferenceScreen)
                     findPreference("radio_info_settings");
             getPreferenceScreen().removePreference(preferenceScreen);
         }
     }
 
+    @VisibleForTesting
+    protected boolean isRadioInfoVisible(Context context) {
+        UserManager um = context.getSystemService(UserManager.class);
+        if (um != null) {
+            if (!um.isAdminUser()) {
+                return false;
+            }
+        }
+        return !MobileNetworkUtils.isMobileNetworkUserRestricted(context);
+    }
+
     @Override
     public int getMetricsCategory() {
         return SettingsEnums.TESTING;
diff --git a/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizard.java b/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizard.java
index 6c32edd..f452737 100644
--- a/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizard.java
+++ b/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizard.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.accessibility;
 
+import static android.app.Activity.RESULT_CANCELED;
+
 import static com.android.settings.Utils.getAdaptiveIcon;
 import static com.android.settingslib.widget.TwoTargetPreference.ICON_SIZE_MEDIUM;
 
@@ -41,6 +43,7 @@
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settingslib.RestrictedPreference;
 
+import com.google.android.setupcompat.template.FooterBarMixin;
 import com.google.android.setupdesign.GlifPreferenceLayout;
 
 import java.util.List;
@@ -90,6 +93,12 @@
         final Drawable icon = getContext().getDrawable(R.drawable.ic_accessibility_visibility);
         AccessibilitySetupWizardUtils.updateGlifPreferenceLayout(getContext(), layout, title,
                 description, icon);
+
+        final FooterBarMixin mixin = layout.getMixin(FooterBarMixin.class);
+        AccessibilitySetupWizardUtils.setPrimaryButton(getContext(), mixin, R.string.done, () -> {
+            setResult(RESULT_CANCELED);
+            finish();
+        });
     }
 
     @Override
diff --git a/src/com/android/settings/accessibility/AccessibilitySetupWizardUtils.java b/src/com/android/settings/accessibility/AccessibilitySetupWizardUtils.java
index c530214..b7a3439 100644
--- a/src/com/android/settings/accessibility/AccessibilitySetupWizardUtils.java
+++ b/src/com/android/settings/accessibility/AccessibilitySetupWizardUtils.java
@@ -19,8 +19,13 @@
 import android.graphics.drawable.Drawable;
 import android.widget.LinearLayout;
 
+import androidx.annotation.StringRes;
+
 import com.android.settings.R;
 
+import com.google.android.setupcompat.template.FooterBarMixin;
+import com.google.android.setupcompat.template.FooterButton;
+import com.google.android.setupcompat.template.Mixin;
 import com.google.android.setupdesign.GlifPreferenceLayout;
 import com.google.android.setupdesign.util.ThemeHelper;
 
@@ -30,7 +35,7 @@
     private AccessibilitySetupWizardUtils(){}
 
     /**
-     * Update the {@link GlifPreferenceLayout} attributes if they have previously been initialized.
+     * Updates the {@link GlifPreferenceLayout} attributes if they have previously been initialized.
      * When the SetupWizard supports the extended partner configs, it means the material layout
      * would be applied. It should set a different padding/margin in views to align Settings style
      * for accessibility feature pages.
@@ -55,4 +60,46 @@
             }
         }
     }
+
+    /**
+     * Sets primary button for footer of the {@link GlifPreferenceLayout}.
+     *
+     * <p> This will be the initial by given material theme style.
+     *
+     * @param context A {@link Context}
+     * @param mixin A {@link Mixin} for managing buttons.
+     * @param text The {@code text} by resource.
+     * @param runnable The {@link Runnable} to run.
+     */
+    public static void setPrimaryButton(Context context, FooterBarMixin mixin, @StringRes int text,
+            Runnable runnable) {
+        mixin.setPrimaryButton(
+                new FooterButton.Builder(context)
+                        .setText(text)
+                        .setListener(l -> runnable.run())
+                        .setButtonType(FooterButton.ButtonType.DONE)
+                        .setTheme(R.style.SudGlifButton_Primary)
+                        .build());
+    }
+
+    /**
+     * Sets secondary button for the footer of the {@link GlifPreferenceLayout}.
+     *
+     * <p> This will be the initial by given material theme style.
+     *
+     * @param context A {@link Context}
+     * @param mixin A {@link Mixin} for managing buttons.
+     * @param text The {@code text} by resource.
+     * @param runnable The {@link Runnable} to run.
+     */
+    public static void setSecondaryButton(Context context, FooterBarMixin mixin,
+            @StringRes int text, Runnable runnable) {
+        mixin.setSecondaryButton(
+                new FooterButton.Builder(context)
+                        .setText(text)
+                        .setListener(l -> runnable.run())
+                        .setButtonType(FooterButton.ButtonType.CLEAR)
+                        .setTheme(R.style.SudGlifButton_Secondary)
+                        .build());
+    }
 }
diff --git a/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizard.java b/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizard.java
index cdbfe5f..f2edf8e 100644
--- a/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizard.java
+++ b/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizard.java
@@ -33,7 +33,6 @@
 import com.android.settingslib.Utils;
 
 import com.google.android.setupcompat.template.FooterBarMixin;
-import com.google.android.setupcompat.template.FooterButton;
 import com.google.android.setupdesign.GlifPreferenceLayout;
 
 /**
@@ -55,26 +54,14 @@
                 /* description= */ null, icon);
 
         final FooterBarMixin mixin = layout.getMixin(FooterBarMixin.class);
-        mixin.setSecondaryButton(
-                new FooterButton.Builder(getContext())
-                        .setText(R.string.accessibility_text_reading_reset_button_title)
-                        .setListener(l -> showDialog(DIALOG_RESET_SETTINGS))
-                        .setButtonType(FooterButton.ButtonType.CLEAR)
-                        .setTheme(R.style.SudGlifButton_Secondary)
-                        .build());
-
-        if (isCallingFromAnythingElseEntryPoint()) {
-            mixin.setPrimaryButton(
-                    new FooterButton.Builder(getContext())
-                            .setText(R.string.done)
-                            .setListener(l -> {
-                                setResult(RESULT_CANCELED);
-                                finish();
-                            })
-                            .setButtonType(FooterButton.ButtonType.DONE)
-                            .setTheme(R.style.SudGlifButton_Primary)
-                            .build());
-        }
+        AccessibilitySetupWizardUtils.setPrimaryButton(getContext(), mixin, R.string.done, () -> {
+            setResult(RESULT_CANCELED);
+            finish();
+        });
+        AccessibilitySetupWizardUtils.setSecondaryButton(getContext(), mixin,
+                R.string.accessibility_text_reading_reset_button_title,
+                () -> showDialog(DIALOG_RESET_SETTINGS)
+        );
     }
 
     @Override
diff --git a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentForSetupWizard.java b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentForSetupWizard.java
index 12a9886..a726d81 100644
--- a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentForSetupWizard.java
+++ b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentForSetupWizard.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.accessibility;
 
+import static android.app.Activity.RESULT_CANCELED;
+
 import android.app.settings.SettingsEnums;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
@@ -27,6 +29,7 @@
 
 import com.android.settings.R;
 
+import com.google.android.setupcompat.template.FooterBarMixin;
 import com.google.android.setupdesign.GlifPreferenceLayout;
 
 public class ToggleScreenMagnificationPreferenceFragmentForSetupWizard
@@ -44,6 +47,13 @@
         final Drawable icon = getContext().getDrawable(R.drawable.ic_accessibility_visibility);
         AccessibilitySetupWizardUtils.updateGlifPreferenceLayout(getContext(), layout, title,
                 description, icon);
+
+        final FooterBarMixin mixin = layout.getMixin(FooterBarMixin.class);
+        AccessibilitySetupWizardUtils.setPrimaryButton(getContext(), mixin, R.string.done, () -> {
+            setResult(RESULT_CANCELED);
+            finish();
+        });
+
         hidePreferenceSettingComponents();
     }
 
diff --git a/src/com/android/settings/accessibility/ToggleScreenReaderPreferenceFragmentForSetupWizard.java b/src/com/android/settings/accessibility/ToggleScreenReaderPreferenceFragmentForSetupWizard.java
index f9a1113..89dc437 100644
--- a/src/com/android/settings/accessibility/ToggleScreenReaderPreferenceFragmentForSetupWizard.java
+++ b/src/com/android/settings/accessibility/ToggleScreenReaderPreferenceFragmentForSetupWizard.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.accessibility;
 
+import static android.app.Activity.RESULT_CANCELED;
+
 import android.app.settings.SettingsEnums;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
@@ -27,6 +29,7 @@
 
 import com.android.settings.R;
 
+import com.google.android.setupcompat.template.FooterBarMixin;
 import com.google.android.setupdesign.GlifPreferenceLayout;
 
 public class ToggleScreenReaderPreferenceFragmentForSetupWizard
@@ -45,6 +48,12 @@
         AccessibilitySetupWizardUtils.updateGlifPreferenceLayout(getContext(), layout, title,
                 description, icon);
 
+        final FooterBarMixin mixin = layout.getMixin(FooterBarMixin.class);
+        AccessibilitySetupWizardUtils.setPrimaryButton(getContext(), mixin, R.string.done, () -> {
+            setResult(RESULT_CANCELED);
+            finish();
+        });
+
         mToggleSwitchWasInitiallyChecked = mToggleServiceSwitchPreference.isChecked();
         if (mTopIntroPreference != null) {
             mTopIntroPreference.setVisible(false);
diff --git a/src/com/android/settings/accessibility/ToggleSelectToSpeakPreferenceFragmentForSetupWizard.java b/src/com/android/settings/accessibility/ToggleSelectToSpeakPreferenceFragmentForSetupWizard.java
index a460419..ff9182e 100644
--- a/src/com/android/settings/accessibility/ToggleSelectToSpeakPreferenceFragmentForSetupWizard.java
+++ b/src/com/android/settings/accessibility/ToggleSelectToSpeakPreferenceFragmentForSetupWizard.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.accessibility;
 
+import static android.app.Activity.RESULT_CANCELED;
+
 import android.app.settings.SettingsEnums;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
@@ -27,6 +29,7 @@
 
 import com.android.settings.R;
 
+import com.google.android.setupcompat.template.FooterBarMixin;
 import com.google.android.setupdesign.GlifPreferenceLayout;
 
 public class ToggleSelectToSpeakPreferenceFragmentForSetupWizard
@@ -45,6 +48,12 @@
         AccessibilitySetupWizardUtils.updateGlifPreferenceLayout(getContext(), layout, title,
                 description, icon);
 
+        final FooterBarMixin mixin = layout.getMixin(FooterBarMixin.class);
+        AccessibilitySetupWizardUtils.setPrimaryButton(getContext(), mixin, R.string.done, () -> {
+            setResult(RESULT_CANCELED);
+            finish();
+        });
+
         mToggleSwitchWasInitiallyChecked = mToggleServiceSwitchPreference.isChecked();
         if (mTopIntroPreference != null) {
             mTopIntroPreference.setVisible(false);
diff --git a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
index 7160b0d..873be17 100644
--- a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
+++ b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
@@ -293,8 +293,19 @@
 
                         return true;
                     } else {
-                        // Disable the provider.
-                        togglePackageNameDisabled(packageName);
+                        // If we are disabling the last enabled provider then show a warning.
+                        if (mEnabledPackageNames.size() <= 1) {
+                            final DialogFragment fragment =
+                                    newConfirmationDialogFragment(packageName, title, pref);
+
+                            if (fragment == null || mFragmentManager == null) {
+                                return true;
+                            }
+
+                            fragment.show(mFragmentManager, ConfirmationDialogFragment.TAG);
+                        } else {
+                            togglePackageNameDisabled(packageName);
+                        }
                     }
 
                     return true;
@@ -337,6 +348,29 @@
         return new ErrorDialogFragment(host);
     }
 
+    private @Nullable ConfirmationDialogFragment newConfirmationDialogFragment(
+            @NonNull String packageName,
+            @NonNull CharSequence appName,
+            @NonNull SwitchPreference pref) {
+        DialogHost host =
+                new DialogHost() {
+                    @Override
+                    public void onDialogClick(int whichButton) {
+                        if (whichButton == DialogInterface.BUTTON_POSITIVE) {
+                            // Since the package is now enabled then we
+                            // should remove it from the enabled list.
+                            togglePackageNameDisabled(packageName);
+                        } else if (whichButton == DialogInterface.BUTTON_NEGATIVE) {
+                            // Set the checked back to true because we
+                            // backed out of turning this off.
+                            pref.setChecked(true);
+                        }
+                    }
+                };
+
+        return new ConfirmationDialogFragment(host, packageName, appName);
+    }
+
     private int getUser() {
         UserHandle workUser = getWorkProfileUser();
         return workUser != null ? workUser.getIdentifier() : UserHandle.myUserId();
@@ -386,4 +420,44 @@
         @Override
         public void onClick(DialogInterface dialog, int which) {}
     }
+
+    /**
+     * Confirmation dialog fragment shows a dialog to the user to confirm that they are disabling a
+     * provider.
+     */
+    public static class ConfirmationDialogFragment extends CredentialManagerDialogFragment {
+
+        ConfirmationDialogFragment(
+                DialogHost dialogHost, @NonNull String packageName, @NonNull CharSequence appName) {
+            super(dialogHost);
+
+            final Bundle argument = new Bundle();
+            argument.putString(PACKAGE_NAME_KEY, packageName);
+            argument.putCharSequence(APP_NAME_KEY, appName);
+            setArguments(argument);
+        }
+
+        @Override
+        public Dialog onCreateDialog(Bundle savedInstanceState) {
+            final Bundle bundle = getArguments();
+            final String title =
+                    getContext()
+                            .getString(
+                                    R.string.credman_confirmation_message_title,
+                                    bundle.getCharSequence(
+                                            CredentialManagerDialogFragment.APP_NAME_KEY));
+
+            return new AlertDialog.Builder(getActivity())
+                    .setTitle(title)
+                    .setMessage(getContext().getString(R.string.credman_confirmation_message))
+                    .setPositiveButton(R.string.credman_confirmation_message_positive_button, this)
+                    .setNegativeButton(android.R.string.cancel, this)
+                    .create();
+        }
+
+        @Override
+        public void onClick(DialogInterface dialog, int which) {
+            getDialogHost().onDialogClick(which);
+        }
+    }
 }
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingRfpsFragment.java b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingRfpsFragment.java
index f72e6c4..842bf42 100644
--- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingRfpsFragment.java
+++ b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingRfpsFragment.java
@@ -27,6 +27,7 @@
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
+import android.hardware.fingerprint.FingerprintManager;
 import android.os.Bundle;
 import android.text.TextUtils;
 import android.util.Log;
@@ -40,7 +41,7 @@
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
-import androidx.annotation.IdRes;
+import androidx.activity.OnBackPressedCallback;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.fragment.app.Fragment;
@@ -52,7 +53,6 @@
 import com.android.settings.biometrics.fingerprint.FingerprintErrorDialog;
 import com.android.settings.biometrics2.ui.model.EnrollmentProgress;
 import com.android.settings.biometrics2.ui.model.EnrollmentStatusMessage;
-import com.android.settings.biometrics2.ui.viewmodel.DeviceRotationViewModel;
 import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel;
 import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollProgressViewModel;
 
@@ -80,7 +80,6 @@
     private static final int HINT_TIMEOUT_DURATION = 2500;
 
     private FingerprintEnrollEnrollingViewModel mEnrollingViewModel;
-    private DeviceRotationViewModel mRotationViewModel;
     private FingerprintEnrollProgressViewModel mProgressViewModel;
 
     private Interpolator mFastOutSlowInInterpolator;
@@ -92,13 +91,13 @@
     private ProgressBar mProgressBar;
     private ObjectAnimator mProgressAnim;
     private TextView mErrorText;
-    private FooterBarMixin mFooterBarMixin;
     private AnimatedVectorDrawable mIconAnimationDrawable;
     private AnimatedVectorDrawable mIconBackgroundBlinksDrawable;
+    private int mIconTouchCount;
 
     private final View.OnClickListener mOnSkipClickListener = v -> {
-        mProgressViewModel.cancelEnrollment();
-        mEnrollingViewModel.onSkipButtonClick();
+        mEnrollingViewModel.setOnSkipPressed();
+        cancelEnrollment();
     };
 
     private final Observer<EnrollmentProgress> mProgressObserver = progress -> {
@@ -128,16 +127,21 @@
         }
     };
 
-    private int mIconTouchCount;
-
     @Override
     public void onAttach(@NonNull Context context) {
         final FragmentActivity activity = getActivity();
         final ViewModelProvider provider = new ViewModelProvider(activity);
         mEnrollingViewModel = provider.get(FingerprintEnrollEnrollingViewModel.class);
-        mRotationViewModel = provider.get(DeviceRotationViewModel.class);
         mProgressViewModel = provider.get(FingerprintEnrollProgressViewModel.class);
         super.onAttach(context);
+        requireActivity().getOnBackPressedDispatcher().addCallback(new OnBackPressedCallback(true) {
+            @Override
+            public void handleOnBackPressed() {
+                setEnabled(false);
+                mEnrollingViewModel.setOnBackPressed();
+                cancelEnrollment();
+            }
+        });
     }
 
     @Nullable
@@ -198,8 +202,7 @@
 
         mErrorText = containView.findViewById(R.id.error_text);
         mProgressBar = containView.findViewById(R.id.fingerprint_progress_bar);
-        mFooterBarMixin = containView.getMixin(FooterBarMixin.class);
-        mFooterBarMixin.setSecondaryButton(
+        containView.getMixin(FooterBarMixin.class).setSecondaryButton(
                 new FooterButton.Builder(activity)
                         .setText(R.string.security_settings_fingerprint_enroll_enrolling_skip)
                         .setListener(mOnSkipClickListener)
@@ -263,39 +266,28 @@
         }
     }
 
-    private void onCancelEnrollment(@IdRes int errorMsgId) {
-        // TODO
-        // showErrorDialog() will cause onWindowFocusChanged(false), set mIsCanceled to false
-        // before showErrorDialog() to prevent that another error dialog is triggered again.
-// TODO       mIsCanceled = true;
-// TODO       mIsOrientationChanged = false;
-        mEnrollingViewModel.showErrorDialog(new FingerprintEnrollEnrollingViewModel.ErrorDialogData(
-                mView.getContext().getString(FingerprintErrorDialog.getErrorMessage(errorMsgId)),
-                mView.getContext().getString(FingerprintErrorDialog.getErrorTitle(errorMsgId)),
-                errorMsgId
-        ));
-        cancelEnrollment();
-        stopIconAnimation();
-    }
-
     @Override
     public void onStop() {
         stopIconAnimation();
-        removeEnrollmentObserver();
-        if (!getActivity().isChangingConfigurations()) {
+        removeEnrollmentObservers();
+        if (!getActivity().isChangingConfigurations() && mProgressViewModel.isEnrolling()) {
             mProgressViewModel.cancelEnrollment();
         }
         super.onStop();
     }
 
-    private void removeEnrollmentObserver() {
-        mProgressViewModel.getProgressLiveData().removeObserver(mProgressObserver);
-        mProgressViewModel.getHelpMessageLiveData().removeObserver(mHelpMessageObserver);
+    private void removeEnrollmentObservers() {
+        preRemoveEnrollmentObservers();
         mProgressViewModel.getErrorMessageLiveData().removeObserver(mErrorMessageObserver);
     }
 
+    private void preRemoveEnrollmentObservers() {
+        mProgressViewModel.getProgressLiveData().removeObserver(mProgressObserver);
+        mProgressViewModel.getHelpMessageLiveData().removeObserver(mHelpMessageObserver);
+    }
+
     private void cancelEnrollment() {
-        removeEnrollmentObserver();
+        preRemoveEnrollmentObservers();
         mProgressViewModel.cancelEnrollment();
     }
 
@@ -318,7 +310,27 @@
     }
 
     private void onEnrollmentError(@NonNull EnrollmentStatusMessage errorMessage) {
-        onCancelEnrollment(errorMessage.getMsgId());
+        stopIconAnimation();
+        removeEnrollmentObservers();
+
+        if (mEnrollingViewModel.getOnBackPressed()
+                && errorMessage.getMsgId() == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
+            mEnrollingViewModel.onCancelledDueToOnBackPressed();
+        } else if (mEnrollingViewModel.getOnSkipPressed()
+                && errorMessage.getMsgId() == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
+            mEnrollingViewModel.onCancelledDueToOnSkipPressed();
+        } else {
+            final int errMsgId = errorMessage.getMsgId();
+            mEnrollingViewModel.showErrorDialog(
+                    new FingerprintEnrollEnrollingViewModel.ErrorDialogData(
+                            mView.getContext().getString(
+                                    FingerprintErrorDialog.getErrorMessage(errMsgId)),
+                            mView.getContext().getString(
+                                    FingerprintErrorDialog.getErrorTitle(errMsgId)),
+                            errMsgId
+                    ));
+            mProgressViewModel.cancelEnrollment();
+        }
     }
 
     private void onEnrollmentProgressChange(@NonNull EnrollmentProgress progress) {
@@ -398,7 +410,6 @@
         }
     }
 
-
     @Override
     public void onDestroy() {
         // TODO stopListenOrientationEvent();
@@ -444,7 +455,6 @@
 
     private void showIconTouchDialog() {
         mIconTouchCount = 0;
-        //TODO EnrollingActivity should observe live data and add dialog fragment
         mEnrollingViewModel.onIconTouchDialogShow();
     }
 
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingSfpsFragment.java b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingSfpsFragment.java
index 57b8665..7d2ef9f 100644
--- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingSfpsFragment.java
+++ b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingSfpsFragment.java
@@ -113,7 +113,7 @@
     private boolean mHaveShownSfpsRightEdgeLottie;
 
     private final View.OnClickListener mOnSkipClickListener =
-            (v) -> mEnrollingViewModel.onSkipButtonClick();
+            (v) -> mEnrollingViewModel.onCancelledDueToOnSkipPressed();
     private final Observer<EnrollmentProgress> mProgressObserver = progress -> {
         // TODO
     };
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingUdfpsFragment.java b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingUdfpsFragment.java
index 18a7c25..ad6abf1 100644
--- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingUdfpsFragment.java
+++ b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingUdfpsFragment.java
@@ -107,7 +107,7 @@
     private boolean mIsAccessibilityEnabled;
 
     private final View.OnClickListener mOnSkipClickListener =
-            (v) -> mEnrollingViewModel.onSkipButtonClick();
+            (v) -> mEnrollingViewModel.onCancelledDueToOnSkipPressed();
     private final Observer<EnrollmentProgress> mProgressObserver = progress -> {
         // TODO
     };
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.java b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.java
index c0b0b4d..7448678 100644
--- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.java
+++ b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.java
@@ -31,6 +31,7 @@
 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_DONE;
 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG;
 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_SKIP;
+import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED;
 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH;
 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT;
 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FingerprintEnrollEnrollingAction;
@@ -453,8 +454,7 @@
     private void onFindSensorAction(@FingerprintEnrollFindSensorAction int action) {
         switch (action) {
             case FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_SKIP: {
-                onSetActivityResult(
-                        new ActivityResult(BiometricEnrollBase.RESULT_SKIP, null));
+                onSetActivityResult(new ActivityResult(BiometricEnrollBase.RESULT_SKIP, null));
                 return;
             }
             case FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_DIALOG: {
@@ -487,6 +487,10 @@
                 onSetActivityResult(new ActivityResult(BiometricEnrollBase.RESULT_TIMEOUT, null));
                 break;
             }
+            case FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED: {
+                getSupportFragmentManager().popBackStack();
+                break;
+            }
         }
     }
 
diff --git a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModel.java b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModel.java
index 08109ca..bf7b0ac 100644
--- a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModel.java
+++ b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModel.java
@@ -71,11 +71,17 @@
      */
     public static final int FINGERPRINT_ENROLL_ENROLLING_ACTION_DISMISS_ICON_TOUCH_DIALOG = 3;
 
+    /**
+     * Has got latest cancelled event due to back key
+     */
+    public static final int FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED = 4;
+
     @IntDef(prefix = { "FINGERPRINT_ENROLL_ENROLLING_ACTION_" }, value = {
             FINGERPRINT_ENROLL_ENROLLING_ACTION_SKIP,
             FINGERPRINT_ENROLL_ENROLLING_ACTION_DONE,
             FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG,
-            FINGERPRINT_ENROLL_ENROLLING_ACTION_DISMISS_ICON_TOUCH_DIALOG
+            FINGERPRINT_ENROLL_ENROLLING_ACTION_DISMISS_ICON_TOUCH_DIALOG,
+            FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface FingerprintEnrollEnrollingAction {}
@@ -103,8 +109,9 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface FingerprintErrorDialogAction {}
 
-
     private final int mUserId;
+    private boolean mOnBackPressed;
+    private boolean mOnSkipPressed;
     private final FingerprintRepository mFingerprintRepository;
     private final AccessibilityRepository mAccessibilityRepository;
     private final VibratorRepository mVibratorRepository;
@@ -162,14 +169,26 @@
         mErrorDialogActionLiveData.postValue(action);
     }
 
+    public boolean getOnSkipPressed() {
+        return mOnSkipPressed;
+    }
+
     /**
      * User clicks skip button
      */
-    public void onSkipButtonClick() {
+    public void setOnSkipPressed() {
+        mOnSkipPressed = true;
+    }
+
+    /**
+     * Enrolling is cacelled because user clicks skip
+     */
+    public void onCancelledDueToOnSkipPressed() {
         final int action = FINGERPRINT_ENROLL_ENROLLING_ACTION_SKIP;
         if (DEBUG) {
             Log.d(TAG, "onSkipButtonClick, post action " + action);
         }
+        mOnSkipPressed = false;
         mActionLiveData.postValue(action);
     }
 
@@ -184,6 +203,29 @@
         mActionLiveData.postValue(action);
     }
 
+    public boolean getOnBackPressed() {
+        return mOnBackPressed;
+    }
+
+    /**
+     * Back key is pressed.
+     */
+    public void setOnBackPressed() {
+        mOnBackPressed = true;
+    }
+
+    /**
+     * Enrollment is cancelled because back key is pressed.
+     */
+    public void onCancelledDueToOnBackPressed() {
+        final int action = FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED;
+        if (DEBUG) {
+            Log.d(TAG, "onCancelledEventReceivedAfterOnBackPressed, post action " + action);
+        }
+        mOnBackPressed = false;
+        mActionLiveData.postValue(action);
+    }
+
     /**
      * Icon touch dialog show
      */
diff --git a/src/com/android/settings/bluetooth/BluetoothBroadcastDialog.java b/src/com/android/settings/bluetooth/BluetoothBroadcastDialog.java
index 62a66cf..b9cc29e 100644
--- a/src/com/android/settings/bluetooth/BluetoothBroadcastDialog.java
+++ b/src/com/android/settings/bluetooth/BluetoothBroadcastDialog.java
@@ -125,8 +125,7 @@
 
     @Override
     public int getMetricsCategory() {
-        //TODO(b/228255796) : add new enum for find broadcast fragment
-        return SettingsEnums.PAGE_UNKNOWN;
+        return SettingsEnums.DIALOG_LE_AUDIO_BROADCAST;
     }
 
     private void launchFindBroadcastsActivity() {
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingFragment.java b/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingFragment.java
index 691acee..ea89053 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingFragment.java
@@ -65,7 +65,10 @@
             return;
         }
 
-        // TODO: mCachedDevice will pass to control in next CLs.
+        use(HearingDeviceRingtoneRoutingPreferenceController.class).init(mCachedDevice);
+        use(HearingDeviceCallRoutingPreferenceController.class).init(mCachedDevice);
+        use(HearingDeviceMediaRoutingPreferenceController.class).init(mCachedDevice);
+        use(HearingDeviceSystemSoundsRoutingPreferenceController.class).init(mCachedDevice);
     }
 
     @Override
diff --git a/src/com/android/settings/bluetooth/BluetoothFindBroadcastsFragment.java b/src/com/android/settings/bluetooth/BluetoothFindBroadcastsFragment.java
index e08a244..a365b42 100644
--- a/src/com/android/settings/bluetooth/BluetoothFindBroadcastsFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothFindBroadcastsFragment.java
@@ -239,8 +239,7 @@
 
     @Override
     public int getMetricsCategory() {
-        //TODO(b/228255796) : add new enum for find broadcast fragment
-        return SettingsEnums.PAGE_UNKNOWN;
+        return SettingsEnums.LE_AUDIO_BROADCAST_FIND_BROADCAST;
     }
 
     /**
diff --git a/src/com/android/settings/bluetooth/BluetoothPairingRequest.java b/src/com/android/settings/bluetooth/BluetoothPairingRequest.java
index ed7a1fc..ed477c8 100644
--- a/src/com/android/settings/bluetooth/BluetoothPairingRequest.java
+++ b/src/com/android/settings/bluetooth/BluetoothPairingRequest.java
@@ -50,10 +50,8 @@
             PowerManager powerManager = context.getSystemService(PowerManager.class);
             int pairingVariant = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
                     BluetoothDevice.ERROR);
-            String deviceAddress = device != null ? device.getAddress() : null;
-            String deviceName = device != null ? device.getName() : null;
             boolean shouldShowDialog = LocalBluetoothPreferences.shouldShowDialogInForeground(
-                    context, deviceAddress, deviceName);
+                    context, device);
 
             // Skips consent pairing dialog if the device was recently associated with CDM
             if (pairingVariant == BluetoothDevice.PAIRING_VARIANT_CONSENT
diff --git a/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java b/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java
index a62bbe1..2212e23 100644
--- a/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java
+++ b/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java
@@ -109,8 +109,6 @@
                                             mRequestType);
             connectionAccessIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
 
-            String deviceAddress = mDevice != null ? mDevice.getAddress() : null;
-            String deviceName = mDevice != null ? mDevice.getName() : null;
             String title = null;
             String message = null;
             PowerManager powerManager =
@@ -118,7 +116,7 @@
 
             if (powerManager.isScreenOn()
                     && LocalBluetoothPreferences.shouldShowDialogInForeground(
-                            context, deviceAddress, deviceName)) {
+                            context, mDevice)) {
                 context.startActivity(connectionAccessIntent);
             } else {
                 // Put up a notification that leads to the dialog
diff --git a/src/com/android/settings/bluetooth/HearingDeviceAudioRoutingBasePreferenceController.java b/src/com/android/settings/bluetooth/HearingDeviceAudioRoutingBasePreferenceController.java
new file mode 100644
index 0000000..84412da
--- /dev/null
+++ b/src/com/android/settings/bluetooth/HearingDeviceAudioRoutingBasePreferenceController.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2023 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.ContentResolver;
+import android.content.Context;
+import android.media.AudioAttributes;
+import android.media.AudioDeviceAttributes;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
+import android.media.audiopolicy.AudioProductStrategy;
+import android.util.Log;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.ListPreference;
+import androidx.preference.Preference;
+
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+
+import com.google.common.primitives.Ints;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Abstract class for providing audio routing {@link ListPreference} common control for hearing
+ * device specifically.
+ */
+public abstract class HearingDeviceAudioRoutingBasePreferenceController extends
+        BasePreferenceController implements Preference.OnPreferenceChangeListener {
+
+    private static final String TAG = "HARoutingBasePreferenceController";
+
+    private static final AudioDeviceAttributes DEVICE_SPEAKER_OUT = new AudioDeviceAttributes(
+            AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, "");
+
+    private final AudioManager mAudioManager;
+
+    public HearingDeviceAudioRoutingBasePreferenceController(Context context,
+            String preferenceKey) {
+        super(context, preferenceKey);
+        mAudioManager = mContext.getSystemService(AudioManager.class);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return AVAILABLE;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+
+        final ListPreference listPreference = (ListPreference) preference;
+        final int routingValue = restoreRoutingValue(mContext);
+        listPreference.setValue(String.valueOf(routingValue));
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        final ListPreference listPreference = (ListPreference) preference;
+        final Integer routingValue = Ints.tryParse((String) newValue);
+        final AudioDeviceAttributes hearingDeviceAttribute = new AudioDeviceAttributes(
+                AudioDeviceAttributes.ROLE_OUTPUT,
+                AudioDeviceInfo.TYPE_HEARING_AID,
+                getHearingDevice().getAddress());
+        final List<AudioProductStrategy> supportedStrategies = getSupportedStrategies(
+                getSupportedAttributeList());
+
+        boolean status = false;
+        if (routingValue != null) {
+            switch (routingValue) {
+                case RoutingValue.AUTO:
+                    status = removePreferredDeviceForStrategies(supportedStrategies);
+                    break;
+                case RoutingValue.HEARING_DEVICE:
+                    removePreferredDeviceForStrategies(supportedStrategies);
+                    status = setPreferredDeviceForStrategies(supportedStrategies,
+                            hearingDeviceAttribute);
+                    break;
+                case RoutingValue.DEVICE_SPEAKER:
+                    removePreferredDeviceForStrategies(supportedStrategies);
+                    status = setPreferredDeviceForStrategies(supportedStrategies,
+                            DEVICE_SPEAKER_OUT);
+                    break;
+                default:
+                    throw new IllegalArgumentException("Unexpected routingValue: " + routingValue);
+            }
+        }
+        if (!status) {
+            Log.w(TAG, "routingMode: " + listPreference.getKey() + "routingValue: " + routingValue
+                    + " fail to configure AudioProductStrategy");
+        }
+
+        saveRoutingValue(mContext, routingValue);
+        updateState(listPreference);
+        return true;
+    }
+
+    /**
+     * Gets a list of usage value defined in {@link AudioAttributes} that is used to configure
+     * audio routing via {@link AudioProductStrategy}.
+     */
+    protected abstract int[] getSupportedAttributeList();
+
+    /**
+     * Gets the {@link CachedBluetoothDevice} hearing device that is used to configure audio
+     * routing.
+     */
+    protected abstract CachedBluetoothDevice getHearingDevice();
+
+    /**
+     * Saves the {@link RoutingValue}.
+     *
+     * @param context the valid context used to get the {@link ContentResolver}
+     * @param routingValue the value defined in {@link RoutingValue}
+     */
+    protected abstract void saveRoutingValue(Context context, int routingValue);
+
+    /**
+     * Restores the {@link RoutingValue} and used to reflect status on ListPreference.
+     *
+     * @param context the valid context used to get the {@link ContentResolver}
+     * @return one of {@link RoutingValue}
+     */
+    protected abstract int restoreRoutingValue(Context context);
+
+    private List<AudioProductStrategy> getSupportedStrategies(int[] attributeSdkUsageList) {
+        final List<AudioAttributes> audioAttrList = new ArrayList<>(attributeSdkUsageList.length);
+        for (int attributeSdkUsage : attributeSdkUsageList) {
+            audioAttrList.add(new AudioAttributes.Builder().setUsage(attributeSdkUsage).build());
+        }
+
+        final List<AudioProductStrategy> allStrategies = getAudioProductStrategies();
+        final List<AudioProductStrategy> supportedStrategies = new ArrayList<>();
+        for (AudioProductStrategy strategy : allStrategies) {
+            for (AudioAttributes audioAttr : audioAttrList) {
+                if (strategy.supportsAudioAttributes(audioAttr)) {
+                    supportedStrategies.add(strategy);
+                }
+            }
+        }
+
+        return supportedStrategies.stream().distinct().collect(Collectors.toList());
+    }
+
+    @VisibleForTesting
+    List<AudioProductStrategy> getAudioProductStrategies() {
+        return AudioManager.getAudioProductStrategies();
+    }
+
+    @VisibleForTesting
+    boolean setPreferredDeviceForStrategies(List<AudioProductStrategy> strategies,
+            AudioDeviceAttributes audioDevice) {
+        boolean status = true;
+        for (AudioProductStrategy strategy : strategies) {
+            status &= mAudioManager.setPreferredDeviceForStrategy(strategy, audioDevice);
+        }
+
+        return status;
+    }
+
+    @VisibleForTesting
+    boolean removePreferredDeviceForStrategies(List<AudioProductStrategy> strategies) {
+        boolean status = true;
+        for (AudioProductStrategy strategy : strategies) {
+            status &= mAudioManager.removePreferredDeviceForStrategy(strategy);
+        }
+
+        return status;
+    }
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            RoutingValue.AUTO,
+            RoutingValue.HEARING_DEVICE,
+            RoutingValue.DEVICE_SPEAKER,
+    })
+
+    @VisibleForTesting
+    protected @interface RoutingValue {
+        int AUTO = 0;
+        int HEARING_DEVICE = 1;
+        int DEVICE_SPEAKER = 2;
+    }
+}
diff --git a/src/com/android/settings/bluetooth/HearingDeviceCallRoutingPreferenceController.java b/src/com/android/settings/bluetooth/HearingDeviceCallRoutingPreferenceController.java
new file mode 100644
index 0000000..8daa738
--- /dev/null
+++ b/src/com/android/settings/bluetooth/HearingDeviceCallRoutingPreferenceController.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2023 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.Context;
+import android.media.AudioAttributes;
+import android.provider.Settings;
+
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+
+/**
+ * The controller of the hearing device call routing list preference.
+ */
+public class HearingDeviceCallRoutingPreferenceController extends
+        HearingDeviceAudioRoutingBasePreferenceController {
+
+    private CachedBluetoothDevice mHearingDevice;
+
+    public HearingDeviceCallRoutingPreferenceController(Context context, String preferenceKey) {
+        super(context, preferenceKey);
+    }
+
+    /**
+     * Initializes objects in this controller. Need to call this before using the controller.
+     *
+     * @param cachedBluetoothDevice the hearing device to configure audio routing
+     */
+    public void init(CachedBluetoothDevice cachedBluetoothDevice) {
+        mHearingDevice = cachedBluetoothDevice;
+    }
+
+    @Override
+    protected int[] getSupportedAttributeList() {
+        return new int[]{
+                AudioAttributes.USAGE_VOICE_COMMUNICATION,
+                AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING};
+    }
+
+    @Override
+    protected CachedBluetoothDevice getHearingDevice() {
+        return mHearingDevice;
+    }
+
+    @Override
+    protected void saveRoutingValue(Context context, int routingValue) {
+        Settings.Secure.putInt(context.getContentResolver(),
+                Settings.Secure.HEARING_AID_CALL_ROUTING, routingValue);
+    }
+
+    @Override
+    protected int restoreRoutingValue(Context context) {
+        return Settings.Secure.getInt(context.getContentResolver(),
+                Settings.Secure.HEARING_AID_CALL_ROUTING, RoutingValue.AUTO);
+    }
+}
diff --git a/src/com/android/settings/bluetooth/HearingDeviceMediaRoutingPreferenceController.java b/src/com/android/settings/bluetooth/HearingDeviceMediaRoutingPreferenceController.java
new file mode 100644
index 0000000..4e61346
--- /dev/null
+++ b/src/com/android/settings/bluetooth/HearingDeviceMediaRoutingPreferenceController.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2023 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.Context;
+import android.media.AudioAttributes;
+import android.provider.Settings;
+
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+
+/**
+ * The controller of the hearing device media routing list preference.
+ */
+public class HearingDeviceMediaRoutingPreferenceController extends
+        HearingDeviceAudioRoutingBasePreferenceController {
+
+    private CachedBluetoothDevice mHearingDevice;
+
+    public HearingDeviceMediaRoutingPreferenceController(Context context, String preferenceKey) {
+        super(context, preferenceKey);
+    }
+
+    /**
+     * Initializes objects in this controller. Need to call this before using the controller.
+     *
+     * @param cachedBluetoothDevice the hearing device to configure audio routing
+     */
+    public void init(CachedBluetoothDevice cachedBluetoothDevice) {
+        mHearingDevice = cachedBluetoothDevice;
+    }
+
+    @Override
+    protected int[] getSupportedAttributeList() {
+        return new int[]{
+                AudioAttributes.USAGE_MEDIA,
+                AudioAttributes.USAGE_GAME};
+    }
+
+    @Override
+    protected CachedBluetoothDevice getHearingDevice() {
+        return mHearingDevice;
+    }
+
+    @Override
+    protected void saveRoutingValue(Context context, int routingValue) {
+        Settings.Secure.putInt(context.getContentResolver(),
+                Settings.Secure.HEARING_AID_MEDIA_ROUTING, routingValue);
+    }
+
+    @Override
+    protected int restoreRoutingValue(Context context) {
+        return Settings.Secure.getInt(context.getContentResolver(),
+                Settings.Secure.HEARING_AID_MEDIA_ROUTING, RoutingValue.AUTO);
+    }
+}
diff --git a/src/com/android/settings/bluetooth/HearingDeviceRingtoneRoutingPreferenceController.java b/src/com/android/settings/bluetooth/HearingDeviceRingtoneRoutingPreferenceController.java
new file mode 100644
index 0000000..325d394
--- /dev/null
+++ b/src/com/android/settings/bluetooth/HearingDeviceRingtoneRoutingPreferenceController.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2023 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.Context;
+import android.media.AudioAttributes;
+import android.provider.Settings;
+
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+
+/**
+ * The controller of the hearing device ringtone routing list preference.
+ */
+public class HearingDeviceRingtoneRoutingPreferenceController extends
+        HearingDeviceAudioRoutingBasePreferenceController {
+
+    private CachedBluetoothDevice mHearingDevice;
+
+    public HearingDeviceRingtoneRoutingPreferenceController(Context context, String preferenceKey) {
+        super(context, preferenceKey);
+    }
+
+    /**
+     * Initializes objects in this controller. Need to call this before using the controller.
+     *
+     * @param cachedBluetoothDevice the hearing device to configure audio routing
+     */
+    public void init(CachedBluetoothDevice cachedBluetoothDevice) {
+        mHearingDevice = cachedBluetoothDevice;
+    }
+
+    @Override
+    protected int[] getSupportedAttributeList() {
+        return new int[] {AudioAttributes.USAGE_NOTIFICATION_RINGTONE};
+    }
+
+    @Override
+    protected CachedBluetoothDevice getHearingDevice() {
+        return mHearingDevice;
+    }
+
+    @Override
+    protected void saveRoutingValue(Context context, int routingValue) {
+        Settings.Secure.putInt(context.getContentResolver(),
+                Settings.Secure.HEARING_AID_RINGTONE_ROUTING, routingValue);
+    }
+
+    @Override
+    protected int restoreRoutingValue(Context context) {
+        return Settings.Secure.getInt(context.getContentResolver(),
+                Settings.Secure.HEARING_AID_RINGTONE_ROUTING, RoutingValue.AUTO);
+    }
+}
diff --git a/src/com/android/settings/bluetooth/HearingDeviceSystemSoundsRoutingPreferenceController.java b/src/com/android/settings/bluetooth/HearingDeviceSystemSoundsRoutingPreferenceController.java
new file mode 100644
index 0000000..19de713
--- /dev/null
+++ b/src/com/android/settings/bluetooth/HearingDeviceSystemSoundsRoutingPreferenceController.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2023 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.Context;
+import android.media.AudioAttributes;
+import android.provider.Settings;
+
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+
+/**
+ * The controller of the hearing device system sounds routing list preference.
+ */
+public class HearingDeviceSystemSoundsRoutingPreferenceController extends
+        HearingDeviceAudioRoutingBasePreferenceController {
+
+    private CachedBluetoothDevice mHearingDevice;
+
+    public HearingDeviceSystemSoundsRoutingPreferenceController(Context context,
+            String preferenceKey) {
+        super(context, preferenceKey);
+    }
+
+    /**
+     * Initializes objects in this controller. Need to call this before using the controller.
+     *
+     * @param cachedBluetoothDevice the hearing device to configure audio routing
+     */
+    public void init(CachedBluetoothDevice cachedBluetoothDevice) {
+        mHearingDevice = cachedBluetoothDevice;
+    }
+
+    @Override
+    protected int[] getSupportedAttributeList() {
+        return new int[]{
+                AudioAttributes.USAGE_ALARM,
+                AudioAttributes.USAGE_NOTIFICATION,
+                AudioAttributes.USAGE_NOTIFICATION_EVENT,
+                AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY,
+                AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+                AudioAttributes.USAGE_ASSISTANCE_SONIFICATION,
+                AudioAttributes.USAGE_ASSISTANT};
+    }
+
+    @Override
+    protected CachedBluetoothDevice getHearingDevice() {
+        return mHearingDevice;
+    }
+
+    @Override
+    protected void saveRoutingValue(Context context, int routingValue) {
+        Settings.Secure.putInt(context.getContentResolver(),
+                Settings.Secure.HEARING_AID_SYSTEM_SOUNDS_ROUTING, routingValue);
+
+    }
+
+    @Override
+    protected int restoreRoutingValue(Context context) {
+        return Settings.Secure.getInt(context.getContentResolver(),
+                Settings.Secure.HEARING_AID_SYSTEM_SOUNDS_ROUTING, RoutingValue.AUTO);
+    }
+}
diff --git a/src/com/android/settings/bluetooth/LocalBluetoothPreferences.java b/src/com/android/settings/bluetooth/LocalBluetoothPreferences.java
index faed1c3..4dcc868 100644
--- a/src/com/android/settings/bluetooth/LocalBluetoothPreferences.java
+++ b/src/com/android/settings/bluetooth/LocalBluetoothPreferences.java
@@ -16,7 +16,10 @@
 
 package com.android.settings.bluetooth;
 
+import android.annotation.Nullable;
+import android.app.ActivityManager;
 import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.content.res.Configuration;
@@ -57,8 +60,9 @@
                 KEY_DISCOVERABLE_END_TIMESTAMP, 0);
     }
 
-    static boolean shouldShowDialogInForeground(Context context,
-            String deviceAddress, String deviceName) {
+    static boolean shouldShowDialogInForeground(Context context, @Nullable BluetoothDevice device) {
+        String deviceAddress = device != null ? device.getAddress() : null;
+        String deviceName = device != null ? device.getName() : null;
         LocalBluetoothManager manager = Utils.getLocalBtManager(context);
         if (manager == null) {
             if (DEBUG) Log.v(TAG, "manager == null - do not show dialog.");
@@ -126,6 +130,20 @@
             }
         }
 
+        if (device != null) {
+            ActivityManager activityManager = context.getSystemService(ActivityManager.class);
+            String packageName = device.getCreateBondCaller();
+
+            if (packageName != null && activityManager.getPackageImportance(packageName)
+                    == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
+                if (DEBUG) {
+                    Log.v(TAG, "showing dialog because the initiating application "
+                            + "is in foreground");
+                }
+                return true;
+            }
+        }
+
         if (DEBUG) Log.v(TAG, "Found no reason to show the dialog - do not show dialog.");
         return false;
     }
diff --git a/src/com/android/settings/dashboard/CategoryManager.java b/src/com/android/settings/dashboard/CategoryManager.java
index b6ec4ca..8ea5cf4 100644
--- a/src/com/android/settings/dashboard/CategoryManager.java
+++ b/src/com/android/settings/dashboard/CategoryManager.java
@@ -26,6 +26,7 @@
 import androidx.annotation.VisibleForTesting;
 
 import com.android.settings.homepage.HighlightableMenu;
+import com.android.settings.safetycenter.SafetyCenterManagerWrapper;
 import com.android.settingslib.applications.InterestingConfigChanges;
 import com.android.settingslib.drawer.CategoryKey;
 import com.android.settingslib.drawer.DashboardCategory;
@@ -38,6 +39,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Objects;
 import java.util.Set;
 
 public class CategoryManager {
@@ -151,6 +153,7 @@
                 mCategoryByKeyMap.put(category.key, category);
             }
             backwardCompatCleanupForCategory(mTileByComponentCache, mCategoryByKeyMap);
+            mergeSecurityPrivacyKeys(context, mTileByComponentCache, mCategoryByKeyMap);
             sortCategories(context, mCategoryByKeyMap);
             filterDuplicateTiles(mCategoryByKeyMap);
             if (firstLoading) {
@@ -225,6 +228,36 @@
     }
 
     /**
+     * Merges {@link CategoryKey#CATEGORY_SECURITY_ADVANCED_SETTINGS} and {@link
+     * CategoryKey#CATEGORY_PRIVACY} into {@link
+     * CategoryKey#CATEGORY_MORE_SECURITY_PRIVACY_SETTINGS}
+     */
+    @VisibleForTesting
+    synchronized void mergeSecurityPrivacyKeys(
+            Context context,
+            Map<Pair<String, String>, Tile> tileByComponentCache,
+            Map<String, DashboardCategory> categoryByKeyMap) {
+        if (!SafetyCenterManagerWrapper.get().isEnabled(context)) {
+            return;
+        }
+        for (Entry<Pair<String, String>, Tile> tileEntry : tileByComponentCache.entrySet()) {
+            Tile tile = tileEntry.getValue();
+            if (Objects.equals(tile.getCategory(), CategoryKey.CATEGORY_SECURITY_ADVANCED_SETTINGS)
+                    || Objects.equals(tile.getCategory(), CategoryKey.CATEGORY_PRIVACY)) {
+                final String newCategoryKey = CategoryKey.CATEGORY_MORE_SECURITY_PRIVACY_SETTINGS;
+                tile.setCategory(newCategoryKey);
+                // move tile to new category.
+                DashboardCategory newCategory = categoryByKeyMap.get(newCategoryKey);
+                if (newCategory == null) {
+                    newCategory = new DashboardCategory(newCategoryKey);
+                    categoryByKeyMap.put(newCategoryKey, newCategory);
+                }
+                newCategory.addTile(tile);
+            }
+        }
+    }
+
+    /**
      * Sort the tiles injected from all apps such that if they have the same priority value,
      * they wil lbe sorted by package name.
      * <p/>
diff --git a/src/com/android/settings/development/BluetoothSnoopLogFilterProfileMapPreferenceController.java b/src/com/android/settings/development/BluetoothSnoopLogFilterProfileMapPreferenceController.java
new file mode 100644
index 0000000..8ace9bb
--- /dev/null
+++ b/src/com/android/settings/development/BluetoothSnoopLogFilterProfileMapPreferenceController.java
@@ -0,0 +1,137 @@
+/*
+ * 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.development;
+
+import android.content.Context;
+import android.sysprop.BluetoothProperties;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.ListPreference;
+import androidx.preference.Preference;
+
+import com.android.settings.R;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+
+import java.util.Locale;
+
+/** Bluetooth Snoop Logger Map Profile Filter Preference Controller */
+public class BluetoothSnoopLogFilterProfileMapPreferenceController
+        extends DeveloperOptionsPreferenceController
+        implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
+
+    private static final String TAG = "BluetoothSnoopLogFilterProfileMapPreferenceController";
+    private static final String PREFERENCE_KEY = "bt_hci_snoop_log_filter_map";
+    @VisibleForTesting static final int BTSNOOP_LOG_PROFILE_FILTER_MODE_DISABLED_INDEX = 0;
+    @VisibleForTesting static final int BTSNOOP_LOG_PROFILE_FILTER_MODE_MAGIC_INDEX = 1;
+    @VisibleForTesting static final int BTSNOOP_LOG_PROFILE_FILTER_MODE_HEADER_INDEX = 2;
+    @VisibleForTesting static final int BTSNOOP_LOG_PROFILE_FILTER_MODE_FULL_FILTER_INDEX = 3;
+
+    private final String[] mListValues;
+    private final String[] mListEntries;
+    private final String mProfilesFilterDisabledEntry;
+
+    @VisibleForTesting
+    static boolean isSnoopLogModeFilteredEnabled() {
+        return (BluetoothProperties.snoop_log_mode()
+                        .orElse(BluetoothProperties.snoop_log_mode_values.DISABLED)
+                == BluetoothProperties.snoop_log_mode_values.FILTERED);
+    }
+
+    public BluetoothSnoopLogFilterProfileMapPreferenceController(Context context) {
+        super(context);
+        mListValues =
+                context.getResources()
+                        .getStringArray(R.array.bt_hci_snoop_log_profile_filter_values);
+        mListEntries =
+                context.getResources()
+                        .getStringArray(R.array.bt_hci_snoop_log_profile_filter_entries);
+        mProfilesFilterDisabledEntry =
+                context.getResources()
+                        .getString(R.string.bt_hci_snoop_log_filtered_mode_disabled_summary);
+    }
+
+    // Default mode is DISABLED.
+    public int getDefaultModeIndex() {
+        return BTSNOOP_LOG_PROFILE_FILTER_MODE_DISABLED_INDEX;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return PREFERENCE_KEY;
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        BluetoothProperties.snoop_log_filter_profile_map(
+                BluetoothProperties.snoop_log_filter_profile_map_values.valueOf(
+                        newValue.toString().toUpperCase(Locale.US)));
+        updateState(mPreference);
+        return true;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+        final ListPreference listPreference = (ListPreference) preference;
+        if (isSnoopLogModeFilteredEnabled()) {
+            mPreference.setEnabled(true);
+
+            BluetoothProperties.snoop_log_filter_profile_map_values currentValue =
+                    BluetoothProperties.snoop_log_filter_profile_map()
+                            .orElse(
+                                    BluetoothProperties.snoop_log_filter_profile_map_values
+                                            .DISABLED);
+
+            int index = getDefaultModeIndex();
+            for (int i = 0; i < mListValues.length; i++) {
+                if (currentValue
+                        == BluetoothProperties.snoop_log_filter_profile_map_values.valueOf(
+                                mListValues[i].toUpperCase(Locale.US))) {
+                    index = i;
+                    break;
+                }
+            }
+            listPreference.setValue(mListValues[index]);
+            listPreference.setSummary(mListEntries[index]);
+        } else {
+            mPreference.setEnabled(false);
+            listPreference.setSummary(mProfilesFilterDisabledEntry);
+        }
+    }
+
+    /** Called when the Bluetooth Snoop Log Mode changes. */
+    public void onSettingChanged() {
+        updateState(mPreference);
+    }
+
+    @Override
+    protected void onDeveloperOptionsSwitchEnabled() {
+        super.onDeveloperOptionsSwitchEnabled();
+        mPreference.setEnabled(isSnoopLogModeFilteredEnabled());
+    }
+
+    @Override
+    protected void onDeveloperOptionsSwitchDisabled() {
+        super.onDeveloperOptionsSwitchDisabled();
+        BluetoothProperties.snoop_log_filter_profile_map(
+                BluetoothProperties.snoop_log_filter_profile_map_values.DISABLED);
+        ((ListPreference) mPreference).setValue(mListValues[getDefaultModeIndex()]);
+        ((ListPreference) mPreference).setSummary(mListEntries[getDefaultModeIndex()]);
+        mPreference.setEnabled(false);
+    }
+}
diff --git a/src/com/android/settings/development/BluetoothSnoopLogFilterProfilePbapPreferenceController.java b/src/com/android/settings/development/BluetoothSnoopLogFilterProfilePbapPreferenceController.java
new file mode 100644
index 0000000..c17291c
--- /dev/null
+++ b/src/com/android/settings/development/BluetoothSnoopLogFilterProfilePbapPreferenceController.java
@@ -0,0 +1,136 @@
+/*
+ * 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.development;
+
+import android.content.Context;
+import android.sysprop.BluetoothProperties;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.ListPreference;
+import androidx.preference.Preference;
+
+import com.android.settings.R;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+
+import java.util.Locale;
+
+/** Bluetooth Snoop Logger Pbap Profile Filter Preference Controller */
+public class BluetoothSnoopLogFilterProfilePbapPreferenceController
+        extends DeveloperOptionsPreferenceController
+        implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
+
+    private static final String TAG = "BluetoothSnoopLogFilterProfilePbapPreferenceController";
+    private static final String PREFERENCE_KEY = "bt_hci_snoop_log_filter_pbap";
+    @VisibleForTesting static final int BTSNOOP_LOG_PROFILE_FILTER_MODE_DISABLED_INDEX = 0;
+    @VisibleForTesting static final int BTSNOOP_LOG_PROFILE_FILTER_MODE_MAGIC_INDEX = 1;
+    @VisibleForTesting static final int BTSNOOP_LOG_PROFILE_FILTER_MODE_HEADER_INDEX = 2;
+    @VisibleForTesting static final int BTSNOOP_LOG_PROFILE_FILTER_MODE_FULL_FILTER_INDEX = 3;
+
+    private final String[] mListValues;
+    private final String[] mListEntries;
+    private final String mProfilesFilterDisabledEntry;
+
+    @VisibleForTesting
+    static boolean isSnoopLogModeFilteredEnabled() {
+        return (BluetoothProperties.snoop_log_mode()
+                        .orElse(BluetoothProperties.snoop_log_mode_values.DISABLED)
+                == BluetoothProperties.snoop_log_mode_values.FILTERED);
+    }
+
+    public BluetoothSnoopLogFilterProfilePbapPreferenceController(Context context) {
+        super(context);
+        mListValues =
+                context.getResources()
+                        .getStringArray(R.array.bt_hci_snoop_log_profile_filter_values);
+        mListEntries =
+                context.getResources()
+                        .getStringArray(R.array.bt_hci_snoop_log_profile_filter_entries);
+        mProfilesFilterDisabledEntry =
+                context.getResources()
+                        .getString(R.string.bt_hci_snoop_log_filtered_mode_disabled_summary);
+    }
+
+    // Default mode is DISABLED.
+    public int getDefaultModeIndex() {
+        return BTSNOOP_LOG_PROFILE_FILTER_MODE_DISABLED_INDEX;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return PREFERENCE_KEY;
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        BluetoothProperties.snoop_log_filter_profile_pbap(
+                BluetoothProperties.snoop_log_filter_profile_pbap_values.valueOf(
+                        newValue.toString().toUpperCase(Locale.US)));
+        updateState(mPreference);
+        return true;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+        final ListPreference listPreference = (ListPreference) preference;
+        if (isSnoopLogModeFilteredEnabled()) {
+            mPreference.setEnabled(true);
+            BluetoothProperties.snoop_log_filter_profile_pbap_values currentValue =
+                    BluetoothProperties.snoop_log_filter_profile_pbap()
+                            .orElse(
+                                    BluetoothProperties.snoop_log_filter_profile_pbap_values
+                                            .DISABLED);
+
+            int index = getDefaultModeIndex();
+            for (int i = 0; i < mListValues.length; i++) {
+                if (currentValue
+                        == BluetoothProperties.snoop_log_filter_profile_pbap_values.valueOf(
+                                mListValues[i].toUpperCase(Locale.US))) {
+                    index = i;
+                    break;
+                }
+            }
+            listPreference.setValue(mListValues[index]);
+            listPreference.setSummary(mListEntries[index]);
+        } else {
+            mPreference.setEnabled(false);
+            listPreference.setSummary(mProfilesFilterDisabledEntry);
+        }
+    }
+
+    /** Called when the Bluetooth Snoop Log Mode changes. */
+    public void onSettingChanged() {
+        updateState(mPreference);
+    }
+
+    @Override
+    protected void onDeveloperOptionsSwitchEnabled() {
+        super.onDeveloperOptionsSwitchEnabled();
+        mPreference.setEnabled(isSnoopLogModeFilteredEnabled());
+    }
+
+    @Override
+    protected void onDeveloperOptionsSwitchDisabled() {
+        super.onDeveloperOptionsSwitchDisabled();
+        BluetoothProperties.snoop_log_filter_profile_pbap(
+                BluetoothProperties.snoop_log_filter_profile_pbap_values.DISABLED);
+        ((ListPreference) mPreference).setValue(mListValues[getDefaultModeIndex()]);
+        ((ListPreference) mPreference).setSummary(mListEntries[getDefaultModeIndex()]);
+        mPreference.setEnabled(false);
+    }
+}
diff --git a/src/com/android/settings/development/BluetoothSnoopLogHost.java b/src/com/android/settings/development/BluetoothSnoopLogHost.java
new file mode 100644
index 0000000..1e53e73
--- /dev/null
+++ b/src/com/android/settings/development/BluetoothSnoopLogHost.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2023 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.development;
+
+/**
+ * Interface for BluetoothSnoopLogPreferenceController callbacks.
+ */
+public interface BluetoothSnoopLogHost {
+
+    /**
+     * Called when the Bluetooth Snoop Log Mode changes.
+     */
+    void onSettingChanged();
+}
diff --git a/src/com/android/settings/development/BluetoothSnoopLogPreferenceController.java b/src/com/android/settings/development/BluetoothSnoopLogPreferenceController.java
index d698436..31ed652 100644
--- a/src/com/android/settings/development/BluetoothSnoopLogPreferenceController.java
+++ b/src/com/android/settings/development/BluetoothSnoopLogPreferenceController.java
@@ -22,12 +22,9 @@
 import android.provider.Settings;
 import android.text.TextUtils;
 
-import android.util.Log;
-
 import androidx.annotation.VisibleForTesting;
 import androidx.preference.ListPreference;
 import androidx.preference.Preference;
-import androidx.preference.SwitchPreference;
 
 import com.android.settings.R;
 import com.android.settings.core.PreferenceControllerMixin;
@@ -37,22 +34,23 @@
         implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
 
     private static final String PREFERENCE_KEY = "bt_hci_snoop_log";
-    @VisibleForTesting
-    static final int BTSNOOP_LOG_MODE_DISABLED_INDEX = 0;
-    @VisibleForTesting
-    static final int BTSNOOP_LOG_MODE_FILTERED_INDEX = 1;
-    @VisibleForTesting
-    static final int BTSNOOP_LOG_MODE_FULL_INDEX = 2;
+    @VisibleForTesting static final int BTSNOOP_LOG_MODE_DISABLED_INDEX = 0;
+    @VisibleForTesting static final int BTSNOOP_LOG_MODE_FILTERED_INDEX = 1;
+    @VisibleForTesting static final int BTSNOOP_LOG_MODE_FULL_INDEX = 2;
+
     @VisibleForTesting
     static final String BLUETOOTH_BTSNOOP_LOG_MODE_PROPERTY = "persist.bluetooth.btsnooplogmode";
 
     private final String[] mListValues;
     private final String[] mListEntries;
+    private DevelopmentSettingsDashboardFragment mFragment;
 
-    public BluetoothSnoopLogPreferenceController(Context context) {
+    public BluetoothSnoopLogPreferenceController(
+            Context context, DevelopmentSettingsDashboardFragment fragment) {
         super(context);
         mListValues = context.getResources().getStringArray(R.array.bt_hci_snoop_log_values);
         mListEntries = context.getResources().getStringArray(R.array.bt_hci_snoop_log_entries);
+        mFragment = fragment;
     }
 
     // Default mode is DISABLED. It can also be changed by modifying the global setting.
@@ -61,8 +59,10 @@
             return BTSNOOP_LOG_MODE_DISABLED_INDEX;
         }
 
-        final String default_mode = Settings.Global.getString(mContext.getContentResolver(),
-                Settings.Global.BLUETOOTH_BTSNOOP_DEFAULT_MODE);
+        final String default_mode =
+                Settings.Global.getString(
+                        mContext.getContentResolver(),
+                        Settings.Global.BLUETOOTH_BTSNOOP_DEFAULT_MODE);
 
         for (int i = 0; i < mListValues.length; i++) {
             if (TextUtils.equals(default_mode, mListValues[i])) {
@@ -82,6 +82,9 @@
     public boolean onPreferenceChange(Preference preference, Object newValue) {
         SystemProperties.set(BLUETOOTH_BTSNOOP_LOG_MODE_PROPERTY, newValue.toString());
         updateState(mPreference);
+        if (mFragment != null) {
+            mFragment.onSettingChanged();
+        }
         return true;
     }
 
diff --git a/src/com/android/settings/development/DevelopmentMemtagFooterPreferenceController.java b/src/com/android/settings/development/DevelopmentMemtagFooterPreferenceController.java
new file mode 100644
index 0000000..a5612ca
--- /dev/null
+++ b/src/com/android/settings/development/DevelopmentMemtagFooterPreferenceController.java
@@ -0,0 +1,56 @@
+/*
+ * 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.security;
+
+import android.content.Context;
+import android.text.TextUtils;
+
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.HelpUtils;
+import com.android.settingslib.widget.FooterPreference;
+
+/** Footer for face settings showing the help text and help link. */
+public class DevelopmentMemtagFooterPreferenceController extends BasePreferenceController {
+
+    public DevelopmentMemtagFooterPreferenceController(Context context, String preferenceKey) {
+        super(context, preferenceKey);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return AVAILABLE_UNSEARCHABLE;
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        // Set up learn more link.
+        FooterPreference prefFooter = screen.findPreference(getPreferenceKey());
+        String helpUrl = mContext.getString(R.string.help_url_development_memtag);
+        if (prefFooter != null && !TextUtils.isEmpty(helpUrl)) {
+            prefFooter.setLearnMoreAction(
+                    v ->
+                            mContext.startActivity(
+                                    HelpUtils.getHelpIntent(
+                                            mContext, helpUrl, /* backupContext= */ "")));
+            prefFooter.setLearnMoreText(mContext.getString(R.string.development_memtag_learn_more));
+        }
+    }
+}
diff --git a/src/com/android/settings/development/DevelopmentMemtagPage.java b/src/com/android/settings/development/DevelopmentMemtagPage.java
new file mode 100644
index 0000000..df983f3
--- /dev/null
+++ b/src/com/android/settings/development/DevelopmentMemtagPage.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2023 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.development;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settingslib.search.SearchIndexable;
+
+@SearchIndexable
+public class DevelopmentMemtagPage extends DashboardFragment {
+    private static final String TAG = "DevelopmentMemtagPage";
+
+    @Override
+    public int getMetricsCategory() {
+        return SettingsEnums.SETTINGS_DEVELOPMENT_MEMTAG_CATEGORY;
+    }
+
+    @Override
+    protected String getLogTag() {
+        return TAG;
+    }
+
+    @Override
+    public void onAttach(Context context) {
+        super.onAttach(context);
+
+        use(RebootWithMtePreferenceController.class).setFragment(this);
+        use(DevelopmentMemtagPreferenceController.class).setFragment(this);
+    }
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.development_memtag_page;
+    }
+
+    public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+            new BaseSearchIndexProvider(R.xml.development_memtag_page);
+}
diff --git a/src/com/android/settings/development/DevelopmentMemtagPagePreferenceController.java b/src/com/android/settings/development/DevelopmentMemtagPagePreferenceController.java
new file mode 100644
index 0000000..240079b
--- /dev/null
+++ b/src/com/android/settings/development/DevelopmentMemtagPagePreferenceController.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2023 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.development;
+
+import android.content.Context;
+
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.security.MemtagHelper;
+import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+
+public class DevelopmentMemtagPagePreferenceController extends DeveloperOptionsPreferenceController
+        implements PreferenceControllerMixin {
+    private static final String KEY_DEVELOPMENT_MEMTAG_PAGE = "development_memtag_page";
+
+    public DevelopmentMemtagPagePreferenceController(
+            Context context, DevelopmentSettingsDashboardFragment fragment) {
+        super(context);
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return android.os.SystemProperties.getBoolean("ro.arm64.memtag.bootctl_supported", false);
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_DEVELOPMENT_MEMTAG_PAGE;
+    }
+
+    @Override
+    protected void onDeveloperOptionsSwitchDisabled() {
+        super.onDeveloperOptionsSwitchDisabled();
+        MemtagHelper.setChecked(false);
+    }
+}
diff --git a/src/com/android/settings/development/DevelopmentMemtagPreferenceController.java b/src/com/android/settings/development/DevelopmentMemtagPreferenceController.java
new file mode 100644
index 0000000..751ccba
--- /dev/null
+++ b/src/com/android/settings/development/DevelopmentMemtagPreferenceController.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2023 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.development;
+
+import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+
+import android.content.Context;
+import android.os.SystemProperties;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.TogglePreferenceController;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.security.MemtagHelper;
+import com.android.settings.security.MemtagRebootDialog;
+import com.android.settingslib.RestrictedLockUtilsInternal;
+import com.android.settingslib.RestrictedSwitchPreference;
+import com.android.settingslib.development.DevelopmentSettingsEnabler;
+
+public class DevelopmentMemtagPreferenceController extends TogglePreferenceController {
+    private Preference mPreference;
+    private DashboardFragment mFragment;
+
+    public DevelopmentMemtagPreferenceController(Context context, String key) {
+        super(context, key);
+    }
+
+    public void setFragment(DashboardFragment fragment) {
+        mFragment = fragment;
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext)
+                        && SystemProperties.getBoolean("ro.arm64.memtag.bootctl_supported", false)
+                ? BasePreferenceController.AVAILABLE
+                : BasePreferenceController.UNSUPPORTED_ON_DEVICE;
+    }
+
+    @Override
+    public boolean isChecked() {
+        return MemtagHelper.isChecked();
+    }
+
+    @Override
+    public boolean setChecked(boolean isChecked) {
+        MemtagHelper.setChecked(isChecked);
+        if (mPreference != null) {
+            refreshSummary(mPreference);
+        }
+        if (isChecked != MemtagHelper.isOn()) {
+            int msg =
+                    isChecked
+                            ? R.string.development_memtag_reboot_message_on
+                            : R.string.development_memtag_reboot_message_off;
+            MemtagRebootDialog.show(mContext, mFragment, msg);
+        }
+        mFragment.forceUpdatePreferences();
+        return true;
+    }
+
+    @Override
+    public int getSliceHighlightMenuRes() {
+        return R.string.menu_key_system;
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        mPreference = screen.findPreference(getPreferenceKey());
+        refreshSummary(mPreference);
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+        EnforcedAdmin admin = RestrictedLockUtilsInternal.checkIfMteIsDisabled(mContext);
+        if (admin != null) {
+            // Make sure this is disabled even if the user directly goes to this
+            // page via the android.settings.ADVANCED_MEMORY_PROTECTION_SETTINGS intent.
+            ((RestrictedSwitchPreference) preference).setDisabledByAdmin(admin);
+        }
+        refreshSummary(preference);
+    }
+
+    @Override
+    public CharSequence getSummary() {
+        return mContext.getResources().getString(MemtagHelper.getSummary());
+    }
+}
diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
index 8ff2336..c732c0a 100644
--- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
+++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
@@ -83,7 +83,7 @@
         AdbClearKeysDialogHost, LogPersistDialogHost,
         BluetoothRebootDialog.OnRebootDialogListener,
         AbstractBluetoothPreferenceController.Callback,
-        NfcRebootDialog.OnNfcRebootDialogConfirmedListener {
+        NfcRebootDialog.OnNfcRebootDialogConfirmedListener, BluetoothSnoopLogHost {
 
     private static final String TAG = "DevSettingsDashboard";
 
@@ -431,6 +431,18 @@
     }
 
     @Override
+    public void onSettingChanged() {
+        final BluetoothSnoopLogFilterProfileMapPreferenceController controllerMap =
+                getDevelopmentOptionsController(
+                        BluetoothSnoopLogFilterProfileMapPreferenceController.class);
+        final BluetoothSnoopLogFilterProfilePbapPreferenceController controllerPbap =
+                getDevelopmentOptionsController(
+                        BluetoothSnoopLogFilterProfilePbapPreferenceController.class);
+        controllerMap.onSettingChanged();
+        controllerPbap.onSettingChanged();
+    }
+
+    @Override
     public void onActivityResult(int requestCode, int resultCode, Intent data) {
         boolean handledResult = false;
         for (AbstractPreferenceController controller : mPreferenceControllers) {
@@ -544,11 +556,15 @@
         controllers.add(new BugReportPreferenceController(context));
         controllers.add(new BugReportHandlerPreferenceController(context));
         controllers.add(new SystemServerHeapDumpPreferenceController(context));
-        controllers.add(new RebootWithMtePreferenceController(context, fragment));
+        controllers.add(new DevelopmentMemtagPagePreferenceController(context, fragment));
         controllers.add(new LocalBackupPasswordPreferenceController(context));
         controllers.add(new StayAwakePreferenceController(context, lifecycle));
         controllers.add(new HdcpCheckingPreferenceController(context));
-        controllers.add(new BluetoothSnoopLogPreferenceController(context));
+        controllers.add(new BluetoothSnoopLogPreferenceController(context, fragment));
+        controllers.add(new DefaultLaunchPreferenceController(context,
+                "snoop_logger_filters_dashboard"));
+        controllers.add(new BluetoothSnoopLogFilterProfilePbapPreferenceController(context));
+        controllers.add(new BluetoothSnoopLogFilterProfileMapPreferenceController(context));
         controllers.add(new OemUnlockPreferenceController(context, activity, fragment));
         controllers.add(new PictureColorModePreferenceController(context, lifecycle));
         controllers.add(new WebViewAppPreferenceController(context));
diff --git a/src/com/android/settings/development/RebootWithMtePreferenceController.java b/src/com/android/settings/development/RebootWithMtePreferenceController.java
index f7bd726..76ad2ce 100644
--- a/src/com/android/settings/development/RebootWithMtePreferenceController.java
+++ b/src/com/android/settings/development/RebootWithMtePreferenceController.java
@@ -17,32 +17,35 @@
 package com.android.settings.development;
 
 import android.content.Context;
+import android.os.SystemProperties;
 import android.text.TextUtils;
 
+import androidx.fragment.app.Fragment;
 import androidx.preference.Preference;
 
 import com.android.settings.R;
 import com.android.settings.Utils;
+import com.android.settings.core.BasePreferenceController;
 import com.android.settings.core.PreferenceControllerMixin;
 import com.android.settings.security.MemtagHelper;
-import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+import com.android.settingslib.development.DevelopmentSettingsEnabler;
 
-public class RebootWithMtePreferenceController extends DeveloperOptionsPreferenceController
+public class RebootWithMtePreferenceController extends BasePreferenceController
         implements PreferenceControllerMixin {
-
     private static final String KEY_REBOOT_WITH_MTE = "reboot_with_mte";
 
-    private final DevelopmentSettingsDashboardFragment mFragment;
+    private Fragment mFragment;
 
-    public RebootWithMtePreferenceController(
-            Context context, DevelopmentSettingsDashboardFragment fragment) {
-        super(context);
-        mFragment = fragment;
+    public RebootWithMtePreferenceController(Context context) {
+        super(context, KEY_REBOOT_WITH_MTE);
     }
 
     @Override
-    public boolean isAvailable() {
-        return android.os.SystemProperties.getBoolean("ro.arm64.memtag.bootctl_supported", false);
+    public int getAvailabilityStatus() {
+        return DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext)
+                        && SystemProperties.getBoolean("ro.arm64.memtag.bootctl_supported", false)
+                ? BasePreferenceController.AVAILABLE
+                : BasePreferenceController.UNSUPPORTED_ON_DEVICE;
     }
 
     @Override
@@ -64,6 +67,10 @@
         return KEY_REBOOT_WITH_MTE;
     }
 
+    public void setFragment(Fragment fragment) {
+        mFragment = fragment;
+    }
+
     @Override
     public boolean handlePreferenceTreeClick(Preference preference) {
         if (Utils.isMonkeyRunning()) {
diff --git a/src/com/android/settings/development/snooplogger/SnoopLoggerFiltersDashboard.java b/src/com/android/settings/development/snooplogger/SnoopLoggerFiltersDashboard.java
new file mode 100644
index 0000000..6f1ede2
--- /dev/null
+++ b/src/com/android/settings/development/snooplogger/SnoopLoggerFiltersDashboard.java
@@ -0,0 +1,79 @@
+/*
+ * 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.development.snooplogger;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.provider.SearchIndexableResource;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settingslib.development.DevelopmentSettingsEnabler;
+import com.android.settingslib.search.SearchIndexable;
+
+import java.util.List;
+
+/**
+ * Bluetooth Snoop Logger Filters Dashboard
+ */
+@SearchIndexable
+public class SnoopLoggerFiltersDashboard extends DashboardFragment {
+
+    private static final String TAG = "SnoopLoggerFiltersDashboard";
+
+    @Override
+    public int getMetricsCategory() {
+        return SettingsEnums.SETTINGS_SNOOP_LOGGER_DASHBOARD;
+    }
+
+    @Override
+    protected String getLogTag() {
+        return TAG;
+    }
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.snoop_logger_filters_settings;
+    }
+
+    @Override
+    public void onAttach(Context context) {
+        super.onAttach(context);
+    }
+
+    @Override
+    public int getHelpResource() {
+        return 0;
+    }
+
+    public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+            new BaseSearchIndexProvider() {
+                @Override
+                public List<SearchIndexableResource> getXmlResourcesToIndex(
+                        Context context, boolean enabled) {
+                    final SearchIndexableResource sir = new SearchIndexableResource(context);
+                    sir.xmlResId = R.xml.snoop_logger_filters_settings;
+                    return List.of(sir);
+                }
+
+                @Override
+                protected boolean isPageSearchEnabled(Context context) {
+                    return DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(context);
+                }
+            };
+}
diff --git a/src/com/android/settings/development/snooplogger/SnoopLoggerFiltersPreference.java b/src/com/android/settings/development/snooplogger/SnoopLoggerFiltersPreference.java
new file mode 100644
index 0000000..f0c9ff4
--- /dev/null
+++ b/src/com/android/settings/development/snooplogger/SnoopLoggerFiltersPreference.java
@@ -0,0 +1,53 @@
+/*
+ * 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.development.snooplogger;
+
+import android.content.Context;
+import android.os.SystemProperties;
+
+import androidx.preference.SwitchPreference;
+
+/**
+ * Bluetooth Snoop Logger Filters Preference
+ */
+public class SnoopLoggerFiltersPreference extends SwitchPreference {
+
+    private final String mKey;
+    private static final String TAG = "SnoopLoggerFiltersPreference";
+    private static final String SNOOP_LOG_FILTERS_PREFIX = "persist.bluetooth.snooplogfilter.";
+    private static final String SNOOP_LOG_FILTERS_SUFFIX = ".enabled";
+
+    public SnoopLoggerFiltersPreference(Context context, String key, String entry) {
+        super(context);
+        mKey = key;
+        setKey(key);
+        setTitle(entry);
+
+        String filterProp = SNOOP_LOG_FILTERS_PREFIX.concat(mKey).concat(SNOOP_LOG_FILTERS_SUFFIX);
+
+        boolean isFilterEnabled = SystemProperties.get(filterProp).equals("true");
+
+        super.setChecked(isFilterEnabled);
+    }
+
+    @Override
+    public void setChecked(boolean isChecked) {
+        super.setChecked(isChecked);
+        String filterProp = SNOOP_LOG_FILTERS_PREFIX.concat(mKey).concat(SNOOP_LOG_FILTERS_SUFFIX);
+        SystemProperties.set(filterProp, isChecked ? "true" : "false");
+    }
+}
diff --git a/src/com/android/settings/development/snooplogger/SnoopLoggerFiltersPreferenceController.java b/src/com/android/settings/development/snooplogger/SnoopLoggerFiltersPreferenceController.java
new file mode 100644
index 0000000..8262182
--- /dev/null
+++ b/src/com/android/settings/development/snooplogger/SnoopLoggerFiltersPreferenceController.java
@@ -0,0 +1,65 @@
+/*
+ * 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.development.snooplogger;
+
+import android.content.Context;
+import android.sysprop.BluetoothProperties;
+
+import androidx.preference.PreferenceGroup;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+
+/** A {@link BasePreferenceController} used in {@link SnoopLoggerFiltersDashboard} */
+public class SnoopLoggerFiltersPreferenceController extends BasePreferenceController {
+    private static final String TAG = "SnoopLoggerFiltersPreferenceController";
+
+    private final String[] mListValues;
+    private final String[] mListEntries;
+
+    public SnoopLoggerFiltersPreferenceController(Context context, String key) {
+        super(context, key);
+        mListValues =
+                context.getResources().getStringArray(R.array.bt_hci_snoop_log_filters_values);
+        mListEntries =
+                context.getResources().getStringArray(R.array.bt_hci_snoop_log_filters_entries);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        BluetoothProperties.snoop_log_mode_values snoopLogMode =
+                BluetoothProperties.snoop_log_mode()
+                        .orElse(BluetoothProperties.snoop_log_mode_values.DISABLED);
+        if (snoopLogMode == BluetoothProperties.snoop_log_mode_values.FILTERED) {
+            return AVAILABLE;
+        }
+        return DISABLED_DEPENDENT_SETTING;
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        PreferenceGroup mGroup = screen.findPreference(getPreferenceKey());
+        mGroup.removeAll();
+        final Context prefContext = mGroup.getContext();
+        for (int i = 0; i < mListValues.length; i++) {
+            mGroup.addPreference(
+                    new SnoopLoggerFiltersPreference(prefContext, mListValues[i], mListEntries[i]));
+        }
+    }
+}
diff --git a/src/com/android/settings/deviceinfo/PhoneNumberPreferenceController.java b/src/com/android/settings/deviceinfo/PhoneNumberPreferenceController.java
index f91b98f..d1bf808 100644
--- a/src/com/android/settings/deviceinfo/PhoneNumberPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/PhoneNumberPreferenceController.java
@@ -30,7 +30,6 @@
 import com.android.settings.R;
 import com.android.settings.core.BasePreferenceController;
 import com.android.settings.network.SubscriptionUtil;
-import com.android.settingslib.DeviceInfoUtils;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -157,7 +156,7 @@
 
     @VisibleForTesting
     protected CharSequence getFormattedPhoneNumber(SubscriptionInfo subscriptionInfo) {
-        final String phoneNumber = DeviceInfoUtils.getBidiFormattedPhoneNumber(mContext,
+        final String phoneNumber = SubscriptionUtil.getBidiFormattedPhoneNumber(mContext,
                 subscriptionInfo);
         return TextUtils.isEmpty(phoneNumber) ? mContext.getString(R.string.device_info_default)
                 : phoneNumber;
diff --git a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java
index e6f7a0e..d3058ce 100644
--- a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java
+++ b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java
@@ -59,7 +59,7 @@
 import androidx.lifecycle.OnLifecycleEvent;
 
 import com.android.settings.R;
-import com.android.settingslib.DeviceInfoUtils;
+import com.android.settings.network.SubscriptionUtil;
 import com.android.settingslib.Utils;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 
@@ -329,7 +329,7 @@
     public void updatePhoneNumber() {
         // If formattedNumber is null or empty, it'll display as "Unknown".
         mDialog.setText(PHONE_NUMBER_VALUE_ID,
-                DeviceInfoUtils.getBidiFormattedPhoneNumber(mContext, mSubscriptionInfo));
+                SubscriptionUtil.getBidiFormattedPhoneNumber(mContext, mSubscriptionInfo));
     }
 
     private void updateDataState(int state) {
diff --git a/src/com/android/settings/emergency/EmergencyGestureSettings.java b/src/com/android/settings/emergency/EmergencyGestureSettings.java
index 7826872..3803ce1 100644
--- a/src/com/android/settings/emergency/EmergencyGestureSettings.java
+++ b/src/com/android/settings/emergency/EmergencyGestureSettings.java
@@ -54,8 +54,8 @@
                     final EmergencyGestureEntrypointPreferenceController controller =
                             new EmergencyGestureEntrypointPreferenceController(context,
                                     "dummy_emergency_gesture_pref_key");
-                    return !controller.isAvailable()
-                            || controller.shouldSuppressFromSearch();
+                    return controller.isAvailable()
+                            && !controller.shouldSuppressFromSearch();
                 }
             };
 }
diff --git a/src/com/android/settings/nearby/FastPairPreferenceController.java b/src/com/android/settings/nearby/FastPairPreferenceController.java
deleted file mode 100644
index a115202..0000000
--- a/src/com/android/settings/nearby/FastPairPreferenceController.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.nearby;
-
-import android.content.Context;
-
-import androidx.lifecycle.LifecycleObserver;
-
-import com.android.settings.core.BasePreferenceController;
-
-/**
- * {@link BasePreferenceController} for Fast Pair settings.
- */
-public class FastPairPreferenceController extends BasePreferenceController implements
-        LifecycleObserver {
-    public static final String TAG = "FastPairPrefController";
-    public static final String KEY_FAST_PAIR_SETTINGS = "connected_device_fast_pair";
-
-    public FastPairPreferenceController(Context context) {
-        super(context, KEY_FAST_PAIR_SETTINGS);
-    }
-
-    @Override
-    public int getAvailabilityStatus() {
-        return AVAILABLE;
-    }
-}
diff --git a/src/com/android/settings/nearby/FastPairSettingsFragment.java b/src/com/android/settings/nearby/FastPairSettingsFragment.java
deleted file mode 100644
index 2fff7a0..0000000
--- a/src/com/android/settings/nearby/FastPairSettingsFragment.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * 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.nearby;
-
-import android.app.settings.SettingsEnums;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.nearby.NearbyManager;
-import android.os.Bundle;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.Log;
-
-import androidx.annotation.Nullable;
-import androidx.preference.Preference;
-
-import com.android.settings.R;
-import com.android.settings.SettingsPreferenceFragment;
-import com.android.settings.search.BaseSearchIndexProvider;
-import com.android.settingslib.search.SearchIndexable;
-import com.android.settingslib.widget.MainSwitchPreference;
-import com.android.settingslib.widget.OnMainSwitchChangeListener;
-
-import java.util.Objects;
-
-/**
- * Fragment with the top level fast pair settings.
- */
-@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
-public class FastPairSettingsFragment extends SettingsPreferenceFragment {
-
-    private static final String TAG = "FastPairSettingsFrag";
-
-    private static final String SCAN_SWITCH_KEY = "fast_pair_scan_switch";
-    private static final String SAVED_DEVICES_PREF_KEY = "saved_devices";
-
-    private MainSwitchPreference mMainSwitchPreference;
-    private OnMainSwitchChangeListener mMainSwitchChangeListener;
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        mMainSwitchPreference = Objects.requireNonNull(
-                findPreference(SCAN_SWITCH_KEY));
-        mMainSwitchChangeListener = (switchView, isChecked) ->
-                NearbyManager.setFastPairScanEnabled(getContext(), isChecked);
-        Preference savedDevicePref = Objects.requireNonNull(
-                findPreference(SAVED_DEVICES_PREF_KEY));
-        savedDevicePref.setOnPreferenceClickListener(preference -> {
-            Intent savedDevicesIntent = getSavedDevicesIntent();
-            if (savedDevicesIntent != null && getActivity() != null) {
-                getActivity().startActivity(savedDevicesIntent);
-            }
-            return true;
-        });
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-        mMainSwitchPreference.addOnSwitchChangeListener(mMainSwitchChangeListener);
-        mMainSwitchPreference.setChecked(NearbyManager.isFastPairScanEnabled(getContext()));
-    }
-
-    @Override
-    public void onPause() {
-        super.onPause();
-        mMainSwitchPreference.removeOnSwitchChangeListener(mMainSwitchChangeListener);
-    }
-
-    @Override
-    public int getMetricsCategory() {
-        return SettingsEnums.CONNECTION_DEVICE_ADVANCED_FAST_PAIR;
-    }
-
-    @Override
-    public int getHelpResource() {
-        return 0;
-    }
-
-    @Override
-    protected int getPreferenceScreenResId() {
-        return R.xml.fast_pair_settings;
-    }
-
-    public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
-            new BaseSearchIndexProvider(R.xml.fast_pair_settings);
-
-    @Nullable
-    private ComponentName getSavedDevicesComponent() {
-        String savedDevicesComponent = Settings.Secure.getString(
-                getContentResolver(),
-                Settings.Secure.NEARBY_FAST_PAIR_SETTINGS_DEVICES_COMPONENT);
-        if (TextUtils.isEmpty(savedDevicesComponent)) {
-            savedDevicesComponent = getString(
-                com.android.internal.R.string.config_defaultNearbyFastPairSettingsDevicesComponent);
-        }
-
-        if (TextUtils.isEmpty(savedDevicesComponent)) {
-            return null;
-        }
-
-        return ComponentName.unflattenFromString(savedDevicesComponent);
-    }
-
-    @Nullable
-    private Intent getSavedDevicesIntent() {
-        ComponentName componentName = getSavedDevicesComponent();
-        if (componentName == null) {
-            return null;
-        }
-
-        PackageManager pm = getPackageManager();
-        Intent intent = getIntent();
-        intent.setAction(Intent.ACTION_VIEW);
-        intent.setComponent(componentName);
-
-        final ResolveInfo resolveInfo = pm.resolveActivity(intent, PackageManager.GET_META_DATA);
-        if (resolveInfo == null || resolveInfo.activityInfo == null) {
-            Log.e(TAG, "Device-specified fast pair component (" + componentName
-                    + ") not available");
-            return null;
-        }
-        return intent;
-    }
-}
diff --git a/src/com/android/settings/network/ActiveSubscriptionsListener.java b/src/com/android/settings/network/ActiveSubscriptionsListener.java
index b23b723..dce441b 100644
--- a/src/com/android/settings/network/ActiveSubscriptionsListener.java
+++ b/src/com/android/settings/network/ActiveSubscriptionsListener.java
@@ -16,6 +16,7 @@
 
 package com.android.settings.network;
 
+import android.annotation.NonNull;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -278,6 +279,15 @@
     }
 
     /**
+     * Gets a list of active, visible subscription Id(s) of the currently active SIM(s).
+     *
+     * @return the list of subId's that are active and visible; the length may be 0.
+     */
+    public @NonNull int[] getActiveSubscriptionIdList() {
+        return getSubscriptionManager().getActiveSubscriptionIdList();
+    }
+
+    /**
      * Clear data cached within listener
      */
     public void clearCache() {
diff --git a/src/com/android/settings/network/EraseEuiccDataController.java b/src/com/android/settings/network/EraseEuiccDataController.java
index 091b6d7..3dc3ab5 100644
--- a/src/com/android/settings/network/EraseEuiccDataController.java
+++ b/src/com/android/settings/network/EraseEuiccDataController.java
@@ -24,6 +24,7 @@
 
 import com.android.settings.core.BasePreferenceController;
 import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.network.telephony.MobileNetworkUtils;
 import com.android.settings.system.ResetDashboardFragment;
 
 /**
@@ -52,6 +53,7 @@
     @Override
     public int getAvailabilityStatus() {
         return SubscriptionUtil.isSimHardwareVisible(mContext) &&
+                (!MobileNetworkUtils.isMobileNetworkUserRestricted(mContext)) &&
                 mContext.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_TELEPHONY_EUICC) ? AVAILABLE_UNSEARCHABLE
                 : UNSUPPORTED_ON_DEVICE;
diff --git a/src/com/android/settings/network/ProxySubscriptionManager.java b/src/com/android/settings/network/ProxySubscriptionManager.java
index 614491a..51fafb1 100644
--- a/src/com/android/settings/network/ProxySubscriptionManager.java
+++ b/src/com/android/settings/network/ProxySubscriptionManager.java
@@ -20,6 +20,7 @@
 import static androidx.lifecycle.Lifecycle.Event.ON_START;
 import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
 
+import android.annotation.NonNull;
 import android.content.Context;
 import android.os.Looper;
 import android.provider.Settings;
@@ -242,6 +243,15 @@
     }
 
     /**
+     * Gets a list of active, visible subscription Id(s) of the currently active SIM(s).
+     *
+     * @return the list of subId's that are active and visible; the length may be 0.
+     */
+    public @NonNull int[] getActiveSubscriptionIdList() {
+        return mSubscriptionMonitor.getActiveSubscriptionIdList();
+    }
+
+    /**
      * Clear data cached within proxy
      */
     public void clearCache() {
diff --git a/src/com/android/settings/network/SubscriptionUtil.java b/src/com/android/settings/network/SubscriptionUtil.java
index d6cac10..a562990 100644
--- a/src/com/android/settings/network/SubscriptionUtil.java
+++ b/src/com/android/settings/network/SubscriptionUtil.java
@@ -31,6 +31,8 @@
 import android.telephony.TelephonyManager;
 import android.telephony.UiccCardInfo;
 import android.telephony.UiccSlotInfo;
+import android.text.BidiFormatter;
+import android.text.TextDirectionHeuristics;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -42,7 +44,6 @@
 import com.android.settings.network.helper.SubscriptionAnnotation;
 import com.android.settings.network.telephony.DeleteEuiccSubscriptionDialogActivity;
 import com.android.settings.network.telephony.ToggleSubscriptionDialogActivity;
-import com.android.settingslib.DeviceInfoUtils;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -292,7 +293,7 @@
         final Supplier<Stream<DisplayInfo>> uniqueInfos = () -> originalInfos.get().map(info -> {
             if (duplicateOriginalNames.contains(info.originalName)) {
                 // This may return null, if the user cannot view the phone number itself.
-                final String phoneNumber = DeviceInfoUtils.getBidiFormattedPhoneNumber(context,
+                final String phoneNumber = getBidiFormattedPhoneNumber(context,
                         info.subscriptionInfo);
                 String lastFourDigits = "";
                 if (phoneNumber != null) {
@@ -564,6 +565,20 @@
     }
 
     /**
+     * To get the formatting text for display in a potentially opposite-directionality context
+     * without garbling.
+     * @param subscriptionInfo {@link SubscriptionInfo} subscription information.
+     * @return Returns phone number with Bidi format.
+     */
+    @Nullable
+    public static String getBidiFormattedPhoneNumber(Context context,
+            SubscriptionInfo subscriptionInfo) {
+        String phoneNumber = getFormattedPhoneNumber(context, subscriptionInfo);
+        return (phoneNumber == null) ? phoneNumber :
+                BidiFormatter.getInstance().unicodeWrap(phoneNumber, TextDirectionHeuristics.LTR);
+    }
+
+    /**
      * Returns the subscription on a removable sim card. The device does not need to be on removable
      * slot.
      */
diff --git a/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceController.java b/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceController.java
index f4543f5..1c20f59 100644
--- a/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceController.java
+++ b/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceController.java
@@ -19,12 +19,20 @@
 import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE;
 import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
 
+import android.app.settings.SettingsEnums;
 import android.content.Context;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.ims.ImsException;
+import android.telephony.ims.ImsManager;
+import android.telephony.ims.ImsMmTelManager;
+import android.util.Log;
 
+import androidx.annotation.NonNull;
 import androidx.lifecycle.LifecycleObserver;
 import androidx.lifecycle.OnLifecycleEvent;
 import androidx.preference.Preference;
@@ -32,9 +40,14 @@
 import androidx.preference.SwitchPreference;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.R;
 import com.android.settings.datausage.DataUsageUtils;
 import com.android.settings.network.MobileDataContentObserver;
+import com.android.settings.network.ProxySubscriptionManager;
 import com.android.settings.network.SubscriptionsChangeListener;
+import com.android.settings.network.ims.WifiCallingQueryImsState;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 
 /**
  * Controls whether switch mobile data to the non-default SIM if the non-default SIM has better
@@ -49,6 +62,7 @@
 public class AutoDataSwitchPreferenceController extends TelephonyTogglePreferenceController
         implements LifecycleObserver,
         SubscriptionsChangeListener.SubscriptionsChangeListenerClient {
+    private static final String LOG_TAG = "AutoDataSwitchPrefCtrl";
 
     private SwitchPreference mPreference;
     private SubscriptionsChangeListener mChangeListener;
@@ -56,9 +70,12 @@
     private MobileDataContentObserver mMobileDataContentObserver;
     private PreferenceScreen mScreen;
 
+    private final MetricsFeatureProvider mMetricsFeatureProvider;
+
     public AutoDataSwitchPreferenceController(Context context,
             String preferenceKey) {
         super(context, preferenceKey);
+        mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
     }
 
     void init(int subId) {
@@ -103,11 +120,36 @@
                 TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH);
     }
 
+    private int getOtherSubId(@NonNull int[] subIds) {
+        if (subIds.length > 1) {
+            for (int subId : subIds) {
+                if (subId != mSubId) {
+                    return subId;
+                }
+            }
+        }
+        return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+    }
+
+    private boolean isEnabled(int subId) {
+        if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+            return false;
+        }
+        TelephonyManager telephonyManager = mContext.getSystemService(
+                TelephonyManager.class).createForSubscriptionId(subId);
+        return telephonyManager != null && telephonyManager.isMobileDataPolicyEnabled(
+                        TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH);
+    }
+
     @Override
     public boolean setChecked(boolean isChecked) {
         mManager.setMobileDataPolicyEnabled(
                 TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
                 isChecked);
+        if (mContext.getResources().getBoolean(
+                R.bool.config_auto_data_switch_enables_cross_sim_calling)) {
+            trySetCrossSimCalling(mContext, getActiveSubscriptionIdList(), isChecked /* enabled */);
+        }
         return true;
     }
 
@@ -116,6 +158,40 @@
         return DataUsageUtils.hasMobileData(mContext);
     }
 
+    private boolean isCrossSimCallingAllowedByPlatform(Context context, int subId) {
+        if ((new WifiCallingQueryImsState(context, subId)).isWifiCallingSupported()) {
+            PersistableBundle bundle = getCarrierConfigForSubId(subId);
+            return (bundle != null) && bundle.getBoolean(
+                    CarrierConfigManager.KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL,
+                    false /*default*/);
+        }
+        return false;
+    }
+
+    protected ImsMmTelManager getImsMmTelManager(Context context, int subId) {
+        ImsManager imsMgr = context.getSystemService(ImsManager.class);
+        return (imsMgr == null) ? null : imsMgr.getImsMmTelManager(subId);
+    }
+
+    private void trySetCrossSimCallingPerSub(Context context, int subId, boolean enabled) {
+        try {
+            getImsMmTelManager(context, subId).setCrossSimCallingEnabled(enabled);
+        } catch (ImsException | IllegalArgumentException | NullPointerException exception) {
+            Log.w(LOG_TAG, "failed to change cross SIM calling configuration to " + enabled
+                    + " for subID " + subId + "with exception: ", exception);
+        }
+    }
+
+    private void trySetCrossSimCalling(Context context, int[] subIds, boolean enabled) {
+        mMetricsFeatureProvider.action(mContext,
+                SettingsEnums.ACTION_UPDATE_CROSS_SIM_CALLING_ON_AUTO_DATA_SWITCH_EVENT, enabled);
+        for (int subId : subIds) {
+            if (isCrossSimCallingAllowedByPlatform(context, subId)) {
+                trySetCrossSimCallingPerSub(context, subId, enabled);
+            }
+        }
+    }
+
     @Override
     public int getAvailabilityStatus(int subId) {
         if (!SubscriptionManager.isValidSubscriptionId(subId)
@@ -143,11 +219,20 @@
         updateState(mPreference);
     }
 
+    private int[] getActiveSubscriptionIdList() {
+        return ProxySubscriptionManager.getInstance(mContext).getActiveSubscriptionIdList();
+    }
+
     /**
-     * Trigger displaying preference when Mobilde data content changed.
+     * Trigger displaying preference when Mobile data content changed.
      */
     @VisibleForTesting
     public void refreshPreference() {
+        if (mContext.getResources().getBoolean(
+                R.bool.config_auto_data_switch_enables_cross_sim_calling)) {
+            int[] subIds = getActiveSubscriptionIdList();
+            trySetCrossSimCalling(mContext, subIds, isEnabled(getOtherSubId(subIds)));
+        }
         if (mScreen != null) {
             super.displayPreference(mScreen);
         }
diff --git a/src/com/android/settings/network/telephony/RenameMobileNetworkDialogFragment.java b/src/com/android/settings/network/telephony/RenameMobileNetworkDialogFragment.java
index ec48c82..8823353 100644
--- a/src/com/android/settings/network/telephony/RenameMobileNetworkDialogFragment.java
+++ b/src/com/android/settings/network/telephony/RenameMobileNetworkDialogFragment.java
@@ -47,7 +47,6 @@
 import com.android.settings.R;
 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
 import com.android.settings.network.SubscriptionUtil;
-import com.android.settingslib.DeviceInfoUtils;
 
 import com.google.common.collect.ImmutableMap;
 
@@ -184,7 +183,7 @@
         phoneTitle.setVisibility(info.isOpportunistic() ? View.GONE : View.VISIBLE);
 
         final TextView phoneNumber = view.findViewById(R.id.number_value);
-        final String pn = DeviceInfoUtils.getBidiFormattedPhoneNumber(getContext(), info);
+        final String pn = SubscriptionUtil.getBidiFormattedPhoneNumber(getContext(), info);
         if (!TextUtils.isEmpty(pn)) {
             phoneNumber.setText(pn);
         }
diff --git a/src/com/android/settings/notification/NotificationBackend.java b/src/com/android/settings/notification/NotificationBackend.java
index c63a294..7b7d41a 100644
--- a/src/com/android/settings/notification/NotificationBackend.java
+++ b/src/com/android/settings/notification/NotificationBackend.java
@@ -413,18 +413,6 @@
         }
     }
 
-    public void allowAssistantAdjustment(String capability, boolean allowed) {
-        try {
-            if (allowed) {
-                sINM.allowAssistantAdjustment(capability);
-            } else {
-                sINM.disallowAssistantAdjustment(capability);
-            }
-        } catch (Exception e) {
-            Log.w(TAG, "Error calling NoMan", e);
-        }
-    }
-
     public List<String> getAssistantAdjustments(String pkg) {
         try {
             return sINM.getAllowedAssistantAdjustments(pkg);
diff --git a/src/com/android/settings/security/ConfirmSimDeletionPreferenceController.java b/src/com/android/settings/security/ConfirmSimDeletionPreferenceController.java
index 3bf1563..2712a02 100644
--- a/src/com/android/settings/security/ConfirmSimDeletionPreferenceController.java
+++ b/src/com/android/settings/security/ConfirmSimDeletionPreferenceController.java
@@ -57,7 +57,8 @@
     @Override
     public int getAvailabilityStatus() {
         // hide if eSim is not supported on the device
-        return MobileNetworkUtils.showEuiccSettings(mContext) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+        return (!MobileNetworkUtils.isMobileNetworkUserRestricted(mContext)) &&
+                MobileNetworkUtils.showEuiccSettings(mContext) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
     }
 
     private boolean getGlobalState() {
diff --git a/src/com/android/settings/security/MemtagPreferenceController.java b/src/com/android/settings/security/MemtagPreferenceController.java
index b5a4be7..5e224a1 100644
--- a/src/com/android/settings/security/MemtagPreferenceController.java
+++ b/src/com/android/settings/security/MemtagPreferenceController.java
@@ -1,5 +1,6 @@
 /*
  * 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.
@@ -58,7 +59,11 @@
             refreshSummary(mPreference);
         }
         if (isChecked != MemtagHelper.isOn()) {
-            MemtagRebootDialog.show(mContext, mFragment, isChecked);
+            int msg =
+                    isChecked
+                            ? R.string.memtag_reboot_message_on
+                            : R.string.memtag_reboot_message_off;
+            MemtagRebootDialog.show(mContext, mFragment, msg);
         }
         return true;
     }
diff --git a/src/com/android/settings/security/MemtagRebootDialog.java b/src/com/android/settings/security/MemtagRebootDialog.java
index 735de8f..adedff8 100644
--- a/src/com/android/settings/security/MemtagRebootDialog.java
+++ b/src/com/android/settings/security/MemtagRebootDialog.java
@@ -34,16 +34,16 @@
         implements DialogInterface.OnClickListener, DialogInterface.OnDismissListener {
 
     public static final String TAG = "MemtagRebootDialog";
-    private boolean mIsChecked;
+    private int mMessage;
 
-    public MemtagRebootDialog(Context context, boolean isChecked) {
-        mIsChecked = isChecked;
+    public MemtagRebootDialog(Context context, int msg) {
+        mMessage = msg;
     }
 
-    public static void show(Context context, Fragment host, boolean isChecked) {
+    public static void show(Context context, Fragment host, int msg) {
         final FragmentManager manager = host.getActivity().getSupportFragmentManager();
         if (manager.findFragmentByTag(TAG) == null) {
-            final MemtagRebootDialog dialog = new MemtagRebootDialog(context, isChecked);
+            final MemtagRebootDialog dialog = new MemtagRebootDialog(context, msg);
             dialog.show(manager, TAG);
         }
     }
@@ -55,11 +55,9 @@
 
     @Override
     public Dialog onCreateDialog(Bundle savedInstanceState) {
-        int msg =
-                mIsChecked ? R.string.memtag_reboot_message_on : R.string.memtag_reboot_message_off;
         return new AlertDialog.Builder(getActivity())
                 .setTitle(R.string.memtag_reboot_title)
-                .setMessage(msg)
+                .setMessage(mMessage)
                 .setPositiveButton(R.string.memtag_reboot_yes, this /* onClickListener */)
                 .setNegativeButton(R.string.memtag_reboot_no, null /* onClickListener */)
                 .create();
diff --git a/src/com/android/settings/sim/SimDialogActivity.java b/src/com/android/settings/sim/SimDialogActivity.java
index a1258be..dcfa983 100644
--- a/src/com/android/settings/sim/SimDialogActivity.java
+++ b/src/com/android/settings/sim/SimDialogActivity.java
@@ -17,24 +17,35 @@
 package com.android.settings.sim;
 
 import android.app.Activity;
+import android.app.settings.SettingsEnums;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.os.Bundle;
+import android.os.PersistableBundle;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
+import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.ims.ImsException;
+import android.telephony.ims.ImsManager;
+import android.telephony.ims.ImsMmTelManager;
 import android.util.Log;
 import android.view.WindowManager;
 import android.widget.Toast;
 
+import androidx.annotation.NonNull;
 import androidx.fragment.app.Fragment;
 import androidx.fragment.app.FragmentActivity;
 import androidx.fragment.app.FragmentManager;
 
 import com.android.settings.R;
+import com.android.settings.network.CarrierConfigCache;
 import com.android.settings.network.SubscriptionUtil;
+import com.android.settings.network.ims.WifiCallingQueryImsState;
 import com.android.settings.network.telephony.SubscriptionActionDialogActivity;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 
 import java.util.List;
 
@@ -62,6 +73,7 @@
     // Show auto data switch dialog(when user enables multi-SIM)
     public static final int ENABLE_AUTO_DATA_SWITCH = 6;
 
+    private MetricsFeatureProvider mMetricsFeatureProvider;
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -73,6 +85,7 @@
         }
         SimDialogProhibitService.supportDismiss(this);
 
+        mMetricsFeatureProvider = FeatureFactory.getFactory(this).getMetricsFeatureProvider();
         getWindow().addSystemFlags(
                 WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
         showOrUpdateDialog();
@@ -192,6 +205,61 @@
         }
     }
 
+    private PersistableBundle getCarrierConfigForSubId(int subId) {
+        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+            return null;
+        }
+        return CarrierConfigCache.getInstance(this).getConfigForSubId(subId);
+    }
+
+    private boolean isCrossSimCallingAllowedByPlatform(int subId) {
+        if ((new WifiCallingQueryImsState(this, subId)).isWifiCallingSupported()) {
+            PersistableBundle bundle = getCarrierConfigForSubId(subId);
+            return (bundle != null) && bundle.getBoolean(
+                    CarrierConfigManager.KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL,
+                    false /*default*/);
+        }
+        return false;
+    }
+
+    private ImsMmTelManager getImsMmTelManager(int subId) {
+        ImsManager imsMgr = getSystemService(ImsManager.class);
+        return (imsMgr == null) ? null : imsMgr.getImsMmTelManager(subId);
+    }
+
+    private void trySetCrossSimCallingPerSub(int subId, boolean enabled) {
+        try {
+            getImsMmTelManager(subId).setCrossSimCallingEnabled(enabled);
+        } catch (ImsException | IllegalArgumentException | NullPointerException exception) {
+            Log.w(TAG, "failed to change cross SIM calling configuration to " + enabled
+                    + " for subID " + subId + "with exception: ", exception);
+        }
+    }
+
+    private boolean autoDataSwitchEnabledOnNonDataSub(@NonNull int[] subIds, int defaultDataSub) {
+        for (int subId : subIds) {
+            if (subId != defaultDataSub) {
+                final TelephonyManager telephonyManager = getSystemService(
+                        TelephonyManager.class).createForSubscriptionId(subId);
+                if (telephonyManager.isMobileDataPolicyEnabled(
+                        TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private void trySetCrossSimCalling(int[] subIds, boolean enabled) {
+        mMetricsFeatureProvider.action(this,
+                SettingsEnums.ACTION_UPDATE_CROSS_SIM_CALLING_ON_2ND_SIM_ENABLE, enabled);
+        for (int subId : subIds) {
+            if (isCrossSimCallingAllowedByPlatform(subId)) {
+                trySetCrossSimCallingPerSub(subId, enabled);
+            }
+        }
+    }
+
     /**
      * Show dialog prompting the user to enable auto data switch
      */
@@ -199,6 +267,26 @@
         final FragmentManager fragmentManager = getSupportFragmentManager();
         SimDialogFragment fragment = createFragment(ENABLE_AUTO_DATA_SWITCH);
         fragment.show(fragmentManager, Integer.toString(ENABLE_AUTO_DATA_SWITCH));
+
+        if (getResources().getBoolean(
+                R.bool.config_auto_data_switch_enables_cross_sim_calling)) {
+            // If auto data switch is already enabled on the non-DDS, the dialog for enabling it
+            // is suppressed (no onEnableAutoDataSwitch()). so we ensure cross-SIM calling is
+            // enabled.
+
+            // OTOH, if auto data switch is disabled on the new non-DDS, the user may still not
+            // enable it in the dialog. So we ensure cross-SIM calling is disabled before the
+            // dialog. If the user does enable auto data switch, we will re-enable cross-SIM calling
+            // through onEnableAutoDataSwitch()- a minor redundancy to ensure correctness.
+            final SubscriptionManager subscriptionManager =
+                    getSystemService(SubscriptionManager.class);
+            int[] subIds = subscriptionManager.getActiveSubscriptionIdList();
+            int defaultDataSub = subscriptionManager.getDefaultDataSubscriptionId();
+            if (subIds.length > 1) {
+                trySetCrossSimCalling(subIds,
+                        autoDataSwitchEnabledOnNonDataSub(subIds, defaultDataSub));
+            }
+        }
     }
 
     /**
@@ -210,6 +298,14 @@
                 TelephonyManager.class).createForSubscriptionId(subId);
         telephonyManager.setMobileDataPolicyEnabled(
                 TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH, true);
+
+        if (getResources().getBoolean(
+                R.bool.config_auto_data_switch_enables_cross_sim_calling)) {
+            final SubscriptionManager subscriptionManager =
+                    getSystemService(SubscriptionManager.class);
+            trySetCrossSimCalling(subscriptionManager.getActiveSubscriptionIdList(),
+                    true /* enabled */);
+        }
     }
 
     public void onFragmentDismissed(SimDialogFragment simDialogFragment) {
diff --git a/src/com/android/settings/wifi/AddNetworkFragment.java b/src/com/android/settings/wifi/AddNetworkFragment.java
index 47a027d..9fd8626 100644
--- a/src/com/android/settings/wifi/AddNetworkFragment.java
+++ b/src/com/android/settings/wifi/AddNetworkFragment.java
@@ -20,6 +20,7 @@
 import android.app.settings.SettingsEnums;
 import android.content.Intent;
 import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
 import android.os.Bundle;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -28,6 +29,7 @@
 import android.widget.Button;
 import android.widget.ImageButton;
 import android.widget.TextView;
+import android.widget.Toast;
 
 import androidx.annotation.VisibleForTesting;
 
@@ -51,6 +53,8 @@
 
     private static final int REQUEST_CODE_WIFI_DPP_ENROLLEE_QR_CODE_SCANNER = 0;
 
+    private static final String EXTRA_SAVE_WHEN_SUBMIT = ":settings:save_when_submit";
+
     private WifiConfigController2 mUIController;
     private Button mSubmitBtn;
     private Button mCancelBtn;
@@ -196,11 +200,35 @@
     }
 
     private void successfullyFinish(WifiConfiguration config) {
-        final Intent intent = new Intent();
-        final Activity activity = getActivity();
-        intent.putExtra(WIFI_CONFIG_KEY, config);
-        activity.setResult(Activity.RESULT_OK, intent);
-        activity.finish();
+        Activity activity = getActivity();
+        boolean autoSave = activity.getIntent().getBooleanExtra(EXTRA_SAVE_WHEN_SUBMIT, false);
+        if (autoSave && config != null) {
+            WifiManager.ActionListener saveListener = new WifiManager.ActionListener() {
+                @Override
+                public void onSuccess() {
+                    if (activity != null && !activity.isFinishing()) {
+                        activity.setResult(Activity.RESULT_OK);
+                        activity.finish();
+                    }
+                }
+
+                @Override
+                public void onFailure(int reason) {
+                    if (activity != null && !activity.isFinishing()) {
+                        Toast.makeText(activity, R.string.wifi_failed_save_message,
+                                Toast.LENGTH_SHORT).show();
+                        activity.finish();
+                    }
+                }
+            };
+
+            activity.getSystemService(WifiManager.class).save(config, saveListener);
+        } else {
+            Intent intent = new Intent();
+            intent.putExtra(WIFI_CONFIG_KEY, config);
+            activity.setResult(Activity.RESULT_OK, intent);
+            activity.finish();
+        }
     }
 
     @VisibleForTesting
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizardTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizardTest.java
index 508b229..e14e271 100644
--- a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizardTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizardTest.java
@@ -23,6 +23,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
@@ -45,6 +46,7 @@
 import com.android.settings.R;
 import com.android.settingslib.RestrictedPreference;
 
+import com.google.android.setupcompat.template.FooterBarMixin;
 import com.google.android.setupdesign.GlifPreferenceLayout;
 
 import org.junit.Before;
@@ -79,6 +81,8 @@
     private FragmentActivity mActivity;
     @Mock
     private GlifPreferenceLayout mGlifLayoutView;
+    @Mock
+    private FooterBarMixin mFooterBarMixin;
     private AccessibilitySettingsForSetupWizard mFragment;
 
     @Before
@@ -89,6 +93,7 @@
         when(mAccessibilityManager.getInstalledAccessibilityServiceList()).thenReturn(
                 mAccessibilityServices);
         doReturn(mActivity).when(mFragment).getActivity();
+        doReturn(mFooterBarMixin).when(mGlifLayoutView).getMixin(FooterBarMixin.class);
     }
 
     @Test
@@ -99,6 +104,7 @@
                 mContext.getString(R.string.vision_settings_title));
         verify(mGlifLayoutView).setDescriptionText(
                 mContext.getString(R.string.vision_settings_description));
+        verify(mFooterBarMixin).setPrimaryButton(any());
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizardTest.java b/tests/robotests/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizardTest.java
index 7df24f1..1cd301f 100644
--- a/tests/robotests/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizardTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizardTest.java
@@ -100,19 +100,10 @@
     }
 
     @Test
-    public void onViewCreated_verifySetSecondaryButton() {
-        mFragment.onViewCreated(mGlifLayoutView, null);
-
-        verify(mFooterBarMixin).setSecondaryButton(any());
-    }
-
-    @Test
-    public void onViewCreated_verifySetPrimaryButton() {
-        doReturn(mActivity).when(mFragment).getActivity();
-        doReturn("setupwizard").when(mActivity).getCallingPackage();
-
+    public void onViewCreated_verifyAction() {
         mFragment.onViewCreated(mGlifLayoutView, null);
 
         verify(mFooterBarMixin).setPrimaryButton(any());
+        verify(mFooterBarMixin).setSecondaryButton(any());
     }
 }
diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentForSetupWizardTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentForSetupWizardTest.java
index c5978f6..84783b21 100644
--- a/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentForSetupWizardTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentForSetupWizardTest.java
@@ -18,6 +18,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
@@ -38,6 +39,7 @@
 import com.android.settings.widget.SettingsMainSwitchBar;
 import com.android.settingslib.widget.TopIntroPreference;
 
+import com.google.android.setupcompat.template.FooterBarMixin;
 import com.google.android.setupdesign.GlifPreferenceLayout;
 
 import org.junit.Before;
@@ -64,6 +66,8 @@
     private GlifPreferenceLayout mGlifLayoutView;
     @Mock
     private SettingsMainSwitchBar mSwitchBar;
+    @Mock
+    private FooterBarMixin mFooterBarMixin;
     private ToggleScreenMagnificationPreferenceFragmentForSetupWizard mFragment;
 
     @Before
@@ -72,6 +76,7 @@
                 spy(new TestToggleScreenMagnificationPreferenceFragmentForSetupWizard(mContext));
         doReturn(mActivity).when(mFragment).getActivity();
         when(mActivity.getSwitchBar()).thenReturn(mSwitchBar);
+        doReturn(mFooterBarMixin).when(mGlifLayoutView).getMixin(FooterBarMixin.class);
     }
 
     @Test
@@ -83,6 +88,7 @@
         verify(mGlifLayoutView).setDescriptionText(
                 mContext.getString(R.string.accessibility_screen_magnification_intro_text));
         verify(mGlifLayoutView).setDividerInsets(Integer.MAX_VALUE, 0);
+        verify(mFooterBarMixin).setPrimaryButton(any());
         assertThat(mFragment.mTopIntroPreference.isVisible()).isFalse();
         assertThat(mFragment.mSettingsPreference.isVisible()).isFalse();
         assertThat(mFragment.mFollowingTypingSwitchPreference.isVisible()).isFalse();
diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleScreenReaderPreferenceFragmentForSetupWizardTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleScreenReaderPreferenceFragmentForSetupWizardTest.java
index 2cbe1ad..c604652 100644
--- a/tests/robotests/src/com/android/settings/accessibility/ToggleScreenReaderPreferenceFragmentForSetupWizardTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/ToggleScreenReaderPreferenceFragmentForSetupWizardTest.java
@@ -18,6 +18,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
@@ -37,6 +38,7 @@
 import com.android.settings.widget.SettingsMainSwitchPreference;
 import com.android.settingslib.widget.TopIntroPreference;
 
+import com.google.android.setupcompat.template.FooterBarMixin;
 import com.google.android.setupdesign.GlifPreferenceLayout;
 
 import org.junit.Before;
@@ -62,6 +64,8 @@
     private GlifPreferenceLayout mGlifLayoutView;
     @Mock
     private SettingsMainSwitchBar mSwitchBar;
+    @Mock
+    private FooterBarMixin mFooterBarMixin;
     private ToggleScreenReaderPreferenceFragmentForSetupWizard mFragment;
 
     @Before
@@ -69,6 +73,7 @@
         mFragment = spy(new TestToggleScreenReaderPreferenceFragmentForSetupWizard(mContext));
         doReturn(mActivity).when(mFragment).getActivity();
         when(mActivity.getSwitchBar()).thenReturn(mSwitchBar);
+        doReturn(mFooterBarMixin).when(mGlifLayoutView).getMixin(FooterBarMixin.class);
     }
 
     @Test
@@ -79,6 +84,7 @@
         verify(mGlifLayoutView).setDescriptionText(
                 mContext.getString(R.string.talkback_summary));
         verify(mGlifLayoutView).setDividerInsets(Integer.MAX_VALUE, 0);
+        verify(mFooterBarMixin).setPrimaryButton(any());
         assertThat(mFragment.mTopIntroPreference.isVisible()).isFalse();
     }
 
diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleSelectToSpeakPreferenceFragmentForSetupWizardTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleSelectToSpeakPreferenceFragmentForSetupWizardTest.java
index 43440ff..7893831 100644
--- a/tests/robotests/src/com/android/settings/accessibility/ToggleSelectToSpeakPreferenceFragmentForSetupWizardTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/ToggleSelectToSpeakPreferenceFragmentForSetupWizardTest.java
@@ -18,6 +18,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
@@ -37,6 +38,7 @@
 import com.android.settings.widget.SettingsMainSwitchPreference;
 import com.android.settingslib.widget.TopIntroPreference;
 
+import com.google.android.setupcompat.template.FooterBarMixin;
 import com.google.android.setupdesign.GlifPreferenceLayout;
 
 import org.junit.Before;
@@ -62,6 +64,8 @@
     private GlifPreferenceLayout mGlifLayoutView;
     @Mock
     private SettingsMainSwitchBar mSwitchBar;
+    @Mock
+    private FooterBarMixin mFooterBarMixin;
     private ToggleSelectToSpeakPreferenceFragmentForSetupWizard mFragment;
 
     @Before
@@ -69,6 +73,7 @@
         mFragment = spy(new TestToggleSelectToSpeakPreferenceFragmentForSetupWizard(mContext));
         doReturn(mActivity).when(mFragment).getActivity();
         when(mActivity.getSwitchBar()).thenReturn(mSwitchBar);
+        doReturn(mFooterBarMixin).when(mGlifLayoutView).getMixin(FooterBarMixin.class);
     }
 
     @Test
@@ -79,6 +84,7 @@
         verify(mGlifLayoutView).setDescriptionText(
                 mContext.getString(R.string.select_to_speak_summary));
         verify(mGlifLayoutView).setDividerInsets(Integer.MAX_VALUE, 0);
+        verify(mFooterBarMixin).setPrimaryButton(any());
         assertThat(mFragment.mTopIntroPreference.isVisible()).isFalse();
     }
 
diff --git a/tests/robotests/src/com/android/settings/bluetooth/HearingDeviceAudioRoutingBasePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/HearingDeviceAudioRoutingBasePreferenceControllerTest.java
new file mode 100644
index 0000000..5be36c8
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/bluetooth/HearingDeviceAudioRoutingBasePreferenceControllerTest.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2023 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.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.media.AudioAttributes;
+import android.media.AudioDeviceAttributes;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
+import android.media.audiopolicy.AudioProductStrategy;
+
+import androidx.preference.ListPreference;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+
+import java.util.List;
+
+/** Tests for {@link HearingDeviceAudioRoutingBasePreferenceController}. */
+@RunWith(RobolectricTestRunner.class)
+public class HearingDeviceAudioRoutingBasePreferenceControllerTest {
+
+    @Rule
+    public MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+    @Spy
+    private final Context mContext = ApplicationProvider.getApplicationContext();
+    private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1";
+    private static final String FAKE_KEY = "fake_key";
+    private static final String TEST_SHARED_PREFERENCE = "test_bluetooth_settings";
+
+    @Mock
+    private CachedBluetoothDevice mCachedBluetoothDevice;
+    @Mock
+    private AudioProductStrategy mAudioProductStrategyMedia;
+    private AudioDeviceAttributes mHearingDeviceAttribute;
+    private ListPreference mListPreference;
+    private TestHearingDeviceAudioRoutingBasePreferenceController mController;
+
+    @Before
+    public void setUp() {
+        mListPreference = new ListPreference(mContext);
+        when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS);
+        mHearingDeviceAttribute = new AudioDeviceAttributes(
+                AudioDeviceAttributes.ROLE_OUTPUT,
+                AudioDeviceInfo.TYPE_HEARING_AID,
+                TEST_DEVICE_ADDRESS);
+        when(mAudioProductStrategyMedia.getAudioAttributesForLegacyStreamType(
+                AudioManager.STREAM_MUSIC))
+                .thenReturn((new AudioAttributes.Builder()).build());
+        doReturn(getSharedPreferences()).when(mContext).getSharedPreferences(anyString(), anyInt());
+
+        mController = spy(
+                new TestHearingDeviceAudioRoutingBasePreferenceController(mContext, FAKE_KEY));
+        mController.setupForTesting(mCachedBluetoothDevice);
+        doReturn(List.of(mAudioProductStrategyMedia)).when(mController).getAudioProductStrategies();
+    }
+
+    @Test
+    public void onPreferenceChange_routingValueAuto_expectedListValue() {
+        mController.onPreferenceChange(mListPreference, String.valueOf(
+                HearingDeviceAudioRoutingBasePreferenceController.RoutingValue.AUTO));
+
+        verify(mController).removePreferredDeviceForStrategies(any());
+        assertThat(mListPreference.getValue()).isEqualTo(String.valueOf(
+                HearingDeviceAudioRoutingBasePreferenceController.RoutingValue.AUTO));
+    }
+
+    @Test
+    public void onPreferenceChange_routingValueHearingDevice_expectedListValue() {
+        mController.onPreferenceChange(mListPreference, String.valueOf(
+                HearingDeviceAudioRoutingBasePreferenceController.RoutingValue.HEARING_DEVICE));
+
+        verify(mController).setPreferredDeviceForStrategies(any(), eq(mHearingDeviceAttribute));
+        assertThat(mListPreference.getValue()).isEqualTo(String.valueOf(
+                HearingDeviceAudioRoutingBasePreferenceController.RoutingValue.HEARING_DEVICE));
+    }
+
+    @Test
+    public void onPreferenceChange_routingValueDeviceSpeaker_expectedListValue() {
+        final AudioDeviceAttributes deviceSpeakerOut = new AudioDeviceAttributes(
+                AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, "");
+
+        mController.onPreferenceChange(mListPreference, String.valueOf(
+                HearingDeviceAudioRoutingBasePreferenceController.RoutingValue.DEVICE_SPEAKER));
+
+        verify(mController).setPreferredDeviceForStrategies(any(), eq(deviceSpeakerOut));
+        assertThat(mListPreference.getValue()).isEqualTo(String.valueOf(
+                HearingDeviceAudioRoutingBasePreferenceController.RoutingValue.DEVICE_SPEAKER));
+
+    }
+
+    private SharedPreferences getSharedPreferences() {
+        return mContext.getSharedPreferences(TEST_SHARED_PREFERENCE, Context.MODE_PRIVATE);
+    }
+
+    private static class TestHearingDeviceAudioRoutingBasePreferenceController extends
+            HearingDeviceAudioRoutingBasePreferenceController {
+
+        private static CachedBluetoothDevice sCachedBluetoothDevice;
+        private static int sSavedRoutingValue;
+
+        TestHearingDeviceAudioRoutingBasePreferenceController(Context context,
+                String preferenceKey) {
+            super(context, preferenceKey);
+        }
+
+        @Override
+        protected int[] getSupportedAttributeList() {
+            return new int[]{AudioAttributes.USAGE_MEDIA};
+        }
+
+        @Override
+        protected CachedBluetoothDevice getHearingDevice() {
+            return sCachedBluetoothDevice;
+        }
+
+        @Override
+        protected void saveRoutingValue(Context context, int routingValue) {
+            sSavedRoutingValue = routingValue;
+        }
+
+        @Override
+        protected int restoreRoutingValue(Context context) {
+            return sSavedRoutingValue;
+        }
+
+        public static void setupForTesting(CachedBluetoothDevice cachedBluetoothDevice) {
+            sCachedBluetoothDevice = cachedBluetoothDevice;
+        }
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/development/BluetoothSnoopLogFilterProfileMapPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/BluetoothSnoopLogFilterProfileMapPreferenceControllerTest.java
new file mode 100644
index 0000000..411cca0
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/BluetoothSnoopLogFilterProfileMapPreferenceControllerTest.java
@@ -0,0 +1,185 @@
+/*
+ * 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.development;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.sysprop.BluetoothProperties;
+
+import androidx.preference.ListPreference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.Locale;
+
+@RunWith(RobolectricTestRunner.class)
+public class BluetoothSnoopLogFilterProfileMapPreferenceControllerTest {
+
+    @Spy private Context mSpyContext = RuntimeEnvironment.application;
+    @Spy private Resources mSpyResources = RuntimeEnvironment.application.getResources();
+    private ListPreference mPreference;
+    @Mock private PreferenceScreen mPreferenceScreen;
+    private BluetoothSnoopLogFilterProfileMapPreferenceController mController;
+
+    private CharSequence[] mListValues;
+    private CharSequence[] mListEntries;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        doReturn(mSpyResources).when(mSpyContext).getResources();
+        // Get XML values without mock
+        // Setup test list preference using XML values
+        mPreference = new ListPreference(mSpyContext);
+        mPreference.setEntries(R.array.bt_hci_snoop_log_profile_filter_entries);
+        mPreference.setEntryValues(R.array.bt_hci_snoop_log_profile_filter_values);
+        // Init the actual controller
+        mController = new BluetoothSnoopLogFilterProfileMapPreferenceController(mSpyContext);
+        // Construct preference in the controller via a mocked preference screen object
+        when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
+                .thenReturn(mPreference);
+        mController.displayPreference(mPreferenceScreen);
+        mListValues = mPreference.getEntryValues();
+        mListEntries = mPreference.getEntries();
+        BluetoothProperties.snoop_log_mode(BluetoothProperties.snoop_log_mode_values.FILTERED);
+    }
+
+    @Test
+    public void verifyResourceSizeAndRange() {
+        Assert.assertTrue(
+                BluetoothSnoopLogFilterProfileMapPreferenceController
+                        .isSnoopLogModeFilteredEnabled());
+        // Verify normal list entries and default preference entries have the same size
+        Assert.assertEquals(mListEntries.length, mListValues.length);
+        // Update the preference
+        mController.updateState(mPreference);
+        // Verify default preference value, entry and summary
+        final int defaultIndex = mController.getDefaultModeIndex();
+        Assert.assertEquals(mPreference.getValue(), mListValues[defaultIndex]);
+        Assert.assertEquals(mPreference.getEntry(), mListEntries[defaultIndex]);
+        Assert.assertEquals(mPreference.getSummary(), mListEntries[defaultIndex]);
+    }
+
+    @Test
+    public void onPreferenceChanged_turnOnBluetoothSnoopLogFullFilterMap() {
+        Assert.assertTrue(
+                BluetoothSnoopLogFilterProfileMapPreferenceController
+                        .isSnoopLogModeFilteredEnabled());
+        mController.onPreferenceChange(
+                null,
+                mListValues[
+                        BluetoothSnoopLogFilterProfileMapPreferenceController
+                                .BTSNOOP_LOG_PROFILE_FILTER_MODE_FULL_FILTER_INDEX]);
+        var mode =
+                BluetoothProperties.snoop_log_filter_profile_map()
+                        .orElse(BluetoothProperties.snoop_log_filter_profile_map_values.DISABLED);
+        // "fullfilter" is hard-coded between Settings and system/bt
+        Assert.assertEquals(
+                mode, BluetoothProperties.snoop_log_filter_profile_map_values.FULLFILTER);
+    }
+
+    @Test
+    public void onPreferenceChanged_turnOnBluetoothSnoopLogHeaderFilterMap() {
+        Assert.assertTrue(
+                BluetoothSnoopLogFilterProfileMapPreferenceController
+                        .isSnoopLogModeFilteredEnabled());
+        mController.onPreferenceChange(
+                null,
+                mListValues[
+                        BluetoothSnoopLogFilterProfileMapPreferenceController
+                                .BTSNOOP_LOG_PROFILE_FILTER_MODE_HEADER_INDEX]);
+        var mode =
+                BluetoothProperties.snoop_log_filter_profile_map()
+                        .orElse(BluetoothProperties.snoop_log_filter_profile_map_values.DISABLED);
+        // "header" is hard-coded between Settings and system/bt
+        Assert.assertEquals(mode, BluetoothProperties.snoop_log_filter_profile_map_values.HEADER);
+    }
+
+    @Test
+    public void onPreferenceChanged_turnOnBluetoothSnoopLogMagicFilterMap() {
+        Assert.assertTrue(
+                BluetoothSnoopLogFilterProfileMapPreferenceController
+                        .isSnoopLogModeFilteredEnabled());
+        mController.onPreferenceChange(
+                null,
+                mListValues[
+                        BluetoothSnoopLogFilterProfileMapPreferenceController
+                                .BTSNOOP_LOG_PROFILE_FILTER_MODE_MAGIC_INDEX]);
+        var mode =
+                BluetoothProperties.snoop_log_filter_profile_map()
+                        .orElse(BluetoothProperties.snoop_log_filter_profile_map_values.DISABLED);
+        // "magic" is hard-coded between Settings and system/bt
+        Assert.assertEquals(mode, BluetoothProperties.snoop_log_filter_profile_map_values.MAGIC);
+    }
+
+    @Test
+    public void onPreferenceChanged_turnOffBluetoothSnoopLogFilterMap() {
+        Assert.assertTrue(
+                BluetoothSnoopLogFilterProfileMapPreferenceController
+                        .isSnoopLogModeFilteredEnabled());
+        mController.onPreferenceChange(
+                null,
+                mListValues[
+                        BluetoothSnoopLogFilterProfileMapPreferenceController
+                                .BTSNOOP_LOG_PROFILE_FILTER_MODE_DISABLED_INDEX]);
+        var mode =
+                BluetoothProperties.snoop_log_filter_profile_map()
+                        .orElse(BluetoothProperties.snoop_log_filter_profile_map_values.DISABLED);
+        // "disabled" is hard-coded between Settings and system/bt
+        Assert.assertEquals(mode, BluetoothProperties.snoop_log_filter_profile_map_values.DISABLED);
+    }
+
+    @Test
+    public void updateState_preferenceShouldBeSetToRightValue() {
+        Assert.assertTrue(
+                BluetoothSnoopLogFilterProfileMapPreferenceController
+                        .isSnoopLogModeFilteredEnabled());
+        for (int i = 0; i < mListValues.length; ++i) {
+            BluetoothProperties.snoop_log_filter_profile_map(
+                    BluetoothProperties.snoop_log_filter_profile_map_values.valueOf(
+                            mListValues[i].toString().toUpperCase(Locale.US)));
+            mController.updateState(mPreference);
+            Assert.assertEquals(mPreference.getValue(), mListValues[i].toString());
+            Assert.assertEquals(mPreference.getSummary(), mListEntries[i].toString());
+        }
+    }
+
+    @Test
+    public void onDeveloperOptionsDisabled_shouldDisablePreference() {
+        mController.onDeveloperOptionsDisabled();
+        Assert.assertFalse(mPreference.isEnabled());
+        Assert.assertEquals(
+                mPreference.getValue(), mListValues[mController.getDefaultModeIndex()].toString());
+        Assert.assertEquals(
+                mPreference.getSummary(),
+                mListEntries[mController.getDefaultModeIndex()].toString());
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/development/BluetoothSnoopLogFilterProfilePbapPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/BluetoothSnoopLogFilterProfilePbapPreferenceControllerTest.java
new file mode 100644
index 0000000..add84c3
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/BluetoothSnoopLogFilterProfilePbapPreferenceControllerTest.java
@@ -0,0 +1,186 @@
+/*
+ * 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.development;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.sysprop.BluetoothProperties;
+
+import androidx.preference.ListPreference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.Locale;
+
+@RunWith(RobolectricTestRunner.class)
+public class BluetoothSnoopLogFilterProfilePbapPreferenceControllerTest {
+
+    @Spy private Context mSpyContext = RuntimeEnvironment.application;
+    @Spy private Resources mSpyResources = RuntimeEnvironment.application.getResources();
+    private ListPreference mPreference;
+    @Mock private PreferenceScreen mPreferenceScreen;
+    private BluetoothSnoopLogFilterProfilePbapPreferenceController mController;
+
+    private CharSequence[] mListValues;
+    private CharSequence[] mListEntries;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        doReturn(mSpyResources).when(mSpyContext).getResources();
+        // Get XML values without mock
+        // Setup test list preference using XML values
+        mPreference = new ListPreference(mSpyContext);
+        mPreference.setEntries(R.array.bt_hci_snoop_log_profile_filter_entries);
+        mPreference.setEntryValues(R.array.bt_hci_snoop_log_profile_filter_values);
+        // Init the actual controller
+        mController = new BluetoothSnoopLogFilterProfilePbapPreferenceController(mSpyContext);
+        // Construct preference in the controller via a mocked preference screen object
+        when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
+                .thenReturn(mPreference);
+        mController.displayPreference(mPreferenceScreen);
+        mListValues = mPreference.getEntryValues();
+        mListEntries = mPreference.getEntries();
+        BluetoothProperties.snoop_log_mode(BluetoothProperties.snoop_log_mode_values.FILTERED);
+    }
+
+    @Test
+    public void verifyResourceSizeAndRange() {
+        Assert.assertTrue(
+                BluetoothSnoopLogFilterProfilePbapPreferenceController
+                        .isSnoopLogModeFilteredEnabled());
+        // Verify normal list entries and default preference entries have the same size
+        Assert.assertEquals(mListEntries.length, mListValues.length);
+        // Update the preference
+        mController.updateState(mPreference);
+        // Verify default preference value, entry and summary
+        final int defaultIndex = mController.getDefaultModeIndex();
+        Assert.assertEquals(mPreference.getValue(), mListValues[defaultIndex]);
+        Assert.assertEquals(mPreference.getEntry(), mListEntries[defaultIndex]);
+        Assert.assertEquals(mPreference.getSummary(), mListEntries[defaultIndex]);
+    }
+
+    @Test
+    public void onPreferenceChanged_turnOnBluetoothSnoopLogFullFilterPbap() {
+        Assert.assertTrue(
+                BluetoothSnoopLogFilterProfilePbapPreferenceController
+                        .isSnoopLogModeFilteredEnabled());
+        mController.onPreferenceChange(
+                null,
+                mListValues[
+                        BluetoothSnoopLogFilterProfilePbapPreferenceController
+                                .BTSNOOP_LOG_PROFILE_FILTER_MODE_FULL_FILTER_INDEX]);
+        var mode =
+                BluetoothProperties.snoop_log_filter_profile_pbap()
+                        .orElse(BluetoothProperties.snoop_log_filter_profile_pbap_values.DISABLED);
+        // "fullfilter" is hard-coded between Settings and system/bt
+        Assert.assertEquals(
+                mode, BluetoothProperties.snoop_log_filter_profile_pbap_values.FULLFILTER);
+    }
+
+    @Test
+    public void onPreferenceChanged_turnOnBluetoothSnoopLogHeaderFilterPbap() {
+        Assert.assertTrue(
+                BluetoothSnoopLogFilterProfilePbapPreferenceController
+                        .isSnoopLogModeFilteredEnabled());
+        mController.onPreferenceChange(
+                null,
+                mListValues[
+                        BluetoothSnoopLogFilterProfilePbapPreferenceController
+                                .BTSNOOP_LOG_PROFILE_FILTER_MODE_HEADER_INDEX]);
+        var mode =
+                BluetoothProperties.snoop_log_filter_profile_pbap()
+                        .orElse(BluetoothProperties.snoop_log_filter_profile_pbap_values.DISABLED);
+        // "header" is hard-coded between Settings and system/bt
+        Assert.assertEquals(mode, BluetoothProperties.snoop_log_filter_profile_pbap_values.HEADER);
+    }
+
+    @Test
+    public void onPreferenceChanged_turnOnBluetoothSnoopLogMagicFilterPbap() {
+        Assert.assertTrue(
+                BluetoothSnoopLogFilterProfilePbapPreferenceController
+                        .isSnoopLogModeFilteredEnabled());
+        mController.onPreferenceChange(
+                null,
+                mListValues[
+                        BluetoothSnoopLogFilterProfilePbapPreferenceController
+                                .BTSNOOP_LOG_PROFILE_FILTER_MODE_MAGIC_INDEX]);
+        var mode =
+                BluetoothProperties.snoop_log_filter_profile_pbap()
+                        .orElse(BluetoothProperties.snoop_log_filter_profile_pbap_values.DISABLED);
+        // "magic" is hard-coded between Settings and system/bt
+        Assert.assertEquals(mode, BluetoothProperties.snoop_log_filter_profile_pbap_values.MAGIC);
+    }
+
+    @Test
+    public void onPreferenceChanged_turnOffBluetoothSnoopLogFilterPbap() {
+        Assert.assertTrue(
+                BluetoothSnoopLogFilterProfilePbapPreferenceController
+                        .isSnoopLogModeFilteredEnabled());
+        mController.onPreferenceChange(
+                null,
+                mListValues[
+                        BluetoothSnoopLogFilterProfilePbapPreferenceController
+                                .BTSNOOP_LOG_PROFILE_FILTER_MODE_DISABLED_INDEX]);
+        var mode =
+                BluetoothProperties.snoop_log_filter_profile_pbap()
+                        .orElse(BluetoothProperties.snoop_log_filter_profile_pbap_values.DISABLED);
+        // "disabled" is hard-coded between Settings and system/bt
+        Assert.assertEquals(
+                mode, BluetoothProperties.snoop_log_filter_profile_pbap_values.DISABLED);
+    }
+
+    @Test
+    public void updateState_preferenceShouldBeSetToRightValue() {
+        Assert.assertTrue(
+                BluetoothSnoopLogFilterProfilePbapPreferenceController
+                        .isSnoopLogModeFilteredEnabled());
+        for (int i = 0; i < mListValues.length; ++i) {
+            BluetoothProperties.snoop_log_filter_profile_pbap(
+                    BluetoothProperties.snoop_log_filter_profile_pbap_values.valueOf(
+                            mListValues[i].toString().toUpperCase(Locale.US)));
+            mController.updateState(mPreference);
+            Assert.assertEquals(mPreference.getValue(), mListValues[i].toString());
+            Assert.assertEquals(mPreference.getSummary(), mListEntries[i].toString());
+        }
+    }
+
+    @Test
+    public void onDeveloperOptionsDisabled_shouldDisablePreference() {
+        mController.onDeveloperOptionsDisabled();
+        Assert.assertFalse(mPreference.isEnabled());
+        Assert.assertEquals(
+                mPreference.getValue(), mListValues[mController.getDefaultModeIndex()].toString());
+        Assert.assertEquals(
+                mPreference.getSummary(),
+                mListEntries[mController.getDefaultModeIndex()].toString());
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/development/BluetoothSnoopLogPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/BluetoothSnoopLogPreferenceControllerTest.java
index 630fd5f..6668a53 100644
--- a/tests/robotests/src/com/android/settings/development/BluetoothSnoopLogPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/BluetoothSnoopLogPreferenceControllerTest.java
@@ -17,9 +17,8 @@
 package com.android.settings.development;
 
 import static com.android.settings.development.BluetoothSnoopLogPreferenceController.BLUETOOTH_BTSNOOP_LOG_MODE_PROPERTY;
-import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
@@ -31,6 +30,7 @@
 
 import com.android.settings.R;
 
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -43,13 +43,10 @@
 @RunWith(RobolectricTestRunner.class)
 public class BluetoothSnoopLogPreferenceControllerTest {
 
-    @Spy
-    private Context mSpyContext = RuntimeEnvironment.application;
-    @Spy
-    private Resources mSpyResources = RuntimeEnvironment.application.getResources();
+    @Spy private Context mSpyContext = RuntimeEnvironment.application;
+    @Spy private Resources mSpyResources = RuntimeEnvironment.application.getResources();
     private ListPreference mPreference;
-    @Mock
-    private PreferenceScreen mPreferenceScreen;
+    @Mock private PreferenceScreen mPreferenceScreen;
     private BluetoothSnoopLogPreferenceController mController;
 
     private CharSequence[] mListValues;
@@ -65,10 +62,10 @@
         mPreference.setEntries(R.array.bt_hci_snoop_log_entries);
         mPreference.setEntryValues(R.array.bt_hci_snoop_log_values);
         // Init the actual controller
-        mController = new BluetoothSnoopLogPreferenceController(mSpyContext);
+        mController = new BluetoothSnoopLogPreferenceController(mSpyContext, null);
         // Construct preference in the controller via a mocked preference screen object
         when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
-            .thenReturn(mPreference);
+                .thenReturn(mPreference);
         mController.displayPreference(mPreferenceScreen);
         mListValues = mPreference.getEntryValues();
         mListEntries = mPreference.getEntries();
@@ -77,41 +74,44 @@
     @Test
     public void verifyResourceSizeAndRange() {
         // Verify normal list entries and default preference entries have the same size
-        assertThat(mListEntries.length).isEqualTo(mListValues.length);
+        Assert.assertEquals(mListEntries.length, mListValues.length);
         // Update the preference
         mController.updateState(mPreference);
         // Verify default preference value, entry and summary
         final int defaultIndex = mController.getDefaultModeIndex();
-        assertThat(mPreference.getValue()).isEqualTo(mListValues[defaultIndex]);
-        assertThat(mPreference.getEntry()).isEqualTo(mListEntries[defaultIndex]);
-        assertThat(mPreference.getSummary()).isEqualTo(mListEntries[defaultIndex]);
+        Assert.assertEquals(mPreference.getValue(), mListValues[defaultIndex]);
+        Assert.assertEquals(mPreference.getEntry(), mListEntries[defaultIndex]);
+        Assert.assertEquals(mPreference.getSummary(), mListEntries[defaultIndex]);
     }
 
     @Test
     public void onPreferenceChanged_turnOnFullBluetoothSnoopLog() {
-        mController.onPreferenceChange(null,
+        mController.onPreferenceChange(
+                null,
                 mListValues[BluetoothSnoopLogPreferenceController.BTSNOOP_LOG_MODE_FULL_INDEX]);
         final String mode = SystemProperties.get(BLUETOOTH_BTSNOOP_LOG_MODE_PROPERTY);
         // "full" is hard-coded between Settings and system/bt
-        assertThat(mode).isEqualTo("full");
+        Assert.assertEquals(mode, "full");
     }
 
     @Test
     public void onPreferenceChanged_turnOnFilteredBluetoothSnoopLog() {
-        mController.onPreferenceChange(null,
+        mController.onPreferenceChange(
+                null,
                 mListValues[BluetoothSnoopLogPreferenceController.BTSNOOP_LOG_MODE_FILTERED_INDEX]);
         final String mode = SystemProperties.get(BLUETOOTH_BTSNOOP_LOG_MODE_PROPERTY);
         // "filtered" is hard-coded between Settings and system/bt
-        assertThat(mode).isEqualTo("filtered");
+        Assert.assertEquals(mode, "filtered");
     }
 
     @Test
     public void onPreferenceChanged_turnOffBluetoothSnoopLog() {
-        mController.onPreferenceChange(null,
+        mController.onPreferenceChange(
+                null,
                 mListValues[BluetoothSnoopLogPreferenceController.BTSNOOP_LOG_MODE_DISABLED_INDEX]);
         final String mode = SystemProperties.get(BLUETOOTH_BTSNOOP_LOG_MODE_PROPERTY);
         // "disabled" is hard-coded between Settings and system/bt
-        assertThat(mode).isEqualTo("disabled");
+        Assert.assertEquals(mode, "disabled");
     }
 
     @Test
@@ -119,20 +119,19 @@
         for (int i = 0; i < mListValues.length; ++i) {
             SystemProperties.set(BLUETOOTH_BTSNOOP_LOG_MODE_PROPERTY, mListValues[i].toString());
             mController.updateState(mPreference);
-            assertThat(mPreference.getValue()).isEqualTo(mListValues[i].toString());
-            assertThat(mPreference.getSummary()).isEqualTo(mListEntries[i].toString());
+            Assert.assertEquals(mPreference.getValue(), mListValues[i].toString());
+            Assert.assertEquals(mPreference.getSummary(), mListEntries[i].toString());
         }
     }
 
     @Test
     public void onDeveloperOptionsDisabled_shouldDisablePreference() {
         mController.onDeveloperOptionsDisabled();
-        assertThat(mPreference.isEnabled()).isFalse();
-        assertThat(mPreference.getValue()).isEqualTo(
-                mListValues[mController.getDefaultModeIndex()]
-                        .toString());
-        assertThat(mPreference.getSummary()).isEqualTo(
-                mListEntries[mController.getDefaultModeIndex()]
-                        .toString());
+        Assert.assertFalse(mPreference.isEnabled());
+        Assert.assertEquals(
+                mPreference.getValue(), mListValues[mController.getDefaultModeIndex()].toString());
+        Assert.assertEquals(
+                mPreference.getSummary(),
+                mListEntries[mController.getDefaultModeIndex()].toString());
     }
 }
diff --git a/tests/robotests/src/com/android/settings/development/DevelopmentMemtagPagePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/DevelopmentMemtagPagePreferenceControllerTest.java
new file mode 100644
index 0000000..7989682
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/DevelopmentMemtagPagePreferenceControllerTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2023 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.development;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import android.content.Context;
+import android.os.SystemProperties;
+
+import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowSystemProperties;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowRestrictedLockUtilsInternal.class})
+public class DevelopmentMemtagPagePreferenceControllerTest {
+    private final String mMemtagSupportedProperty = "ro.arm64.memtag.bootctl_supported";
+
+    private DevelopmentMemtagPagePreferenceController mController;
+    private Context mContext;
+
+    @Mock private DevelopmentSettingsDashboardFragment mFragment;
+    private static final String FRAGMENT_TAG = "memtag_page";
+
+    @Before
+    public void setUp() {
+        ShadowSystemProperties.override(mMemtagSupportedProperty, "true");
+
+        mContext = RuntimeEnvironment.application;
+        mController = new DevelopmentMemtagPagePreferenceController(mContext, mFragment);
+    }
+
+    @Test
+    public void onAvailable_sysPropEnabled() {
+        SystemProperties.set("ro.arm64.memtag.bootctl_supported", "1");
+        assertTrue(mController.isAvailable());
+    }
+
+    @Test
+    public void onAvailable_sysPropDisabled() {
+        SystemProperties.set("ro.arm64.memtag.bootctl_supported", "0");
+        assertFalse(mController.isAvailable());
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/development/DevelopmentMemtagPageTest.java b/tests/robotests/src/com/android/settings/development/DevelopmentMemtagPageTest.java
new file mode 100644
index 0000000..39dc48e
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/DevelopmentMemtagPageTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2023 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.development;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+
+import com.android.settings.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class DevelopmentMemtagPageTest {
+    private DevelopmentMemtagPage mMemtagPage;
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        mMemtagPage = new DevelopmentMemtagPage();
+        mContext = RuntimeEnvironment.application;
+    }
+
+    @Test
+    public void getMetricsCategory_isSETTINGS_MEMTAG_CATEGORY() {
+        assertThat(mMemtagPage.getMetricsCategory())
+                .isEqualTo(SettingsEnums.SETTINGS_MEMTAG_CATEGORY);
+    }
+
+    @Test
+    public void getPreferenceScreenResId_isMemtag_page() {
+        assertThat(mMemtagPage.getPreferenceScreenResId()).isEqualTo(R.xml.development_memtag_page);
+    }
+
+    @Test
+    public void SEARCH_INDEX_DATA_PROVIDERgetPreferenceControllers_isNotEmpty() {
+        assertThat(
+                        DevelopmentMemtagPage.SEARCH_INDEX_DATA_PROVIDER.getPreferenceControllers(
+                                mContext))
+                .isNotEmpty();
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/development/DevelopmentMemtagPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/DevelopmentMemtagPreferenceControllerTest.java
new file mode 100644
index 0000000..d4af470
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/DevelopmentMemtagPreferenceControllerTest.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2023 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.development;
+
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
+import static androidx.test.espresso.matcher.RootMatchers.isDialog;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.os.Bundle;
+
+import androidx.fragment.app.FragmentActivity;
+import androidx.fragment.app.FragmentContainerView;
+import androidx.test.rule.ActivityTestRule;
+
+import com.android.settings.R;
+import com.android.settings.security.ZygoteShadow;
+import com.android.settings.testutils.shadow.ShadowDeviceConfig;
+import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal;
+import com.android.settingslib.RestrictedSwitchPreference;
+import com.android.settingslib.testutils.shadow.ShadowInteractionJankMonitor;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowSystemProperties;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(
+        shadows = {
+            ZygoteShadow.class,
+            ShadowDeviceConfig.class,
+            ShadowInteractionJankMonitor.class,
+            ShadowRestrictedLockUtilsInternal.class
+        })
+public class DevelopmentMemtagPreferenceControllerTest {
+    private final String mMemtagSupportedProperty = "ro.arm64.memtag.bootctl_supported";
+
+    @Rule
+    public ActivityTestRule<TestActivity> mActivityTestRule =
+            new ActivityTestRule<>(TestActivity.class);
+
+    private DevelopmentMemtagPage mMemtagPage;
+    private DevelopmentMemtagPreferenceController mController;
+    private Context mContext;
+    private TestActivity mActivity;
+
+    private static final String FRAGMENT_TAG = "development_memtag_page";
+
+    @Before
+    public void setUp() {
+        ShadowSystemProperties.override(mMemtagSupportedProperty, "true");
+
+        mContext = RuntimeEnvironment.application;
+        mMemtagPage = new DevelopmentMemtagPage();
+        mActivity = mActivityTestRule.getActivity();
+        mActivity
+                .getSupportFragmentManager()
+                .beginTransaction()
+                .add(TestActivity.CONTAINER_VIEW_ID, mMemtagPage)
+                .commit();
+        mController = new DevelopmentMemtagPreferenceController(mContext, FRAGMENT_TAG);
+        mController.setFragment(mMemtagPage);
+    }
+
+    @Test
+    public void getSliceHighlightMenuRes_isMenu_key_security() {
+        assertThat(mController.getSliceHighlightMenuRes()).isEqualTo(R.string.menu_key_security);
+    }
+
+    @Test
+    public void setChecked_isChecked_updatesSummary() {
+        ZygoteShadow.setSupportsMemoryTagging(true);
+        mController.setChecked(true);
+        assertThat(mController.getSummary())
+                .isEqualTo(mContext.getResources().getString(R.string.memtag_on));
+    }
+
+    @Test
+    public void setChecked_isUnchecked_updatesSummary() {
+        ZygoteShadow.setSupportsMemoryTagging(false);
+        mController.setChecked(false);
+        assertThat(mController.getSummary())
+                .isEqualTo(mContext.getResources().getString(R.string.memtag_off));
+    }
+
+    @Test
+    public void setChecked_isCheckedPending_updatesSummary() {
+        ZygoteShadow.setSupportsMemoryTagging(false);
+        mController.setChecked(true);
+        assertThat(mController.getSummary())
+                .isEqualTo(mContext.getResources().getString(R.string.memtag_on_pending));
+    }
+
+    @Test
+    public void setChecked_isUncheckedPending_updatesSummary() {
+        ZygoteShadow.setSupportsMemoryTagging(true);
+        mController.setChecked(false);
+        assertThat(mController.getSummary())
+                .isEqualTo(mContext.getResources().getString(R.string.memtag_off_pending));
+    }
+
+    @Test
+    public void setChecked_isCheckedPending_showsDialog() {
+        ZygoteShadow.setSupportsMemoryTagging(false);
+        mController.setChecked(true);
+        onView(withText(R.string.memtag_reboot_title)).inRoot(isDialog());
+    }
+
+    @Test
+    public void setChecked_isUncheckedPending_showsDialog() {
+        ZygoteShadow.setSupportsMemoryTagging(true);
+        mController.setChecked(false);
+        onView(withText(R.string.memtag_reboot_title)).inRoot(isDialog());
+    }
+
+    @Test
+    public void setChecked_isChecked_doesNotShowDialog() {
+        ZygoteShadow.setSupportsMemoryTagging(false);
+        mController.setChecked(false);
+        onView(withText(R.string.memtag_reboot_title)).inRoot(isDialog()).check(doesNotExist());
+    }
+
+    @Test
+    public void setChecked_isUnchecked_doesNotShowDialog() {
+        ZygoteShadow.setSupportsMemoryTagging(true);
+        mController.setChecked(true);
+        onView(withText(R.string.memtag_reboot_title)).inRoot(isDialog()).check(doesNotExist());
+    }
+
+    @Test
+    public void updateState_disabledByAdmin_disablesPreference() {
+        ShadowRestrictedLockUtilsInternal.setMteIsDisabled(true);
+        RestrictedSwitchPreference preference = new RestrictedSwitchPreference(mContext);
+        mController.updateState(preference);
+        assertThat(preference.isDisabledByAdmin()).isTrue();
+    }
+
+    private static final class TestActivity extends FragmentActivity {
+        private static final int CONTAINER_VIEW_ID = 1234;
+
+        @Override
+        protected void onCreate(Bundle bundle) {
+            super.onCreate(bundle);
+
+            FragmentContainerView contentView = new FragmentContainerView(this);
+            contentView.setId(CONTAINER_VIEW_ID);
+            setContentView(contentView);
+        }
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/development/RebootWithMtePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/RebootWithMtePreferenceControllerTest.java
index d6b1031..f1e7d3f 100644
--- a/tests/robotests/src/com/android/settings/development/RebootWithMtePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/RebootWithMtePreferenceControllerTest.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.os.SystemProperties;
 
+import androidx.fragment.app.Fragment;
 import androidx.preference.Preference;
 import androidx.test.core.app.ApplicationProvider;
 
@@ -42,14 +43,15 @@
 public class RebootWithMtePreferenceControllerTest {
     private Context mContext;
     private RebootWithMtePreferenceController mController;
-    @Mock private DevelopmentSettingsDashboardFragment mSettings;
+    @Mock private Fragment mFragment;
 
     @Before
     public void setup() throws Exception {
         MockitoAnnotations.initMocks(this);
 
         mContext = ApplicationProvider.getApplicationContext();
-        mController = new RebootWithMtePreferenceController(mContext, mSettings);
+        mController = new RebootWithMtePreferenceController(mContext);
+        mController.setFragment(mFragment);
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/development/snooplogger/SnoopLoggerFiltersDashboardTest.java b/tests/robotests/src/com/android/settings/development/snooplogger/SnoopLoggerFiltersDashboardTest.java
new file mode 100644
index 0000000..40c34bf
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/snooplogger/SnoopLoggerFiltersDashboardTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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.development.snooplogger;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.settings.SettingsEnums;
+
+import com.android.settings.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class SnoopLoggerFiltersDashboardTest {
+
+    private SnoopLoggerFiltersDashboard mDashboard;
+
+    @Before
+    public void setUp() {
+        mDashboard = new SnoopLoggerFiltersDashboard();
+    }
+
+    @Test
+    public void shouldNotHaveHelpResource() {
+        assertThat(mDashboard.getHelpResource()).isEqualTo(0);
+    }
+
+    @Test
+    public void shouldLogAsSnoopLoggerFiltersPage() {
+        assertThat(mDashboard.getMetricsCategory())
+                .isEqualTo(SettingsEnums.SETTINGS_SNOOP_LOGGER_DASHBOARD);
+    }
+
+    @Test
+    public void shouldUseSnoopLoggerFiltersPreferenceLayout() {
+        assertThat(mDashboard.getPreferenceScreenResId())
+                .isEqualTo(R.xml.snoop_logger_filters_settings);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/development/snooplogger/SnoopLoggerFiltersPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/snooplogger/SnoopLoggerFiltersPreferenceControllerTest.java
new file mode 100644
index 0000000..f96ada0
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/snooplogger/SnoopLoggerFiltersPreferenceControllerTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2017 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.development.snooplogger;
+
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.sysprop.BluetoothProperties;
+
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceScreen;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class SnoopLoggerFiltersPreferenceControllerTest {
+
+    @Mock
+    private PreferenceScreen mScreen;
+    @Mock
+    private PreferenceCategory mCategory;
+    private Context mContext;
+    private SnoopLoggerFiltersPreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+        mController = new SnoopLoggerFiltersPreferenceController(mContext, "test_key");
+        when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mCategory);
+        when(mCategory.getContext()).thenReturn(mContext);
+        mController.displayPreference(mScreen);
+    }
+
+    @Test
+    public void getAvailability_debug_available() {
+        BluetoothProperties.snoop_log_mode(BluetoothProperties.snoop_log_mode_values.FILTERED);
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+    }
+
+    @Test
+    public void getAvailability_user_unavailable() {
+        BluetoothProperties.snoop_log_mode(BluetoothProperties.snoop_log_mode_values.DISABLED);
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING);
+    }
+
+    @Test
+    public void onStart_shouldRefreshFilters() {
+        mController.displayPreference(mScreen);
+
+        verify(mCategory, atLeastOnce()).addPreference(any(SnoopLoggerFiltersPreference.class));
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/development/snooplogger/SnoopLoggerFiltersPreferenceTest.java b/tests/robotests/src/com/android/settings/development/snooplogger/SnoopLoggerFiltersPreferenceTest.java
new file mode 100644
index 0000000..56f29ba
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/snooplogger/SnoopLoggerFiltersPreferenceTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.development.snooplogger;
+
+import android.content.Context;
+
+import com.android.settings.R;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class SnoopLoggerFiltersPreferenceTest {
+
+    private static String sKEY;
+    private static String sENTRY;
+
+    private Context mContext;
+    private SnoopLoggerFiltersPreference mPreference;
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+        sKEY = mContext.getResources().getStringArray(R.array.bt_hci_snoop_log_filters_values)[0];
+        sENTRY =
+                mContext.getResources().getStringArray(R.array.bt_hci_snoop_log_filters_entries)[0];
+        mPreference = new SnoopLoggerFiltersPreference(mContext, sKEY, sENTRY);
+    }
+
+    @Test
+    public void constructor_shouldSetTitle() {
+        Assert.assertEquals(mPreference.getTitle(), sENTRY);
+        Assert.assertFalse(mPreference.isChecked());
+    }
+
+    @Test
+    public void setChecked_shouldSetChecked() {
+        mPreference.setChecked(true);
+        Assert.assertTrue(mPreference.isChecked());
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/security/ZygoteShadow.java b/tests/robotests/src/com/android/settings/security/ZygoteShadow.java
index 23b30fa..c7b11c3 100644
--- a/tests/robotests/src/com/android/settings/security/ZygoteShadow.java
+++ b/tests/robotests/src/com/android/settings/security/ZygoteShadow.java
@@ -25,7 +25,7 @@
 public class ZygoteShadow {
     private static boolean sSupportsMemoryTagging;
 
-    static void setSupportsMemoryTagging(boolean value) {
+    public static void setSupportsMemoryTagging(boolean value) {
         sSupportsMemoryTagging = value;
     }
 
diff --git a/tests/unit/src/com/android/settings/TestingSettingsTest.java b/tests/unit/src/com/android/settings/TestingSettingsTest.java
new file mode 100644
index 0000000..1f4e385
--- /dev/null
+++ b/tests/unit/src/com/android/settings/TestingSettingsTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2023 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;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.UserManager;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class TestingSettingsTest {
+
+    @Mock
+    private UserManager mUserManager;
+    @Mock
+    private TestingSettings mTestingSettings;
+
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(ApplicationProvider.getApplicationContext());
+    }
+
+    @Test
+    public void isRadioInfoVisible_returnFalse_whenUserRestricted() {
+        mockService(mContext, Context.USER_SERVICE, UserManager.class, mUserManager);
+
+        doReturn(true).when(mUserManager).isAdminUser();
+        doReturn(false).when(mUserManager).isGuestUser();
+        doReturn(true).when(mUserManager)
+                .hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
+
+        assertThat(mTestingSettings.isRadioInfoVisible(mContext)).isFalse();
+    }
+
+    private <T> void mockService(Context context, String serviceName,
+            Class<T> serviceClass, T service) {
+         when(context.getSystemServiceName(serviceClass)).thenReturn(serviceName);
+         when(context.getSystemService(serviceName)).thenReturn(service);
+     }
+}
diff --git a/tests/unit/src/com/android/settings/dashboard/CategoryManagerTest.java b/tests/unit/src/com/android/settings/dashboard/CategoryManagerTest.java
index 98540f9..26ba856 100644
--- a/tests/unit/src/com/android/settings/dashboard/CategoryManagerTest.java
+++ b/tests/unit/src/com/android/settings/dashboard/CategoryManagerTest.java
@@ -22,6 +22,8 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.when;
+
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
@@ -32,6 +34,7 @@
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
+import com.android.settings.safetycenter.SafetyCenterManagerWrapper;
 import com.android.settingslib.drawer.ActivityTile;
 import com.android.settingslib.drawer.CategoryKey;
 import com.android.settingslib.drawer.DashboardCategory;
@@ -41,6 +44,8 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -54,8 +59,11 @@
     private Map<Pair<String, String>, Tile> mTileByComponentCache;
     private Map<String, DashboardCategory> mCategoryByKeyMap;
 
+    @Mock private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper;
+
     @Before
     public void setUp() {
+        MockitoAnnotations.initMocks(this);
         mContext = ApplicationProvider.getApplicationContext();
         mActivityInfo = new ActivityInfo();
         mActivityInfo.packageName = "pkg";
@@ -64,6 +72,7 @@
         mTileByComponentCache = new HashMap<>();
         mCategoryByKeyMap = new HashMap<>();
         mCategoryManager = CategoryManager.get(mContext);
+        SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper;
     }
 
     @Test
@@ -132,6 +141,90 @@
     }
 
     @Test
+    public void mergeSecurityPrivacyKeys_safetyCenterEnabled_shouldNotChangeOtherKeys() {
+        when(mSafetyCenterManagerWrapper.isEnabled(mContext)).thenReturn(true);
+
+        final Tile tile1 = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_ACCOUNT);
+        final String oldCategory = "com.android.settings.category.wireless";
+        final Tile tile2 = new ActivityTile(mActivityInfo, oldCategory);
+        final DashboardCategory category1 = new DashboardCategory(CategoryKey.CATEGORY_ACCOUNT);
+        category1.addTile(tile1);
+        final DashboardCategory category2 = new DashboardCategory(oldCategory);
+        category2.addTile(tile2);
+        mCategoryByKeyMap.put(CategoryKey.CATEGORY_ACCOUNT, category1);
+        mCategoryByKeyMap.put(oldCategory, category2);
+        mTileByComponentCache.put(new Pair<>("PACKAGE", "CLASS1"), tile1);
+        mTileByComponentCache.put(new Pair<>("PACKAGE", "CLASS2"), tile2);
+
+        mCategoryManager.mergeSecurityPrivacyKeys(
+                mContext, mTileByComponentCache, mCategoryByKeyMap);
+
+        assertThat(mCategoryByKeyMap.size()).isEqualTo(2);
+        assertThat(mCategoryByKeyMap.get(CategoryKey.CATEGORY_ACCOUNT).getTilesCount())
+                .isEqualTo(1);
+        assertThat(mCategoryByKeyMap.get(oldCategory).getTilesCount()).isEqualTo(1);
+        assertThat(mCategoryByKeyMap.get(CategoryKey.CATEGORY_MORE_SECURITY_PRIVACY_SETTINGS))
+                .isNull();
+    }
+
+    @Test
+    public void mergeSecurityPrivacyKeys_safetyCenterEnabled_shouldChangeSecurityPrivacyKeys() {
+        when(mSafetyCenterManagerWrapper.isEnabled(mContext)).thenReturn(true);
+
+        final Tile tileWithSecurityCategory =
+                new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_SECURITY_ADVANCED_SETTINGS);
+        final Tile tileWithPrivacyCategory =
+                new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_PRIVACY);
+        final DashboardCategory categoryAdvancedSecurity =
+                new DashboardCategory(CategoryKey.CATEGORY_SECURITY_ADVANCED_SETTINGS);
+        categoryAdvancedSecurity.addTile(tileWithSecurityCategory);
+        final DashboardCategory categoryPrivacy =
+                new DashboardCategory(CategoryKey.CATEGORY_PRIVACY);
+        categoryPrivacy.addTile(tileWithPrivacyCategory);
+        mCategoryByKeyMap.put(
+                CategoryKey.CATEGORY_SECURITY_ADVANCED_SETTINGS, categoryAdvancedSecurity);
+        mCategoryByKeyMap.put(CategoryKey.CATEGORY_PRIVACY, categoryPrivacy);
+        mTileByComponentCache.put(new Pair<>("PACKAGE", "CLASS1"), tileWithSecurityCategory);
+        mTileByComponentCache.put(new Pair<>("PACKAGE", "CLASS2"), tileWithPrivacyCategory);
+
+        mCategoryManager.mergeSecurityPrivacyKeys(
+                mContext, mTileByComponentCache, mCategoryByKeyMap);
+
+        assertThat(
+                        mCategoryByKeyMap
+                                .get(CategoryKey.CATEGORY_MORE_SECURITY_PRIVACY_SETTINGS)
+                                .getTilesCount())
+                .isEqualTo(2);
+    }
+
+    @Test
+    public void mergeSecurityPrivacyKeys_safetyCenterDisabled_shouldNotChangeSecurityPrivacyKeys() {
+        when(mSafetyCenterManagerWrapper.isEnabled(mContext)).thenReturn(false);
+
+        final Tile tileWithSecurityCategory =
+                new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_SECURITY_ADVANCED_SETTINGS);
+        final Tile tileWithPrivacyCategory =
+                new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_PRIVACY);
+        final DashboardCategory categoryAdvancedSecurity =
+                new DashboardCategory(CategoryKey.CATEGORY_SECURITY_ADVANCED_SETTINGS);
+        categoryAdvancedSecurity.addTile(tileWithSecurityCategory);
+        final DashboardCategory categoryPrivacy =
+                new DashboardCategory(CategoryKey.CATEGORY_PRIVACY);
+        categoryPrivacy.addTile(tileWithPrivacyCategory);
+        mCategoryByKeyMap.put(
+                CategoryKey.CATEGORY_SECURITY_ADVANCED_SETTINGS, categoryAdvancedSecurity);
+        mCategoryByKeyMap.put(CategoryKey.CATEGORY_PRIVACY, categoryPrivacy);
+        mTileByComponentCache.put(new Pair<>("PACKAGE", "CLASS1"), tileWithSecurityCategory);
+        mTileByComponentCache.put(new Pair<>("PACKAGE", "CLASS2"), tileWithPrivacyCategory);
+
+        mCategoryManager.mergeSecurityPrivacyKeys(
+                mContext, mTileByComponentCache, mCategoryByKeyMap);
+
+        assertThat(mCategoryByKeyMap.get(CategoryKey.CATEGORY_MORE_SECURITY_PRIVACY_SETTINGS))
+                .isNull();
+    }
+
+    @Test
     public void sortCategories_singlePackage_shouldReorderBasedOnPriority() {
         // Create some fake tiles that are not sorted.
         final String testPackage = "com.android.test";
diff --git a/tests/unit/src/com/android/settings/nearby/FastPairPreferenceControllerTest.java b/tests/unit/src/com/android/settings/nearby/FastPairPreferenceControllerTest.java
deleted file mode 100644
index f06be4b..0000000
--- a/tests/unit/src/com/android/settings/nearby/FastPairPreferenceControllerTest.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.nearby;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.spy;
-
-import android.content.Context;
-import android.os.Looper;
-
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-public class FastPairPreferenceControllerTest {
-
-    private Context mContext;
-    private FastPairPreferenceController mController;
-
-    @Before
-    public void setUp() {
-        mContext = spy(ApplicationProvider.getApplicationContext());
-        mController = new FastPairPreferenceController(mContext);
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-    }
-
-    @Test
-    public void isAvailable_shouldBeTrue() {
-        assertThat(mController.isAvailable()).isTrue();
-    }
-}
diff --git a/tests/unit/src/com/android/settings/nearby/FastPairSettingsFragmentTest.java b/tests/unit/src/com/android/settings/nearby/FastPairSettingsFragmentTest.java
deleted file mode 100644
index faabe8f..0000000
--- a/tests/unit/src/com/android/settings/nearby/FastPairSettingsFragmentTest.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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.nearby;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.app.Instrumentation;
-import android.app.settings.SettingsEnums;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.platform.app.InstrumentationRegistry;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-public class FastPairSettingsFragmentTest {
-
-    private FastPairSettingsFragment mFragment;
-
-    @Before
-    public void setUp() {
-        final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
-        instrumentation.runOnMainSync(() -> mFragment = new FastPairSettingsFragment());
-    }
-
-    @Test
-    public void getCategoryKey_isNetwork() {
-        assertThat(mFragment.getMetricsCategory())
-                .isEqualTo(SettingsEnums.CONNECTION_DEVICE_ADVANCED_FAST_PAIR);
-    }
-}