Merge "Refactor AutomaticDataSwitchingPreference" into main
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 800c6440..fbce181 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -10864,6 +10864,12 @@
     <!-- Preference label for the Audio storage section. [CHAR LIMIT=50] -->
     <string name="storage_audio">Audio</string>
 
+    <!-- Preference label for the Documents storage section. [CHAR LIMIT=50] -->
+    <string name="storage_documents">Documents</string>
+
+    <!-- Preference label for the Other storage section. [CHAR LIMIT=50] -->
+    <string name="storage_other">Other</string>
+
     <!-- Preference label for the Apps storage section. [CHAR LIMIT=50] -->
     <string name="storage_apps">Apps</string>
 
diff --git a/src/com/android/settings/TrustedCredentialsFragment.java b/src/com/android/settings/TrustedCredentialsFragment.java
index a150850..fc8fea3 100644
--- a/src/com/android/settings/TrustedCredentialsFragment.java
+++ b/src/com/android/settings/TrustedCredentialsFragment.java
@@ -17,6 +17,7 @@
 package com.android.settings;
 
 import static android.app.admin.DevicePolicyResources.Strings.Settings.PERSONAL_CATEGORY_HEADER;
+import static android.app.admin.DevicePolicyResources.Strings.Settings.PRIVATE_CATEGORY_HEADER;
 import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_CATEGORY_HEADER;
 import static android.widget.LinearLayout.LayoutParams.MATCH_PARENT;
 import static android.widget.LinearLayout.LayoutParams.WRAP_CONTENT;
@@ -108,18 +109,37 @@
             mKeyChainConnectionByProfileId = new SparseArray<>();
     private ViewGroup mFragmentView;
 
-    private final BroadcastReceiver mWorkProfileChangedReceiver = new BroadcastReceiver() {
+    private final BroadcastReceiver mProfileChangedReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (Intent.ACTION_MANAGED_PROFILE_AVAILABLE.equals(action)
-                    || Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action)
-                    || Intent.ACTION_MANAGED_PROFILE_UNLOCKED.equals(action)) {
+            if (isBroadcastValidForAction(intent)) {
                 mGroupAdapter.load();
             }
         }
     };
 
+    private boolean isBroadcastValidForAction(Intent intent) {
+        String action = intent.getAction();
+        if (android.os.Flags.allowPrivateProfile()
+                && android.multiuser.Flags.enablePrivateSpaceFeatures()
+                && android.multiuser.Flags.handleInterleavedSettingsForPrivateSpace()) {
+            UserHandle userHandle = intent.getParcelableExtra(Intent.EXTRA_USER, UserHandle.class);
+            if (userHandle == null) {
+                Log.w(TAG, "received action " + action + " with missing user extra");
+                return false;
+            }
+
+            UserInfo userInfo = mUserManager.getUserInfo(userHandle.getIdentifier());
+            return (Intent.ACTION_PROFILE_AVAILABLE.equals(action)
+                    || Intent.ACTION_PROFILE_UNAVAILABLE.equals(action)
+                    || Intent.ACTION_PROFILE_ACCESSIBLE.equals(action))
+                    && (userInfo.isManagedProfile() || userInfo.isPrivateProfile());
+        }
+        return (Intent.ACTION_MANAGED_PROFILE_AVAILABLE.equals(action)
+                || Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action)
+                || Intent.ACTION_MANAGED_PROFILE_UNLOCKED.equals(action));
+    }
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -142,10 +162,18 @@
         }
 
         IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
-        filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
-        filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNLOCKED);
-        activity.registerReceiver(mWorkProfileChangedReceiver, filter);
+        if (android.os.Flags.allowPrivateProfile()
+                && android.multiuser.Flags.enablePrivateSpaceFeatures()
+                && android.multiuser.Flags.handleInterleavedSettingsForPrivateSpace()) {
+            filter.addAction(Intent.ACTION_PROFILE_AVAILABLE);
+            filter.addAction(Intent.ACTION_PROFILE_UNAVAILABLE);
+            filter.addAction(Intent.ACTION_PROFILE_ACCESSIBLE);
+        } else {
+            filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
+            filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
+            filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNLOCKED);
+        }
+        activity.registerReceiver(mProfileChangedReceiver, filter);
     }
 
     @Override
