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)
+ }
+}