Merge "Remove biometrics for work from more settings"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 5d32022..a5271f9 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] -->
diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml
index 82d7e43..abbc101 100644
--- a/res/xml/development_settings.xml
+++ b/res/xml/development_settings.xml
@@ -80,6 +80,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/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/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/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
index 8ff2336..0bdccfb 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) {
@@ -548,7 +560,11 @@
         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/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/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/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/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/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/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/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/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/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);
+     }
+}