@@ -177,7 +205,16 @@
 
     private void createChildView(
             LayoutInflater inflater, ViewGroup parent, Bundle childState, int i) {
-        boolean isWork = mGroupAdapter.getUserInfoByGroup(i).isManagedProfile();
+        UserInfo userInfo = mGroupAdapter.getUserInfoByGroup(i);
+        if (Utils.shouldHideUser(userInfo.getUserHandle(), mUserManager)) {
+            return;
+        }
+        boolean isProfile = userInfo.isManagedProfile();
+        if (android.os.Flags.allowPrivateProfile()
+                && android.multiuser.Flags.enablePrivateSpaceFeatures()
+                && android.multiuser.Flags.handleInterleavedSettingsForPrivateSpace()) {
+            isProfile |= userInfo.isPrivateProfile();
+        }
         ChildAdapter adapter = mGroupAdapter.createChildAdapter(i);
 
         LinearLayout containerView = (LinearLayout) inflater.inflate(
@@ -186,9 +223,9 @@
 
         int profilesSize = mGroupAdapter.getGroupCount();
         adapter.showHeader(profilesSize > 1);
-        adapter.showDivider(isWork);
-        adapter.setExpandIfAvailable(profilesSize <= 2 || !isWork, childState);
-        if (isWork) {
+        adapter.showDivider(isProfile);
+        adapter.setExpandIfAvailable(profilesSize <= 2 || !isProfile, childState);
+        if (isProfile) {
             parent.addView(containerView);
         } else {
             parent.addView(containerView, 0);
@@ -203,7 +240,7 @@
 
     @Override
     public void onDestroy() {
-        getActivity().unregisterReceiver(mWorkProfileChangedReceiver);
+        getActivity().unregisterReceiver(mProfileChangedReceiver);
         for (AdapterData.AliasLoader aliasLoader : mAliasLoaders) {
             aliasLoader.cancel(true);
         }
@@ -331,9 +368,16 @@
             }
 
             TextView title = convertView.findViewById(android.R.id.title);
-            if (getUserInfoByGroup(groupPosition).isManagedProfile()) {
+            UserInfo userInfo = getUserInfoByGroup(groupPosition);
+            if (userInfo.isManagedProfile()) {
                 title.setText(mDevicePolicyManager.getResources().getString(WORK_CATEGORY_HEADER,
                         () -> getString(com.android.settingslib.R.string.category_work)));
+            } else if (android.os.Flags.allowPrivateProfile()
+                    && android.multiuser.Flags.enablePrivateSpaceFeatures()
+                    && android.multiuser.Flags.handleInterleavedSettingsForPrivateSpace()
+                    && userInfo.isPrivateProfile()) {
+                title.setText(mDevicePolicyManager.getResources().getString(PRIVATE_CATEGORY_HEADER,
+                        () -> getString(com.android.settingslib.R.string.category_private)));
             } else {
                 title.setText(mDevicePolicyManager.getResources().getString(
                         PERSONAL_CATEGORY_HEADER,
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index c38ebfe..c4b0014 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -1365,6 +1365,16 @@
         }
     }
 
+    /**
+     * Returns true if the user should be hidden in Settings when it's in quiet mode.
+     */
+    public static boolean shouldHideUser(
+            @NonNull UserHandle userHandle, @NonNull UserManager userManager) {
+        UserProperties userProperties = userManager.getUserProperties(userHandle);
+        return userProperties.getShowInQuietMode() == UserProperties.SHOW_IN_QUIET_MODE_HIDDEN
+                && userManager.isQuietModeEnabled(userHandle);
+    }
+
     private static FaceManager.RemovalCallback faceManagerRemovalCallback(int userId) {
         return new FaceManager.RemovalCallback() {
             @Override
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsSpatialAudioController.java b/src/com/android/settings/bluetooth/BluetoothDetailsSpatialAudioController.java
index e5fb365..30e86fe 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsSpatialAudioController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsSpatialAudioController.java
@@ -18,6 +18,7 @@
 
 import static android.media.Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE;
 
+import android.app.settings.SettingsEnums;
 import android.content.Context;
 import android.media.AudioDeviceAttributes;
 import android.media.AudioDeviceInfo;
@@ -60,6 +61,7 @@
     AudioDeviceAttributes mAudioDevice = null;
 
     AtomicBoolean mHasHeadTracker = new AtomicBoolean(false);
+    AtomicBoolean mInitialRefresh = new AtomicBoolean(true);
 
     public BluetoothDetailsSpatialAudioController(
             Context context,
@@ -81,6 +83,10 @@
         TwoStatePreference switchPreference = (TwoStatePreference) preference;
         String key = switchPreference.getKey();
         if (TextUtils.equals(key, KEY_SPATIAL_AUDIO)) {
+            mMetricsFeatureProvider.action(
+                    mContext,
+                    SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_SPATIAL_AUDIO_TOGGLE_CLICKED,
+                    switchPreference.isChecked());
             updateSpatializerEnabled(switchPreference.isChecked());
             ThreadUtils.postOnBackgroundThread(
                     () -> {
@@ -91,6 +97,10 @@
                     });
             return true;
         } else if (TextUtils.equals(key, KEY_HEAD_TRACKING)) {
+            mMetricsFeatureProvider.action(
+                    mContext,
+                    SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_HEAD_TRACKING_TOGGLE_CLICKED,
+                    switchPreference.isChecked());
             updateSpatializerHeadTracking(switchPreference.isChecked());
             return true;
         } else {
@@ -186,6 +196,20 @@
         if (isHeadTrackingAvailable) {
             headTrackingPref.setChecked(mSpatializer.isHeadTrackerEnabled(mAudioDevice));
         }
+
+        if (mInitialRefresh.compareAndSet(true, false)) {
+            // Only triggered when shown for the first time
+            mMetricsFeatureProvider.action(
+                    mContext,
+                    SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_SPATIAL_AUDIO_TRIGGERED,
+                    spatialAudioPref.isChecked());
+            if (mHasHeadTracker.get()) {
+                mMetricsFeatureProvider.action(
+                        mContext,
+                        SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_HEAD_TRACKING_TRIGGERED,
+                        headTrackingPref.isChecked());
+            }
+        }
     }
 
     @VisibleForTesting
diff --git a/src/com/android/settings/connecteddevice/stylus/StylusDevicesController.java b/src/com/android/settings/connecteddevice/stylus/StylusDevicesController.java
index cd23103..7fbaf3c 100644
--- a/src/com/android/settings/connecteddevice/stylus/StylusDevicesController.java
+++ b/src/com/android/settings/connecteddevice/stylus/StylusDevicesController.java
@@ -214,7 +214,7 @@
                 Intent intent = new Intent(Intent.ACTION_MANAGE_DEFAULT_APP).setPackage(
                         packageName).putExtra(Intent.EXTRA_ROLE_NAME, RoleManager.ROLE_NOTES);
 
-                List<UserHandle> users = getUserAndManagedProfiles();
+                List<UserHandle> users = getUserProfiles();
                 if (users.size() <= 1) {
                     mContext.startActivity(intent);
                 } else {
@@ -311,22 +311,23 @@
         return inputMethod != null && inputMethod.supportsStylusHandwriting();
     }
 
-    private List<UserHandle> getUserAndManagedProfiles() {
+    private List<UserHandle> getUserProfiles() {
         UserManager um = mContext.getSystemService(UserManager.class);
-        final List<UserHandle> userManagedProfiles = new ArrayList<>();
-        // Add the current user, then add all the associated managed profiles.
         final UserHandle currentUser = Process.myUserHandle();
-        userManagedProfiles.add(currentUser);
+        final List<UserHandle> userProfiles = new ArrayList<>();
+        userProfiles.add(currentUser);
 
-        final List<UserInfo> userInfos = um.getUsers();
-        for (UserInfo info : userInfos) {
-            int userId = info.id;
-            if (um.isManagedProfile(userId)
-                    && um.getProfileParent(userId).id == currentUser.getIdentifier()) {
-                userManagedProfiles.add(UserHandle.of(userId));
+        final List<UserInfo> userInfos = um.getProfiles(currentUser.getIdentifier());
+        for (UserInfo userInfo : userInfos) {
+            if (userInfo.isManagedProfile()
+                    || (android.os.Flags.allowPrivateProfile()
+                        && android.multiuser.Flags.enablePrivateSpaceFeatures()
+                        && android.multiuser.Flags.handleInterleavedSettingsForPrivateSpace()
+                        && userInfo.isPrivateProfile())) {
+                userProfiles.add(userInfo.getUserHandle());
             }
         }
-        return userManagedProfiles;
+        return userProfiles;
     }
 
     private UserHandle getDefaultNoteTaskProfile() {
diff --git a/src/com/android/settings/dashboard/profileselector/ProfileSelectDialog.java b/src/com/android/settings/dashboard/profileselector/ProfileSelectDialog.java
index 4df1fdd..b276a39 100644
--- a/src/com/android/settings/dashboard/profileselector/ProfileSelectDialog.java
+++ b/src/com/android/settings/dashboard/profileselector/ProfileSelectDialog.java
@@ -25,7 +25,6 @@
 import android.content.DialogInterface.OnShowListener;
 import android.content.Intent;
 import android.content.pm.UserInfo;
-import android.content.pm.UserProperties;
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -42,6 +41,7 @@
 import com.android.internal.widget.LinearLayoutManager;
 import com.android.internal.widget.RecyclerView;
 import com.android.settings.R;
+import com.android.settings.Utils;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.drawer.Tile;
 
@@ -186,7 +186,7 @@
             UserInfo userInfo = userManager.getUserInfo(userHandles.get(i).getIdentifier());
             if (userInfo == null
                     || userInfo.isCloneProfile()
-                    || shouldHideUserInQuietMode(userHandles.get(i), userManager)) {
+                    || Utils.shouldHideUser(userHandles.get(i), userManager)) {
                 if (DEBUG) {
                     Log.d(TAG, "Delete the user: " + userHandles.get(i).getIdentifier());
                 }
@@ -219,7 +219,7 @@
             UserInfo userInfo = userManager.getUserInfo(userHandle.getIdentifier());
             if (userInfo == null
                     || userInfo.isCloneProfile()
-                    || shouldHideUserInQuietMode(userHandle, userManager)) {
+                    || Utils.shouldHideUser(userHandle, userManager)) {
                 if (DEBUG) {
                     Log.d(TAG, "Delete the user: " + userHandle.getIdentifier());
                 }
@@ -228,11 +228,4 @@
             }
         }
     }
-
-    private static boolean shouldHideUserInQuietMode(
-            UserHandle userHandle, UserManager userManager) {
-        UserProperties userProperties = userManager.getUserProperties(userHandle);
-        return userProperties.getShowInQuietMode() == UserProperties.SHOW_IN_QUIET_MODE_HIDDEN
-                && userManager.isQuietModeEnabled(userHandle);
-    }
 }
diff --git a/src/com/android/settings/dashboard/profileselector/UserAdapter.java b/src/com/android/settings/dashboard/profileselector/UserAdapter.java
index 40d1a93..0fefa2f 100644
--- a/src/com/android/settings/dashboard/profileselector/UserAdapter.java
+++ b/src/com/android/settings/dashboard/profileselector/UserAdapter.java
@@ -64,7 +64,11 @@
             UserInfo userInfo = um.getUserInfo(mUserHandle.getIdentifier());
             int tintColor = Utils.getColorAttrDefaultColor(context,
                     com.android.internal.R.attr.materialColorPrimary);
-            if (userInfo.isManagedProfile()) {
+            if (userInfo.isManagedProfile()
+                    || (android.os.Flags.allowPrivateProfile()
+                        && android.multiuser.Flags.enablePrivateSpaceFeatures()
+                        && android.multiuser.Flags.handleInterleavedSettingsForPrivateSpace()
+                        && userInfo.isPrivateProfile())) {
                 mIcon = context.getPackageManager().getUserBadgeForDensityNoBackground(
                         userHandle, /* density= */ 0);
                 mIcon.setTint(tintColor);
@@ -88,6 +92,7 @@
                         () -> context.getString(com.android.settingslib.R.string.category_work));
             } else if (android.os.Flags.allowPrivateProfile()
                     && android.multiuser.Flags.enablePrivateSpaceFeatures()
+                    && android.multiuser.Flags.handleInterleavedSettingsForPrivateSpace()
                     && mUserManager.getUserInfo(userId).isPrivateProfile()) {
                 return resources.getString(PRIVATE_CATEGORY_HEADER,
                         () -> context.getString(com.android.settingslib.R.string.category_private));
@@ -209,6 +214,7 @@
 
     private static UserAdapter createUserAdapter(
             UserManager userManager, Context context, List<UserHandle> userProfiles) {
+        updateUserHandlesIfNeeded(userManager, userProfiles);
         ArrayList<UserDetails> userDetails = new ArrayList<>(userProfiles.size());
         for (UserHandle userProfile : userProfiles) {
             userDetails.add(new UserDetails(userProfile, userManager, context));
@@ -216,6 +222,15 @@
         return new UserAdapter(context, userDetails);
     }
 
+    private static void updateUserHandlesIfNeeded(
+            UserManager userManager, List<UserHandle> userProfiles) {
+        for (int i = userProfiles.size() - 1; i >= 0; --i) {
+            if (com.android.settings.Utils.shouldHideUser(userProfiles.get(i), userManager)) {
+                userProfiles.remove(i);
+            }
+        }
+    }
+
     static class ViewHolder extends RecyclerView.ViewHolder {
         private final ImageView mIconView;
         private final TextView mTitleView;
diff --git a/src/com/android/settings/network/apn/ApnNetworkTypeCheckBox.kt b/src/com/android/settings/network/apn/ApnNetworkTypeCheckBox.kt
index bc85f55..a42031b 100644
--- a/src/com/android/settings/network/apn/ApnNetworkTypeCheckBox.kt
+++ b/src/com/android/settings/network/apn/ApnNetworkTypeCheckBox.kt
@@ -24,18 +24,13 @@
 
 @Composable
 fun ApnNetworkTypeCheckBox(apnData: ApnData, onNetworkTypeChanged: (Long) -> Unit) {
-    val options = remember { ApnNetworkTypes.getNetworkTypeOptions() }
-    val selectedStateMap = remember {
-        ApnNetworkTypes.networkTypeToSelectedStateMap(options, apnData.networkType)
-    }
+    val options = remember { ApnNetworkTypes.getNetworkTypeOptions(apnData.networkType) }
     SettingsDropdownCheckBox(
         label = stringResource(R.string.network_type),
         options = options,
         emptyText = stringResource(R.string.network_type_unspecified),
         enabled = apnData.networkTypeEnabled,
     ) {
-        onNetworkTypeChanged(
-            ApnNetworkTypes.selectedStateMapToNetworkType(options, selectedStateMap)
-        )
+        onNetworkTypeChanged(ApnNetworkTypes.optionsToNetworkType(options))
     }
 }
diff --git a/src/com/android/settings/network/apn/ApnNetworkTypes.kt b/src/com/android/settings/network/apn/ApnNetworkTypes.kt
index e7a93b3..f14b0b3 100644
--- a/src/com/android/settings/network/apn/ApnNetworkTypes.kt
+++ b/src/com/android/settings/network/apn/ApnNetworkTypes.kt
@@ -17,8 +17,7 @@
 package com.android.settings.network.apn
 
 import android.telephony.TelephonyManager
-import androidx.compose.runtime.mutableStateMapOf
-import androidx.compose.runtime.snapshots.SnapshotStateMap
+import androidx.compose.runtime.mutableStateOf
 import com.android.settingslib.spa.widget.editor.SettingsDropdownCheckOption
 
 object ApnNetworkTypes {
@@ -40,38 +39,28 @@
         TelephonyManager.NETWORK_TYPE_NR,
     )
 
-    fun getNetworkTypeOptions(): List<SettingsDropdownCheckOption> =
-        Types.map { SettingsDropdownCheckOption(TelephonyManager.getNetworkTypeName(it)) }
-
     /**
      * Gets the selected Network type Selected Options according to network type.
      * @param networkType Initialized network type bitmask, often multiple network type options may
      *                    be included.
      */
-    fun networkTypeToSelectedStateMap(
-        options: List<SettingsDropdownCheckOption>,
-        networkType: Long,
-    ): SnapshotStateMap<SettingsDropdownCheckOption, Boolean> {
-        val stateMap = mutableStateMapOf<SettingsDropdownCheckOption, Boolean>()
-        Types.forEachIndexed { index, type ->
-            if (networkType and TelephonyManager.getBitMaskForNetworkType(type) != 0L) {
-                stateMap[options[index]] = true
-            }
+    fun getNetworkTypeOptions(networkType: Long): List<SettingsDropdownCheckOption> =
+        Types.map { type ->
+            val selected = networkType and TelephonyManager.getBitMaskForNetworkType(type) != 0L
+            SettingsDropdownCheckOption(
+                text = TelephonyManager.getNetworkTypeName(type),
+                selected = mutableStateOf(selected),
+            )
         }
-        return stateMap
-    }
 
     /**
      * Gets the network type according to the selected Network type Selected Options.
-     * @param stateMap the selected Network type Selected Options.
+     * @param options the selected Network type Selected Options.
      */
-    fun selectedStateMapToNetworkType(
-        options: List<SettingsDropdownCheckOption>,
-        stateMap: SnapshotStateMap<SettingsDropdownCheckOption, Boolean>,
-    ): Long {
+    fun optionsToNetworkType(options: List<SettingsDropdownCheckOption>): Long {
         var networkType = 0L
         options.forEachIndexed { index, option ->
-            if (stateMap[option] == true) {
+            if (option.selected.value) {
                 networkType = networkType or TelephonyManager.getBitMaskForNetworkType(Types[index])
             }
         }
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsSpatialAudioControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsSpatialAudioControllerTest.java
index 2cc55a7..d9a917b 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsSpatialAudioControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsSpatialAudioControllerTest.java
@@ -25,6 +25,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.settings.SettingsEnums;
 import android.bluetooth.BluetoothDevice;
 import android.media.AudioDeviceAttributes;
 import android.media.AudioDeviceInfo;
@@ -34,8 +35,11 @@
 import androidx.preference.PreferenceCategory;
 import androidx.preference.TwoStatePreference;
 
+import com.android.settings.testutils.FakeFeatureFactory;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 
+import com.google.common.collect.ImmutableList;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -55,36 +59,37 @@
     private static final String KEY_SPATIAL_AUDIO = "spatial_audio";
     private static final String KEY_HEAD_TRACKING = "head_tracking";
 
-    @Mock
-    private AudioManager mAudioManager;
-    @Mock
-    private Spatializer mSpatializer;
-    @Mock
-    private Lifecycle mSpatialAudioLifecycle;
-    @Mock
-    private PreferenceCategory mProfilesContainer;
-    @Mock
-    private BluetoothDevice mBluetoothDevice;
+    @Mock private AudioManager mAudioManager;
+    @Mock private Spatializer mSpatializer;
+    @Mock private Lifecycle mSpatialAudioLifecycle;
+    @Mock private PreferenceCategory mProfilesContainer;
+    @Mock private BluetoothDevice mBluetoothDevice;
 
     private AudioDeviceAttributes mAvailableDevice;
 
     private BluetoothDetailsSpatialAudioController mController;
     private TwoStatePreference mSpatialAudioPref;
     private TwoStatePreference mHeadTrackingPref;
+    private FakeFeatureFactory mFeatureFactory;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
         mContext = spy(RuntimeEnvironment.application);
+        mFeatureFactory = FakeFeatureFactory.setupForTest();
+
         when(mContext.getSystemService(AudioManager.class)).thenReturn(mAudioManager);
         when(mAudioManager.getSpatializer()).thenReturn(mSpatializer);
         when(mCachedDevice.getAddress()).thenReturn(MAC_ADDRESS);
         when(mCachedDevice.getDevice()).thenReturn(mBluetoothDevice);
         when(mBluetoothDevice.getAnonymizedAddress()).thenReturn(MAC_ADDRESS);
+        when(mFeatureFactory.getBluetoothFeatureProvider().getSpatializer(mContext))
+                .thenReturn(mSpatializer);
 
-        mController = new BluetoothDetailsSpatialAudioController(mContext, mFragment,
-                mCachedDevice, mSpatialAudioLifecycle);
+        mController =
+                new BluetoothDetailsSpatialAudioController(
+                        mContext, mFragment, mCachedDevice, mSpatialAudioLifecycle);
         mController.mProfilesContainer = mProfilesContainer;
 
         mSpatialAudioPref = mController.createSpatialAudioPreference(mContext);
@@ -93,10 +98,11 @@
         when(mProfilesContainer.findPreference(KEY_SPATIAL_AUDIO)).thenReturn(mSpatialAudioPref);
         when(mProfilesContainer.findPreference(KEY_HEAD_TRACKING)).thenReturn(mHeadTrackingPref);
 
-        mAvailableDevice = new AudioDeviceAttributes(
-                AudioDeviceAttributes.ROLE_OUTPUT,
-                AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
-                MAC_ADDRESS);
+        mAvailableDevice =
+                new AudioDeviceAttributes(
+                        AudioDeviceAttributes.ROLE_OUTPUT,
+                        AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
+                        MAC_ADDRESS);
     }
 
     @Test
@@ -107,8 +113,8 @@
 
     @Test
     public void isAvailable_forSpatializerWithLevelNotNone_returnsTrue() {
-        when(mSpatializer.getImmersiveAudioLevel()).thenReturn(
-                SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL);
+        when(mSpatializer.getImmersiveAudioLevel())
+                .thenReturn(SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL);
         assertThat(mController.isAvailable()).isTrue();
     }
 
@@ -151,29 +157,77 @@
     }
 
     @Test
-    public void
-            refresh_spatialAudioOnAndHeadTrackingIsNotAvailable_hidesHeadTrackingPreference() {
-        List<AudioDeviceAttributes> compatibleAudioDevices = new ArrayList<>();
+    public void refresh_spatialAudioOnHeadTrackingOff_recordMetrics() {
         mController.setAvailableDevice(mAvailableDevice);
-        compatibleAudioDevices.add(mController.mAudioDevice);
-        when(mSpatializer.getCompatibleAudioDevices()).thenReturn(compatibleAudioDevices);
-        when(mSpatializer.hasHeadTracker(mController.mAudioDevice)).thenReturn(false);
+        when(mSpatializer.isAvailableForDevice(mAvailableDevice)).thenReturn(true);
+        when(mSpatializer.getCompatibleAudioDevices())
+                .thenReturn(ImmutableList.of(mAvailableDevice));
+        when(mSpatializer.hasHeadTracker(mAvailableDevice)).thenReturn(true);
+        when(mSpatializer.isHeadTrackerEnabled(mController.mAudioDevice)).thenReturn(false);
 
         mController.refresh();
         ShadowLooper.idleMainLooper();
 
-        verify(mProfilesContainer).removePreference(mHeadTrackingPref);
+        verify(mFeatureFactory.metricsFeatureProvider)
+                .action(
+                        mContext,
+                        SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_SPATIAL_AUDIO_TRIGGERED,
+                        true);
+        verify(mFeatureFactory.metricsFeatureProvider)
+                .action(
+                        mContext,
+                        SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_HEAD_TRACKING_TRIGGERED,
+                        false);
+    }
+
+    @Test
+    public void refresh_spatialAudioOff_recordMetrics() {
+        mController.setAvailableDevice(mAvailableDevice);
+        when(mSpatializer.isAvailableForDevice(mAvailableDevice)).thenReturn(true);
+        when(mSpatializer.getCompatibleAudioDevices()).thenReturn(ImmutableList.of());
+        when(mSpatializer.hasHeadTracker(mAvailableDevice)).thenReturn(true);
+        when(mSpatializer.isHeadTrackerEnabled(mController.mAudioDevice)).thenReturn(false);
+
+        mController.refresh();
+        ShadowLooper.idleMainLooper();
+
+        verify(mFeatureFactory.metricsFeatureProvider)
+                .action(
+                        mContext,
+                        SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_SPATIAL_AUDIO_TRIGGERED,
+                        false);
+        verify(mFeatureFactory.metricsFeatureProvider)
+                .action(
+                        mContext,
+                        SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_HEAD_TRACKING_TRIGGERED,
+                        false);
+    }
+
+    @Test
+    public void refresh_spatialAudioOnAndHeadTrackingIsNotAvailable_hidesHeadTrackingPreference() {
+        mController.setAvailableDevice(mAvailableDevice);
+        when(mSpatializer.isAvailableForDevice(mAvailableDevice)).thenReturn(true);
+        when(mSpatializer.getCompatibleAudioDevices())
+                .thenReturn(ImmutableList.of(mAvailableDevice));
+        when(mSpatializer.hasHeadTracker(mAvailableDevice)).thenReturn(false);
+
+        mController.refresh();
+        ShadowLooper.idleMainLooper();
+
+        assertThat(mHeadTrackingPref.isVisible()).isFalse();
     }
 
     @Test
     public void refresh_spatialAudioOff_hidesHeadTrackingPreference() {
-        List<AudioDeviceAttributes> compatibleAudioDevices = new ArrayList<>();
-        when(mSpatializer.getCompatibleAudioDevices()).thenReturn(compatibleAudioDevices);
+        mController.setAvailableDevice(mAvailableDevice);
+        when(mSpatializer.isAvailableForDevice(mAvailableDevice)).thenReturn(true);
+        when(mSpatializer.getCompatibleAudioDevices()).thenReturn(ImmutableList.of());
+        when(mSpatializer.hasHeadTracker(mAvailableDevice)).thenReturn(true);
 
         mController.refresh();
         ShadowLooper.idleMainLooper();
 
-        verify(mProfilesContainer).removePreference(mHeadTrackingPref);
+        assertThat(mHeadTrackingPref.isVisible()).isFalse();
     }
 
     @Test
@@ -190,6 +244,11 @@
         ShadowLooper.idleMainLooper();
 
         assertThat(mHeadTrackingPref.isChecked()).isTrue();
+        verify(mFeatureFactory.metricsFeatureProvider)
+                .action(
+                        mContext,
+                        SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_HEAD_TRACKING_TRIGGERED,
+                        true);
     }
 
     @Test
@@ -206,6 +265,11 @@
         ShadowLooper.idleMainLooper();
 
         assertThat(mHeadTrackingPref.isChecked()).isFalse();
+        verify(mFeatureFactory.metricsFeatureProvider)
+                .action(
+                        mContext,
+                        SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_HEAD_TRACKING_TRIGGERED,
+                        false);
     }
 
     @Test
@@ -214,6 +278,11 @@
         mSpatialAudioPref.setChecked(true);
         mController.onPreferenceClick(mSpatialAudioPref);
         verify(mSpatializer).addCompatibleAudioDevice(mController.mAudioDevice);
+        verify(mFeatureFactory.metricsFeatureProvider)
+                .action(
+                        mContext,
+                        SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_SPATIAL_AUDIO_TOGGLE_CLICKED,
+                        true);
     }
 
     @Test
@@ -222,6 +291,11 @@
         mSpatialAudioPref.setChecked(false);
         mController.onPreferenceClick(mSpatialAudioPref);
         verify(mSpatializer).removeCompatibleAudioDevice(mController.mAudioDevice);
+        verify(mFeatureFactory.metricsFeatureProvider)
+                .action(
+                        mContext,
+                        SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_SPATIAL_AUDIO_TOGGLE_CLICKED,
+                        false);
     }
 
     @Test
@@ -230,6 +304,11 @@
         mHeadTrackingPref.setChecked(true);
         mController.onPreferenceClick(mHeadTrackingPref);
         verify(mSpatializer).setHeadTrackerEnabled(true, mController.mAudioDevice);
+        verify(mFeatureFactory.metricsFeatureProvider)
+                .action(
+                        mContext,
+                        SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_HEAD_TRACKING_TOGGLE_CLICKED,
+                        true);
     }
 
     @Test
@@ -238,5 +317,10 @@
         mHeadTrackingPref.setChecked(false);
         mController.onPreferenceClick(mHeadTrackingPref);
         verify(mSpatializer).setHeadTrackerEnabled(false, mController.mAudioDevice);
+        verify(mFeatureFactory.metricsFeatureProvider)
+                .action(
+                        mContext,
+                        SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_HEAD_TRACKING_TOGGLE_CLICKED,
+                        false);
     }
 }
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDevicesControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDevicesControllerTest.java
index 6c96f85..c1cbf17 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDevicesControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDevicesControllerTest.java
@@ -41,9 +41,12 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
+import android.content.pm.UserProperties;
+import android.graphics.drawable.Drawable;
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.Settings;
 import android.provider.Settings.Secure;
 import android.view.InputDevice;
@@ -64,6 +67,7 @@
 import com.android.settingslib.core.lifecycle.Lifecycle;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -77,8 +81,12 @@
 
 @RunWith(RobolectricTestRunner.class)
 public class StylusDevicesControllerTest {
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
     private static final String NOTES_PACKAGE_NAME = "notes.package";
     private static final CharSequence NOTES_APP_LABEL = "App Label";
+    private static final int WORK_USER_ID = 1;
+    private static final int PRIVATE_USER_ID = 2;
 
     private Context mContext;
     private StylusDevicesController mController;
@@ -95,6 +103,12 @@
     @Mock
     private UserManager mUserManager;
     @Mock
+    UserInfo mPersonalUserInfo;
+    @Mock
+    UserInfo mWorkUserInfo;
+    @Mock
+    UserInfo mPrivateUserInfo;
+    @Mock
     private RoleManager mRm;
     @Mock
     private Lifecycle mLifecycle;
@@ -102,6 +116,8 @@
     private CachedBluetoothDevice mCachedBluetoothDevice;
     @Mock
     private BluetoothDevice mBluetoothDevice;
+    @Mock
+    private Drawable mIcon;
 
     @Before
     public void setUp() throws Exception {
@@ -134,6 +150,7 @@
         when(mPm.getApplicationInfo(eq(NOTES_PACKAGE_NAME),
                 any(PackageManager.ApplicationInfoFlags.class))).thenReturn(new ApplicationInfo());
         when(mPm.getApplicationLabel(any(ApplicationInfo.class))).thenReturn(NOTES_APP_LABEL);
+        when(mPm.getUserBadgeForDensityNoBackground(any(), anyInt())).thenReturn(mIcon);
         when(mUserManager.getUsers()).thenReturn(Arrays.asList(new UserInfo(0, "default", 0)));
         when(mUserManager.isManagedProfile(anyInt())).thenReturn(false);
 
@@ -371,14 +388,26 @@
         final String permissionPackageName = "permissions.package";
         final UserHandle currentUser = Process.myUserHandle();
         List<UserInfo> userInfos = Arrays.asList(
-                new UserInfo(currentUser.getIdentifier(), "current", 0),
-                new UserInfo(1, "profile", UserInfo.FLAG_PROFILE)
+                mPersonalUserInfo,
+                mWorkUserInfo
         );
-        when(mUserManager.getUsers()).thenReturn(userInfos);
-        when(mUserManager.isManagedProfile(1)).thenReturn(true);
-        when(mUserManager.getUserInfo(currentUser.getIdentifier())).thenReturn(userInfos.get(0));
-        when(mUserManager.getUserInfo(1)).thenReturn(userInfos.get(1));
-        when(mUserManager.getProfileParent(1)).thenReturn(userInfos.get(0));
+        UserProperties personalUserProperties =
+                new UserProperties.Builder()
+                        .setShowInQuietMode(UserProperties.SHOW_IN_QUIET_MODE_DEFAULT)
+                        .build();
+        UserProperties workUserProperties =
+                new UserProperties.Builder()
+                        .setShowInQuietMode(UserProperties.SHOW_IN_QUIET_MODE_PAUSED)
+                        .build();
+        when(mWorkUserInfo.isManagedProfile()).thenReturn(true);
+        when(mWorkUserInfo.getUserHandle()).thenReturn(UserHandle.of(WORK_USER_ID));
+        when(mUserManager.getProfiles(currentUser.getIdentifier())).thenReturn(userInfos);
+        when(mUserManager.getUserInfo(currentUser.getIdentifier())).thenReturn(mPersonalUserInfo);
+        when(mUserManager.getUserInfo(WORK_USER_ID)).thenReturn(mWorkUserInfo);
+        when(mUserManager.getProfileParent(WORK_USER_ID)).thenReturn(mPersonalUserInfo);
+        when(mUserManager.getUserProperties(currentUser)).thenReturn(personalUserProperties);
+        when(mUserManager.getUserProperties(UserHandle.of(WORK_USER_ID)))
+                .thenReturn(workUserProperties);
         when(mPm.getPermissionControllerPackageName()).thenReturn(permissionPackageName);
 
         showScreen(mController);
@@ -389,7 +418,55 @@
     }
 
     @Test
-    public void defaultNotesPreferenceClick_noManagedProfile_sendsManageDefaultRoleIntent() {
+    public void defaultNotesPreferenceClick_multiUsers_showsProfileSelectorDialog() {
+        mSetFlagsRule.enableFlags(
+                android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
+                android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES,
+                android.multiuser.Flags.FLAG_HANDLE_INTERLEAVED_SETTINGS_FOR_PRIVATE_SPACE);
+        mContext.setTheme(androidx.appcompat.R.style.Theme_AppCompat);
+        final String permissionPackageName = "permissions.package";
+        final UserHandle currentUser = Process.myUserHandle();
+        List<UserInfo> userInfos = Arrays.asList(
+                mPersonalUserInfo,
+                mPrivateUserInfo,
+                mWorkUserInfo
+        );
+        UserProperties personalUserProperties =
+                new UserProperties.Builder()
+                        .setShowInQuietMode(UserProperties.SHOW_IN_QUIET_MODE_DEFAULT)
+                        .build();
+        UserProperties workUserProperties =
+                new UserProperties.Builder()
+                        .setShowInQuietMode(UserProperties.SHOW_IN_QUIET_MODE_PAUSED)
+                        .build();
+        UserProperties privateUserProperties =
+                new UserProperties.Builder()
+                        .setShowInQuietMode(UserProperties.SHOW_IN_QUIET_MODE_HIDDEN)
+                        .build();
+        when(mWorkUserInfo.isManagedProfile()).thenReturn(true);
+        when(mWorkUserInfo.getUserHandle()).thenReturn(UserHandle.of(WORK_USER_ID));
+        when(mPrivateUserInfo.isPrivateProfile()).thenReturn(true);
+        when(mPrivateUserInfo.getUserHandle()).thenReturn(UserHandle.of(PRIVATE_USER_ID));
+        when(mUserManager.getProfiles(currentUser.getIdentifier())).thenReturn(userInfos);
+        when(mUserManager.getUserInfo(currentUser.getIdentifier())).thenReturn(mPersonalUserInfo);
+        when(mUserManager.getUserInfo(WORK_USER_ID)).thenReturn(mWorkUserInfo);
+        when(mUserManager.getUserInfo(PRIVATE_USER_ID)).thenReturn(mPrivateUserInfo);
+        when(mUserManager.getUserProperties(currentUser)).thenReturn(personalUserProperties);
+        when(mUserManager.getUserProperties(UserHandle.of(PRIVATE_USER_ID)))
+                .thenReturn(privateUserProperties);
+        when(mUserManager.getUserProperties(UserHandle.of(WORK_USER_ID)))
+                .thenReturn(workUserProperties);
+        when(mPm.getPermissionControllerPackageName()).thenReturn(permissionPackageName);
+
+        showScreen(mController);
+        Preference defaultNotesPref = mPreferenceContainer.getPreference(0);
+        mController.onPreferenceClick(defaultNotesPref);
+
+        assertTrue(mController.mDialog.isShowing());
+    }
+
+    @Test
+    public void defaultNotesPreferenceClick_noProfiles_sendsManageDefaultRoleIntent() {
         final ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
         mContext.setTheme(androidx.appcompat.R.style.Theme_AppCompat);
         final String permissionPackageName = "permissions.package";
@@ -398,7 +475,7 @@
                 new UserInfo(currentUser.getIdentifier(), "current", 0),
                 new UserInfo(1, "other", UserInfo.FLAG_FULL)
         );
-        when(mUserManager.getUsers()).thenReturn(userInfos);
+        when(mUserManager.getProfiles(currentUser.getIdentifier())).thenReturn(userInfos);
         when(mUserManager.isManagedProfile(1)).thenReturn(false);
         when(mUserManager.getUserInfo(currentUser.getIdentifier())).thenReturn(userInfos.get(0));
         when(mUserManager.getUserInfo(1)).thenReturn(userInfos.get(1));
diff --git a/tests/robotests/src/com/android/settings/dashboard/profileselector/UserAdapterTest.java b/tests/robotests/src/com/android/settings/dashboard/profileselector/UserAdapterTest.java
index 2fb5e03..b6ac410 100644
--- a/tests/robotests/src/com/android/settings/dashboard/profileselector/UserAdapterTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/profileselector/UserAdapterTest.java
@@ -24,8 +24,10 @@
 
 import android.content.Context;
 import android.content.pm.UserInfo;
+import android.content.pm.UserProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.widget.FrameLayout;
 import android.widget.TextView;
 
@@ -52,9 +54,12 @@
 public class UserAdapterTest {
     @Rule
     public MockitoRule mRule = MockitoJUnit.rule();
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
 
     private final int mPersonalUserId = UserHandle.myUserId();
     private static final int WORK_USER_ID = 1;
+    private static final int PRIVATE_USER_ID = 2;
 
     @Mock
     private UserManager mUserManager;
@@ -64,6 +69,8 @@
 
     @Mock
     private UserInfo mWorkUserInfo;
+    @Mock
+    private UserInfo mPrivateUserInfo;
 
     @Mock
     private UserAdapter.OnClickListener mOnClickListener;
@@ -71,11 +78,31 @@
     @Spy
     private Context mContext = ApplicationProvider.getApplicationContext();
 
+    private UserProperties mPersonalUserProperties =
+            new UserProperties.Builder()
+                    .setShowInQuietMode(UserProperties.SHOW_IN_QUIET_MODE_DEFAULT)
+                    .build();
+    private UserProperties mWorkUserProperties =
+            new UserProperties.Builder()
+                    .setShowInQuietMode(UserProperties.SHOW_IN_QUIET_MODE_PAUSED)
+                    .build();
+    private UserProperties mPrivateUserProperties =
+            new UserProperties.Builder()
+                    .setShowInQuietMode(UserProperties.SHOW_IN_QUIET_MODE_HIDDEN)
+                    .build();
+
     @Before
     public void setUp() {
         when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
         when(mUserManager.getUserInfo(mPersonalUserId)).thenReturn(mPersonalUserInfo);
         when(mUserManager.getUserInfo(WORK_USER_ID)).thenReturn(mWorkUserInfo);
+        when(mUserManager.getUserInfo(PRIVATE_USER_ID)).thenReturn(mPrivateUserInfo);
+        when(mUserManager.getUserProperties(UserHandle.of(mPersonalUserId)))
+                .thenReturn(mPersonalUserProperties);
+        when(mUserManager.getUserProperties(UserHandle.of(WORK_USER_ID)))
+                .thenReturn(mWorkUserProperties);
+        when(mUserManager.getUserProperties(UserHandle.of(PRIVATE_USER_ID)))
+                .thenReturn(mPrivateUserProperties);
     }
 
     @Test
@@ -103,6 +130,48 @@
     }
 
     @Test
+    public void createUserSpinnerAdapter_withWorkAndPrivateProfiles_shouldSucceed() {
+        mSetFlagsRule.enableFlags(
+                android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
+                android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES,
+                android.multiuser.Flags.FLAG_HANDLE_INTERLEAVED_SETTINGS_FOR_PRIVATE_SPACE);
+        when(mUserManager.getUserProfiles()).thenReturn(
+                Lists.newArrayList(
+                        UserHandle.of(mPersonalUserId),
+                        UserHandle.of(WORK_USER_ID),
+                        UserHandle.of(PRIVATE_USER_ID)));
+
+        UserAdapter userSpinnerAdapter =
+                UserAdapter.createUserSpinnerAdapter(mUserManager, mContext);
+
+        assertThat(userSpinnerAdapter.getCount()).isEqualTo(3);
+        assertThat(userSpinnerAdapter.getUserHandle(0).getIdentifier()).isEqualTo(mPersonalUserId);
+        assertThat(userSpinnerAdapter.getUserHandle(1).getIdentifier()).isEqualTo(WORK_USER_ID);
+        assertThat(userSpinnerAdapter.getUserHandle(2).getIdentifier()).isEqualTo(PRIVATE_USER_ID);
+    }
+
+    @Test
+    public void createUserSpinnerAdapter_withWorkAndQuietPrivateProfile_shouldShowTwoProfiles() {
+        mSetFlagsRule.enableFlags(
+                android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
+                android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES,
+                android.multiuser.Flags.FLAG_HANDLE_INTERLEAVED_SETTINGS_FOR_PRIVATE_SPACE);
+        when(mUserManager.getUserProfiles()).thenReturn(
+                Lists.newArrayList(
+                        UserHandle.of(mPersonalUserId),
+                        UserHandle.of(WORK_USER_ID),
+                        UserHandle.of(PRIVATE_USER_ID)));
+        when(mUserManager.isQuietModeEnabled(UserHandle.of(PRIVATE_USER_ID))).thenReturn(true);
+
+        UserAdapter userSpinnerAdapter =
+                UserAdapter.createUserSpinnerAdapter(mUserManager, mContext);
+
+        assertThat(userSpinnerAdapter.getCount()).isEqualTo(2);
+        assertThat(userSpinnerAdapter.getUserHandle(0).getIdentifier()).isEqualTo(mPersonalUserId);
+        assertThat(userSpinnerAdapter.getUserHandle(1).getIdentifier()).isEqualTo(WORK_USER_ID);
+    }
+
+    @Test
     public void createUserRecycleViewAdapter_canBindViewHolderCorrectly() {
         ArrayList<UserHandle> userHandles =
                 Lists.newArrayList(UserHandle.of(mPersonalUserId), UserHandle.of(WORK_USER_ID));
diff --git a/tests/spa_unit/src/com/android/settings/network/apn/ApnNetworkTypesTest.kt b/tests/spa_unit/src/com/android/settings/network/apn/ApnNetworkTypesTest.kt
new file mode 100644
index 0000000..f8aed59
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/network/apn/ApnNetworkTypesTest.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.network.apn
+
+import android.telephony.TelephonyManager.NETWORK_TYPE_BITMASK_CDMA
+import android.telephony.TelephonyManager.NETWORK_TYPE_BITMASK_EDGE
+import android.telephony.TelephonyManager.NETWORK_TYPE_BITMASK_HSPAP
+import android.telephony.TelephonyManager.NETWORK_TYPE_BITMASK_HSUPA
+import androidx.compose.runtime.mutableStateOf
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.widget.editor.SettingsDropdownCheckOption
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class ApnNetworkTypesTest {
+
+    @Test
+    fun getNetworkTypeOptions() {
+        val networkTypeOptions =
+            ApnNetworkTypes.getNetworkTypeOptions(
+                NETWORK_TYPE_BITMASK_EDGE xor NETWORK_TYPE_BITMASK_CDMA
+            )
+
+        assertThat(networkTypeOptions.single { it.text == "EDGE" }.selected.value).isTrue()
+        assertThat(networkTypeOptions.single { it.text == "CDMA" }.selected.value).isTrue()
+        assertThat(networkTypeOptions.single { it.text == "GPRS" }.selected.value).isFalse()
+    }
+
+    @Test
+    fun optionsToNetworkType() {
+        val options = listOf(
+            SettingsDropdownCheckOption(text = "", selected = mutableStateOf(false)),
+            SettingsDropdownCheckOption(text = "", selected = mutableStateOf(true)),
+            SettingsDropdownCheckOption(text = "", selected = mutableStateOf(false)),
+            SettingsDropdownCheckOption(text = "", selected = mutableStateOf(true)),
+        )
+
+        val networkType = ApnNetworkTypes.optionsToNetworkType(options)
+
+        assertThat(networkType).isEqualTo(NETWORK_TYPE_BITMASK_HSPAP xor NETWORK_TYPE_BITMASK_HSUPA)
+    }
+}