Loading src/com/android/settings/users/UserDetailsSettings.java +43 −5 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import com.android.settings.Utils; import com.android.settings.core.SubSettingLauncher; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.RestrictedPreference; import java.util.List; Loading @@ -65,10 +66,13 @@ public class UserDetailsSettings extends SettingsPreferenceFragment private static final int DIALOG_CONFIRM_REMOVE = 1; private static final int DIALOG_CONFIRM_ENABLE_CALLING = 2; private static final int DIALOG_CONFIRM_ENABLE_CALLING_AND_SMS = 3; private static final int DIALOG_SETUP_USER = 4; private UserManager mUserManager; private UserCapabilities mUserCaps; @VisibleForTesting Preference mSwitchUserPref; RestrictedPreference mSwitchUserPref; private SwitchPreference mPhonePref; @VisibleForTesting Preference mAppAndContentAccessPref; Loading @@ -90,6 +94,7 @@ public class UserDetailsSettings extends SettingsPreferenceFragment final Context context = getActivity(); mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); mUserCaps = UserCapabilities.create(context); addPreferencesFromResource(R.xml.user_details_settings); initialize(context, getArguments()); Loading @@ -106,15 +111,20 @@ public class UserDetailsSettings extends SettingsPreferenceFragment if (preference == mRemoveUserPref) { if (canDeleteUser()) { showDialog(DIALOG_CONFIRM_REMOVE); } return true; } } else if (preference == mSwitchUserPref) { if (canSwitchUserNow()) { if (shouldShowSetupPromptDialog()) { showDialog(DIALOG_SETUP_USER); } else { switchUser(); } return true; } } else if (preference == mAppAndContentAccessPref) { openAppAndContentAccessScreen(false); return true; } return false; } Loading @@ -139,6 +149,8 @@ public class UserDetailsSettings extends SettingsPreferenceFragment return SettingsEnums.DIALOG_USER_ENABLE_CALLING; case DIALOG_CONFIRM_ENABLE_CALLING_AND_SMS: return SettingsEnums.DIALOG_USER_ENABLE_CALLING_AND_SMS; case DIALOG_SETUP_USER: return SettingsEnums.DIALOG_USER_SETUP; default: return 0; } Loading @@ -160,6 +172,13 @@ public class UserDetailsSettings extends SettingsPreferenceFragment case DIALOG_CONFIRM_ENABLE_CALLING_AND_SMS: return UserDialogs.createEnablePhoneCallsAndSmsDialog(getActivity(), (dialog, which) -> enableCallsAndSms(true)); case DIALOG_SETUP_USER: return UserDialogs.createSetupUserDialog(getActivity(), (dialog, which) -> { if (canSwitchUserNow()) { switchUser(); } }); } throw new IllegalArgumentException("Unsupported dialogId " + dialogId); } Loading Loading @@ -188,7 +207,14 @@ public class UserDetailsSettings extends SettingsPreferenceFragment mSwitchUserPref.setTitle( context.getString(com.android.settingslib.R.string.user_switch_to_user, mUserInfo.name)); if (mUserCaps.mDisallowSwitchUser) { mSwitchUserPref.setDisabledByAdmin(RestrictedLockUtilsInternal.getDeviceOwner(context)); } else { mSwitchUserPref.setDisabledByAdmin(null); mSwitchUserPref.setSelectable(true); mSwitchUserPref.setOnPreferenceClickListener(this); } if (!mUserManager.isAdminUser()) { // non admin users can't remove users and allow calls removePreference(KEY_ENABLE_TELEPHONY); Loading Loading @@ -321,4 +347,16 @@ public class UserDetailsSettings extends SettingsPreferenceFragment .setSourceMetricsCategory(getMetricsCategory()) .launch(); } private boolean isSecondaryUser(UserInfo user) { return UserManager.USER_TYPE_FULL_SECONDARY.equals(user.userType); } private boolean shouldShowSetupPromptDialog() { // TODO: FLAG_INITIALIZED is set when a user is switched to for the first time, // but what we would really need here is a flag that shows if the setup process was // completed. After the user cancels the setup process, mUserInfo.isInitialized() will // return true so there will be no setup prompt dialog shown to the user anymore. return isSecondaryUser(mUserInfo) && !mUserInfo.isInitialized(); } } src/com/android/settings/users/UserDialogs.java +17 −0 Original line number Diff line number Diff line Loading @@ -138,4 +138,21 @@ public final class UserDialogs { .setNegativeButton(android.R.string.cancel, null) .create(); } /** * Creates a dialog to confirm that the user is ok to start setting up a new user. * * @param onConfirmListener Callback object for positive action */ public static Dialog createSetupUserDialog(Context context, DialogInterface.OnClickListener onConfirmListener) { return new AlertDialog.Builder(context) .setTitle(com.android.settingslib.R.string.user_setup_dialog_title) .setMessage(com.android.settingslib.R.string.user_setup_dialog_message) .setPositiveButton(com.android.settingslib.R.string.user_setup_button_setup_now, onConfirmListener) .setNegativeButton(com.android.settingslib.R.string.user_setup_button_setup_later, null) .create(); } } src/com/android/settings/users/UserSettings.java +28 −116 Original line number Diff line number Diff line Loading @@ -102,8 +102,6 @@ public class UserSettings extends SettingsPreferenceFragment /** UserId of the user being removed */ private static final String SAVE_REMOVING_USER = "removing_user"; /** UserId of the user that was just added */ private static final String SAVE_ADDING_USER = "adding_user"; private static final String KEY_USER_LIST = "user_list"; private static final String KEY_USER_ME = "user_me"; Loading @@ -119,8 +117,7 @@ public class UserSettings extends SettingsPreferenceFragment private static final int DIALOG_CONFIRM_REMOVE = 1; private static final int DIALOG_ADD_USER = 2; private static final int DIALOG_SETUP_USER = 3; private static final int DIALOG_SETUP_PROFILE = 4; // Dialogs with id 3 and 4 got removed private static final int DIALOG_USER_CANNOT_MANAGE = 5; private static final int DIALOG_CHOOSE_USER_TYPE = 6; private static final int DIALOG_NEED_LOCKSCREEN = 7; Loading @@ -130,8 +127,7 @@ public class UserSettings extends SettingsPreferenceFragment private static final int DIALOG_USER_PROFILE_EDITOR_ADD_RESTRICTED_PROFILE = 11; private static final int MESSAGE_UPDATE_LIST = 1; private static final int MESSAGE_SETUP_USER = 2; private static final int MESSAGE_CONFIG_USER = 3; private static final int MESSAGE_USER_CREATED = 2; private static final int USER_TYPE_USER = 1; private static final int USER_TYPE_RESTRICTED_PROFILE = 2; Loading Loading @@ -160,7 +156,6 @@ public class UserSettings extends SettingsPreferenceFragment @VisibleForTesting SparseArray<Bitmap> mUserIcons = new SparseArray<>(); private int mRemovingUserId = -1; private int mAddedUserId = 0; private boolean mAddingUser; private String mAddingUserName; private UserCapabilities mUserCaps; Loading @@ -187,12 +182,9 @@ public class UserSettings extends SettingsPreferenceFragment case MESSAGE_UPDATE_LIST: updateUserList(); break; case MESSAGE_SETUP_USER: case MESSAGE_USER_CREATED: onUserCreated(msg.arg1); break; case MESSAGE_CONFIG_USER: onManageUserClicked(msg.arg1, true); break; } } }; Loading Loading @@ -254,9 +246,6 @@ public class UserSettings extends SettingsPreferenceFragment .setOnPreferenceChangeListener(mAddUserWhenLockedPreferenceController); if (icicle != null) { if (icicle.containsKey(SAVE_ADDING_USER)) { mAddedUserId = icicle.getInt(SAVE_ADDING_USER); } if (icicle.containsKey(SAVE_REMOVING_USER)) { mRemovingUserId = icicle.getInt(SAVE_REMOVING_USER); } Loading Loading @@ -334,7 +323,6 @@ public class UserSettings extends SettingsPreferenceFragment public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); mEditUserInfoController.onSaveInstanceState(outState); outState.putInt(SAVE_ADDING_USER, mAddedUserId); outState.putInt(SAVE_REMOVING_USER, mRemovingUserId); } Loading Loading @@ -482,15 +470,15 @@ public class UserSettings extends SettingsPreferenceFragment } } private void onManageUserClicked(int userId, boolean newUser) { private void onUserCreated(int userId) { mAddingUser = false; UserInfo userInfo = mUserManager.getUserInfo(userId); if (userId == UserHandle.myUserId()) { // Jump to owner info panel OwnerInfoSettings.show(this); } else { openUserDetails(userInfo, true); } private void openUserDetails(UserInfo userInfo, boolean newUser) { Bundle extras = new Bundle(); extras.putInt(UserDetailsSettings.EXTRA_USER_ID, userId); extras.putInt(UserDetailsSettings.EXTRA_USER_ID, userInfo.id); extras.putBoolean(AppRestrictionsFragment.EXTRA_NEW_USER, newUser); new SubSettingLauncher(getContext()) .setDestination(UserDetailsSettings.class.getName()) Loading @@ -499,21 +487,6 @@ public class UserSettings extends SettingsPreferenceFragment .setSourceMetricsCategory(getMetricsCategory()) .launch(); } } private void onUserCreated(int userId) { mAddedUserId = userId; mAddingUser = false; if (!isResumed()) { Log.w(TAG, "Cannot show dialog after onPause"); return; } if (mUserManager.getUserInfo(userId).isRestricted()) { showDialog(DIALOG_SETUP_PROFILE); } else { showDialog(DIALOG_SETUP_USER); } } @Override public void onDialogShowing() { Loading Loading @@ -571,37 +544,6 @@ public class UserSettings extends SettingsPreferenceFragment .create(); return dlg; } case DIALOG_SETUP_USER: { Dialog dlg = new AlertDialog.Builder(context) .setTitle(com.android.settingslib.R.string.user_setup_dialog_title) .setMessage(com.android.settingslib.R.string.user_setup_dialog_message) .setPositiveButton( com.android.settingslib.R.string.user_setup_button_setup_now, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { switchUserNow(mAddedUserId); } }) .setNegativeButton( com.android.settingslib.R.string.user_setup_button_setup_later, null) .create(); return dlg; } case DIALOG_SETUP_PROFILE: { Dialog dlg = new AlertDialog.Builder(context) .setMessage( com.android.settingslib.R.string.user_setup_profile_dialog_message) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { switchUserNow(mAddedUserId); } }) .setNegativeButton(android.R.string.cancel, null) .create(); return dlg; } case DIALOG_CHOOSE_USER_TYPE: { List<HashMap<String, String>> data = new ArrayList<HashMap<String, String>>(); HashMap<String, String> addUserItem = new HashMap<String, String>(); Loading Loading @@ -764,10 +706,6 @@ public class UserSettings extends SettingsPreferenceFragment return SettingsEnums.DIALOG_USER_CANNOT_MANAGE; case DIALOG_ADD_USER: return SettingsEnums.DIALOG_USER_ADD; case DIALOG_SETUP_USER: return SettingsEnums.DIALOG_USER_SETUP; case DIALOG_SETUP_PROFILE: return SettingsEnums.DIALOG_USER_SETUP_PROFILE; case DIALOG_CHOOSE_USER_TYPE: return SettingsEnums.DIALOG_USER_CHOOSE_TYPE; case DIALOG_NEED_LOCKSCREEN: Loading Loading @@ -853,16 +791,11 @@ public class UserSettings extends SettingsPreferenceFragment if (userType == USER_TYPE_USER) { mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST); // Skip setting up user which results in user switching when the // restriction is set. if (!mUserCaps.mDisallowSwitchUser) { mHandler.sendMessage(mHandler.obtainMessage( MESSAGE_SETUP_USER, user.id, user.serialNumber)); } } else { mHandler.sendMessage(mHandler.obtainMessage( MESSAGE_CONFIG_USER, user.id, user.serialNumber)); } MESSAGE_USER_CREATED, user.id, user.serialNumber)); mPendingUserIcon = null; mPendingUserName = null; } Loading @@ -870,18 +803,6 @@ public class UserSettings extends SettingsPreferenceFragment }); } private void switchUserNow(int userId) { if (!canSwitchUserNow()) { return; } try { ActivityManager.getService().switchUser(userId); } catch (RemoteException re) { Log.e(TAG, "Error while switching to other user."); } } /** * Erase the current user (guest) and switch to another user. */ Loading Loading @@ -1125,21 +1046,14 @@ public class UserSettings extends SettingsPreferenceFragment if (pref == mMePreference) { if (isCurrentUserGuest()) { showDialog(DIALOG_CONFIRM_EXIT_GUEST); return true; } showDialog(DIALOG_USER_PROFILE_EDITOR); } else if (pref instanceof UserPreference) { int userId = ((UserPreference) pref).getUserId(); // Get the latest status of the user UserInfo user = mUserManager.getUserInfo(userId); if (!user.isInitialized() && isSecondaryUser(user)) { // for uninitialized secondary users we should show a prompt dialog before // starting the setup mHandler.sendMessage(mHandler.obtainMessage( MESSAGE_SETUP_USER, user.id, user.serialNumber)); } else { onManageUserClicked(userId, false); showDialog(DIALOG_USER_PROFILE_EDITOR); } return true; } else if (pref instanceof UserPreference) { UserInfo userInfo = mUserManager.getUserInfo(((UserPreference) pref).getUserId()); openUserDetails(userInfo, false); return true; } else if (pref == mAddUser) { // If we allow both types, show a picker, otherwise directly go to // flow for full user. Loading @@ -1148,10 +1062,12 @@ public class UserSettings extends SettingsPreferenceFragment } else { onAddUserClicked(USER_TYPE_USER); } return true; } else if (pref == mAddGuest) { UserInfo guest = mUserManager.createGuest( getContext(), getString(com.android.settingslib.R.string.user_guest)); switchUserNow(guest.id); openUserDetails(guest, true); return true; } return false; } Loading Loading @@ -1265,8 +1181,4 @@ public class UserSettings extends SettingsPreferenceFragment return niks; } }; private boolean isSecondaryUser(UserInfo user) { return UserManager.USER_TYPE_FULL_SECONDARY.equals(user.userType); } } tests/robotests/src/com/android/settings/users/UserDetailsSettingsTest.java +35 −1 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.robolectric.Shadows.shadowOf; import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; Loading @@ -53,6 +54,8 @@ import com.android.settings.SettingsActivity; import com.android.settings.SubSettings; import com.android.settings.testutils.shadow.ShadowDevicePolicyManager; import com.android.settings.testutils.shadow.ShadowUserManager; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedPreference; import org.junit.After; import org.junit.Before; Loading Loading @@ -91,7 +94,7 @@ public class UserDetailsSettingsTest { private ShadowUserManager mUserManager; @Mock private Preference mSwitchUserPref; private RestrictedPreference mSwitchUserPref; @Mock private SwitchPreference mPhonePref; @Mock Loading @@ -101,6 +104,7 @@ public class UserDetailsSettingsTest { private FragmentActivity mActivity; private Context mContext; private UserCapabilities mUserCapabilities; private UserDetailsSettings mFragment; private Bundle mArguments; private UserInfo mUserInfo; Loading @@ -111,6 +115,8 @@ public class UserDetailsSettingsTest { mActivity = spy(ActivityController.of(new FragmentActivity()).get()); mContext = spy(RuntimeEnvironment.application); mUserCapabilities = UserCapabilities.create(mContext); mUserCapabilities.mUserSwitcherEnabled = true; mFragment = spy(new UserDetailsSettings()); mArguments = new Bundle(); Loading @@ -121,6 +127,7 @@ public class UserDetailsSettingsTest { doReturn(mTelephonyManager).when(mActivity).getSystemService(Context.TELEPHONY_SERVICE); ReflectionHelpers.setField(mFragment, "mUserManager", userManager); ReflectionHelpers.setField(mFragment, "mUserCaps", mUserCapabilities); doReturn(mActivity).when(mFragment).getActivity(); doReturn(mActivity).when(mFragment).getContext(); Loading Loading @@ -426,6 +433,33 @@ public class UserDetailsSettingsTest { verify(mPhonePref).setChecked(false); } @Test public void initialize_switchUserDisallowed_shouldSetAdminDisabledOnSwitchPreference() { setupSelectedUser(); mUserCapabilities.mDisallowSwitchUser = true; DevicePolicyManager devicePolicyManager = mock(DevicePolicyManager.class); doReturn(devicePolicyManager).when(mActivity) .getSystemService(Context.DEVICE_POLICY_SERVICE); doReturn(mock(ComponentName.class)).when(devicePolicyManager) .getDeviceOwnerComponentOnAnyUser(); mFragment.initialize(mActivity, mArguments); verify(mSwitchUserPref).setDisabledByAdmin(any(RestrictedLockUtils.EnforcedAdmin.class)); } @Test public void initialize_switchUserAllowed_shouldSetSwitchPreferenceEnabled() { setupSelectedUser(); mUserCapabilities.mDisallowSwitchUser = false; mFragment.initialize(mActivity, mArguments); verify(mSwitchUserPref).setDisabledByAdmin(null); verify(mSwitchUserPref).setSelectable(true); verify(mSwitchUserPref).setOnPreferenceClickListener(mFragment); } @Test public void onPreferenceClick_switchClicked_canSwitch_shouldSwitch() { setupSelectedUser(); Loading tests/robotests/src/com/android/settings/users/UserSettingsTest.java +30 −0 Original line number Diff line number Diff line Loading @@ -33,13 +33,16 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.robolectric.Shadows.shadowOf; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.UserInfo; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; Loading @@ -53,6 +56,8 @@ import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; import com.android.settings.SettingsActivity; import com.android.settings.SubSettings; import com.android.settings.testutils.shadow.ShadowDevicePolicyManager; import com.android.settings.testutils.shadow.ShadowUserManager; import com.android.settingslib.RestrictedLockUtils; Loading @@ -70,6 +75,7 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.android.controller.ActivityController; import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowIntent; import org.robolectric.util.ReflectionHelpers; import java.util.Arrays; Loading Loading @@ -589,6 +595,30 @@ public class UserSettingsTest { verify(mUserManager, times(2)).getUsers(true); } @Test public void onPreferenceClick_addGuestClicked_createGuestAndOpenDetails() { UserInfo createdGuest = getGuest(false); removeFlag(createdGuest, UserInfo.FLAG_INITIALIZED); doReturn(createdGuest).when(mUserManager).createGuest(mActivity, "Guest"); doReturn(mActivity).when(mFragment).getContext(); mFragment.onPreferenceClick(mAddGuestPreference); verify(mUserManager).createGuest(mActivity, "Guest"); Intent startedIntent = shadowOf(mActivity).getNextStartedActivity(); ShadowIntent shadowIntent = shadowOf(startedIntent); assertThat(shadowIntent.getIntentClass()).isEqualTo(SubSettings.class); assertThat(startedIntent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT)) .isEqualTo(UserDetailsSettings.class.getName()); Bundle arguments = startedIntent.getBundleExtra( SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS); assertThat(arguments).isNotNull(); assertThat(arguments.getInt(UserDetailsSettings.EXTRA_USER_ID, 0)) .isEqualTo(createdGuest.id); assertThat(arguments.getBoolean(AppRestrictionsFragment.EXTRA_NEW_USER, false)) .isEqualTo(true); } @Test public void getRealUsersCount_onlyAdmin_shouldCount() { givenUsers(getAdminUser(true)); Loading Loading
src/com/android/settings/users/UserDetailsSettings.java +43 −5 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import com.android.settings.Utils; import com.android.settings.core.SubSettingLauncher; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.RestrictedPreference; import java.util.List; Loading @@ -65,10 +66,13 @@ public class UserDetailsSettings extends SettingsPreferenceFragment private static final int DIALOG_CONFIRM_REMOVE = 1; private static final int DIALOG_CONFIRM_ENABLE_CALLING = 2; private static final int DIALOG_CONFIRM_ENABLE_CALLING_AND_SMS = 3; private static final int DIALOG_SETUP_USER = 4; private UserManager mUserManager; private UserCapabilities mUserCaps; @VisibleForTesting Preference mSwitchUserPref; RestrictedPreference mSwitchUserPref; private SwitchPreference mPhonePref; @VisibleForTesting Preference mAppAndContentAccessPref; Loading @@ -90,6 +94,7 @@ public class UserDetailsSettings extends SettingsPreferenceFragment final Context context = getActivity(); mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); mUserCaps = UserCapabilities.create(context); addPreferencesFromResource(R.xml.user_details_settings); initialize(context, getArguments()); Loading @@ -106,15 +111,20 @@ public class UserDetailsSettings extends SettingsPreferenceFragment if (preference == mRemoveUserPref) { if (canDeleteUser()) { showDialog(DIALOG_CONFIRM_REMOVE); } return true; } } else if (preference == mSwitchUserPref) { if (canSwitchUserNow()) { if (shouldShowSetupPromptDialog()) { showDialog(DIALOG_SETUP_USER); } else { switchUser(); } return true; } } else if (preference == mAppAndContentAccessPref) { openAppAndContentAccessScreen(false); return true; } return false; } Loading @@ -139,6 +149,8 @@ public class UserDetailsSettings extends SettingsPreferenceFragment return SettingsEnums.DIALOG_USER_ENABLE_CALLING; case DIALOG_CONFIRM_ENABLE_CALLING_AND_SMS: return SettingsEnums.DIALOG_USER_ENABLE_CALLING_AND_SMS; case DIALOG_SETUP_USER: return SettingsEnums.DIALOG_USER_SETUP; default: return 0; } Loading @@ -160,6 +172,13 @@ public class UserDetailsSettings extends SettingsPreferenceFragment case DIALOG_CONFIRM_ENABLE_CALLING_AND_SMS: return UserDialogs.createEnablePhoneCallsAndSmsDialog(getActivity(), (dialog, which) -> enableCallsAndSms(true)); case DIALOG_SETUP_USER: return UserDialogs.createSetupUserDialog(getActivity(), (dialog, which) -> { if (canSwitchUserNow()) { switchUser(); } }); } throw new IllegalArgumentException("Unsupported dialogId " + dialogId); } Loading Loading @@ -188,7 +207,14 @@ public class UserDetailsSettings extends SettingsPreferenceFragment mSwitchUserPref.setTitle( context.getString(com.android.settingslib.R.string.user_switch_to_user, mUserInfo.name)); if (mUserCaps.mDisallowSwitchUser) { mSwitchUserPref.setDisabledByAdmin(RestrictedLockUtilsInternal.getDeviceOwner(context)); } else { mSwitchUserPref.setDisabledByAdmin(null); mSwitchUserPref.setSelectable(true); mSwitchUserPref.setOnPreferenceClickListener(this); } if (!mUserManager.isAdminUser()) { // non admin users can't remove users and allow calls removePreference(KEY_ENABLE_TELEPHONY); Loading Loading @@ -321,4 +347,16 @@ public class UserDetailsSettings extends SettingsPreferenceFragment .setSourceMetricsCategory(getMetricsCategory()) .launch(); } private boolean isSecondaryUser(UserInfo user) { return UserManager.USER_TYPE_FULL_SECONDARY.equals(user.userType); } private boolean shouldShowSetupPromptDialog() { // TODO: FLAG_INITIALIZED is set when a user is switched to for the first time, // but what we would really need here is a flag that shows if the setup process was // completed. After the user cancels the setup process, mUserInfo.isInitialized() will // return true so there will be no setup prompt dialog shown to the user anymore. return isSecondaryUser(mUserInfo) && !mUserInfo.isInitialized(); } }
src/com/android/settings/users/UserDialogs.java +17 −0 Original line number Diff line number Diff line Loading @@ -138,4 +138,21 @@ public final class UserDialogs { .setNegativeButton(android.R.string.cancel, null) .create(); } /** * Creates a dialog to confirm that the user is ok to start setting up a new user. * * @param onConfirmListener Callback object for positive action */ public static Dialog createSetupUserDialog(Context context, DialogInterface.OnClickListener onConfirmListener) { return new AlertDialog.Builder(context) .setTitle(com.android.settingslib.R.string.user_setup_dialog_title) .setMessage(com.android.settingslib.R.string.user_setup_dialog_message) .setPositiveButton(com.android.settingslib.R.string.user_setup_button_setup_now, onConfirmListener) .setNegativeButton(com.android.settingslib.R.string.user_setup_button_setup_later, null) .create(); } }
src/com/android/settings/users/UserSettings.java +28 −116 Original line number Diff line number Diff line Loading @@ -102,8 +102,6 @@ public class UserSettings extends SettingsPreferenceFragment /** UserId of the user being removed */ private static final String SAVE_REMOVING_USER = "removing_user"; /** UserId of the user that was just added */ private static final String SAVE_ADDING_USER = "adding_user"; private static final String KEY_USER_LIST = "user_list"; private static final String KEY_USER_ME = "user_me"; Loading @@ -119,8 +117,7 @@ public class UserSettings extends SettingsPreferenceFragment private static final int DIALOG_CONFIRM_REMOVE = 1; private static final int DIALOG_ADD_USER = 2; private static final int DIALOG_SETUP_USER = 3; private static final int DIALOG_SETUP_PROFILE = 4; // Dialogs with id 3 and 4 got removed private static final int DIALOG_USER_CANNOT_MANAGE = 5; private static final int DIALOG_CHOOSE_USER_TYPE = 6; private static final int DIALOG_NEED_LOCKSCREEN = 7; Loading @@ -130,8 +127,7 @@ public class UserSettings extends SettingsPreferenceFragment private static final int DIALOG_USER_PROFILE_EDITOR_ADD_RESTRICTED_PROFILE = 11; private static final int MESSAGE_UPDATE_LIST = 1; private static final int MESSAGE_SETUP_USER = 2; private static final int MESSAGE_CONFIG_USER = 3; private static final int MESSAGE_USER_CREATED = 2; private static final int USER_TYPE_USER = 1; private static final int USER_TYPE_RESTRICTED_PROFILE = 2; Loading Loading @@ -160,7 +156,6 @@ public class UserSettings extends SettingsPreferenceFragment @VisibleForTesting SparseArray<Bitmap> mUserIcons = new SparseArray<>(); private int mRemovingUserId = -1; private int mAddedUserId = 0; private boolean mAddingUser; private String mAddingUserName; private UserCapabilities mUserCaps; Loading @@ -187,12 +182,9 @@ public class UserSettings extends SettingsPreferenceFragment case MESSAGE_UPDATE_LIST: updateUserList(); break; case MESSAGE_SETUP_USER: case MESSAGE_USER_CREATED: onUserCreated(msg.arg1); break; case MESSAGE_CONFIG_USER: onManageUserClicked(msg.arg1, true); break; } } }; Loading Loading @@ -254,9 +246,6 @@ public class UserSettings extends SettingsPreferenceFragment .setOnPreferenceChangeListener(mAddUserWhenLockedPreferenceController); if (icicle != null) { if (icicle.containsKey(SAVE_ADDING_USER)) { mAddedUserId = icicle.getInt(SAVE_ADDING_USER); } if (icicle.containsKey(SAVE_REMOVING_USER)) { mRemovingUserId = icicle.getInt(SAVE_REMOVING_USER); } Loading Loading @@ -334,7 +323,6 @@ public class UserSettings extends SettingsPreferenceFragment public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); mEditUserInfoController.onSaveInstanceState(outState); outState.putInt(SAVE_ADDING_USER, mAddedUserId); outState.putInt(SAVE_REMOVING_USER, mRemovingUserId); } Loading Loading @@ -482,15 +470,15 @@ public class UserSettings extends SettingsPreferenceFragment } } private void onManageUserClicked(int userId, boolean newUser) { private void onUserCreated(int userId) { mAddingUser = false; UserInfo userInfo = mUserManager.getUserInfo(userId); if (userId == UserHandle.myUserId()) { // Jump to owner info panel OwnerInfoSettings.show(this); } else { openUserDetails(userInfo, true); } private void openUserDetails(UserInfo userInfo, boolean newUser) { Bundle extras = new Bundle(); extras.putInt(UserDetailsSettings.EXTRA_USER_ID, userId); extras.putInt(UserDetailsSettings.EXTRA_USER_ID, userInfo.id); extras.putBoolean(AppRestrictionsFragment.EXTRA_NEW_USER, newUser); new SubSettingLauncher(getContext()) .setDestination(UserDetailsSettings.class.getName()) Loading @@ -499,21 +487,6 @@ public class UserSettings extends SettingsPreferenceFragment .setSourceMetricsCategory(getMetricsCategory()) .launch(); } } private void onUserCreated(int userId) { mAddedUserId = userId; mAddingUser = false; if (!isResumed()) { Log.w(TAG, "Cannot show dialog after onPause"); return; } if (mUserManager.getUserInfo(userId).isRestricted()) { showDialog(DIALOG_SETUP_PROFILE); } else { showDialog(DIALOG_SETUP_USER); } } @Override public void onDialogShowing() { Loading Loading @@ -571,37 +544,6 @@ public class UserSettings extends SettingsPreferenceFragment .create(); return dlg; } case DIALOG_SETUP_USER: { Dialog dlg = new AlertDialog.Builder(context) .setTitle(com.android.settingslib.R.string.user_setup_dialog_title) .setMessage(com.android.settingslib.R.string.user_setup_dialog_message) .setPositiveButton( com.android.settingslib.R.string.user_setup_button_setup_now, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { switchUserNow(mAddedUserId); } }) .setNegativeButton( com.android.settingslib.R.string.user_setup_button_setup_later, null) .create(); return dlg; } case DIALOG_SETUP_PROFILE: { Dialog dlg = new AlertDialog.Builder(context) .setMessage( com.android.settingslib.R.string.user_setup_profile_dialog_message) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { switchUserNow(mAddedUserId); } }) .setNegativeButton(android.R.string.cancel, null) .create(); return dlg; } case DIALOG_CHOOSE_USER_TYPE: { List<HashMap<String, String>> data = new ArrayList<HashMap<String, String>>(); HashMap<String, String> addUserItem = new HashMap<String, String>(); Loading Loading @@ -764,10 +706,6 @@ public class UserSettings extends SettingsPreferenceFragment return SettingsEnums.DIALOG_USER_CANNOT_MANAGE; case DIALOG_ADD_USER: return SettingsEnums.DIALOG_USER_ADD; case DIALOG_SETUP_USER: return SettingsEnums.DIALOG_USER_SETUP; case DIALOG_SETUP_PROFILE: return SettingsEnums.DIALOG_USER_SETUP_PROFILE; case DIALOG_CHOOSE_USER_TYPE: return SettingsEnums.DIALOG_USER_CHOOSE_TYPE; case DIALOG_NEED_LOCKSCREEN: Loading Loading @@ -853,16 +791,11 @@ public class UserSettings extends SettingsPreferenceFragment if (userType == USER_TYPE_USER) { mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST); // Skip setting up user which results in user switching when the // restriction is set. if (!mUserCaps.mDisallowSwitchUser) { mHandler.sendMessage(mHandler.obtainMessage( MESSAGE_SETUP_USER, user.id, user.serialNumber)); } } else { mHandler.sendMessage(mHandler.obtainMessage( MESSAGE_CONFIG_USER, user.id, user.serialNumber)); } MESSAGE_USER_CREATED, user.id, user.serialNumber)); mPendingUserIcon = null; mPendingUserName = null; } Loading @@ -870,18 +803,6 @@ public class UserSettings extends SettingsPreferenceFragment }); } private void switchUserNow(int userId) { if (!canSwitchUserNow()) { return; } try { ActivityManager.getService().switchUser(userId); } catch (RemoteException re) { Log.e(TAG, "Error while switching to other user."); } } /** * Erase the current user (guest) and switch to another user. */ Loading Loading @@ -1125,21 +1046,14 @@ public class UserSettings extends SettingsPreferenceFragment if (pref == mMePreference) { if (isCurrentUserGuest()) { showDialog(DIALOG_CONFIRM_EXIT_GUEST); return true; } showDialog(DIALOG_USER_PROFILE_EDITOR); } else if (pref instanceof UserPreference) { int userId = ((UserPreference) pref).getUserId(); // Get the latest status of the user UserInfo user = mUserManager.getUserInfo(userId); if (!user.isInitialized() && isSecondaryUser(user)) { // for uninitialized secondary users we should show a prompt dialog before // starting the setup mHandler.sendMessage(mHandler.obtainMessage( MESSAGE_SETUP_USER, user.id, user.serialNumber)); } else { onManageUserClicked(userId, false); showDialog(DIALOG_USER_PROFILE_EDITOR); } return true; } else if (pref instanceof UserPreference) { UserInfo userInfo = mUserManager.getUserInfo(((UserPreference) pref).getUserId()); openUserDetails(userInfo, false); return true; } else if (pref == mAddUser) { // If we allow both types, show a picker, otherwise directly go to // flow for full user. Loading @@ -1148,10 +1062,12 @@ public class UserSettings extends SettingsPreferenceFragment } else { onAddUserClicked(USER_TYPE_USER); } return true; } else if (pref == mAddGuest) { UserInfo guest = mUserManager.createGuest( getContext(), getString(com.android.settingslib.R.string.user_guest)); switchUserNow(guest.id); openUserDetails(guest, true); return true; } return false; } Loading Loading @@ -1265,8 +1181,4 @@ public class UserSettings extends SettingsPreferenceFragment return niks; } }; private boolean isSecondaryUser(UserInfo user) { return UserManager.USER_TYPE_FULL_SECONDARY.equals(user.userType); } }
tests/robotests/src/com/android/settings/users/UserDetailsSettingsTest.java +35 −1 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.robolectric.Shadows.shadowOf; import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; Loading @@ -53,6 +54,8 @@ import com.android.settings.SettingsActivity; import com.android.settings.SubSettings; import com.android.settings.testutils.shadow.ShadowDevicePolicyManager; import com.android.settings.testutils.shadow.ShadowUserManager; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedPreference; import org.junit.After; import org.junit.Before; Loading Loading @@ -91,7 +94,7 @@ public class UserDetailsSettingsTest { private ShadowUserManager mUserManager; @Mock private Preference mSwitchUserPref; private RestrictedPreference mSwitchUserPref; @Mock private SwitchPreference mPhonePref; @Mock Loading @@ -101,6 +104,7 @@ public class UserDetailsSettingsTest { private FragmentActivity mActivity; private Context mContext; private UserCapabilities mUserCapabilities; private UserDetailsSettings mFragment; private Bundle mArguments; private UserInfo mUserInfo; Loading @@ -111,6 +115,8 @@ public class UserDetailsSettingsTest { mActivity = spy(ActivityController.of(new FragmentActivity()).get()); mContext = spy(RuntimeEnvironment.application); mUserCapabilities = UserCapabilities.create(mContext); mUserCapabilities.mUserSwitcherEnabled = true; mFragment = spy(new UserDetailsSettings()); mArguments = new Bundle(); Loading @@ -121,6 +127,7 @@ public class UserDetailsSettingsTest { doReturn(mTelephonyManager).when(mActivity).getSystemService(Context.TELEPHONY_SERVICE); ReflectionHelpers.setField(mFragment, "mUserManager", userManager); ReflectionHelpers.setField(mFragment, "mUserCaps", mUserCapabilities); doReturn(mActivity).when(mFragment).getActivity(); doReturn(mActivity).when(mFragment).getContext(); Loading Loading @@ -426,6 +433,33 @@ public class UserDetailsSettingsTest { verify(mPhonePref).setChecked(false); } @Test public void initialize_switchUserDisallowed_shouldSetAdminDisabledOnSwitchPreference() { setupSelectedUser(); mUserCapabilities.mDisallowSwitchUser = true; DevicePolicyManager devicePolicyManager = mock(DevicePolicyManager.class); doReturn(devicePolicyManager).when(mActivity) .getSystemService(Context.DEVICE_POLICY_SERVICE); doReturn(mock(ComponentName.class)).when(devicePolicyManager) .getDeviceOwnerComponentOnAnyUser(); mFragment.initialize(mActivity, mArguments); verify(mSwitchUserPref).setDisabledByAdmin(any(RestrictedLockUtils.EnforcedAdmin.class)); } @Test public void initialize_switchUserAllowed_shouldSetSwitchPreferenceEnabled() { setupSelectedUser(); mUserCapabilities.mDisallowSwitchUser = false; mFragment.initialize(mActivity, mArguments); verify(mSwitchUserPref).setDisabledByAdmin(null); verify(mSwitchUserPref).setSelectable(true); verify(mSwitchUserPref).setOnPreferenceClickListener(mFragment); } @Test public void onPreferenceClick_switchClicked_canSwitch_shouldSwitch() { setupSelectedUser(); Loading
tests/robotests/src/com/android/settings/users/UserSettingsTest.java +30 −0 Original line number Diff line number Diff line Loading @@ -33,13 +33,16 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.robolectric.Shadows.shadowOf; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.UserInfo; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; Loading @@ -53,6 +56,8 @@ import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; import com.android.settings.SettingsActivity; import com.android.settings.SubSettings; import com.android.settings.testutils.shadow.ShadowDevicePolicyManager; import com.android.settings.testutils.shadow.ShadowUserManager; import com.android.settingslib.RestrictedLockUtils; Loading @@ -70,6 +75,7 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.android.controller.ActivityController; import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowIntent; import org.robolectric.util.ReflectionHelpers; import java.util.Arrays; Loading Loading @@ -589,6 +595,30 @@ public class UserSettingsTest { verify(mUserManager, times(2)).getUsers(true); } @Test public void onPreferenceClick_addGuestClicked_createGuestAndOpenDetails() { UserInfo createdGuest = getGuest(false); removeFlag(createdGuest, UserInfo.FLAG_INITIALIZED); doReturn(createdGuest).when(mUserManager).createGuest(mActivity, "Guest"); doReturn(mActivity).when(mFragment).getContext(); mFragment.onPreferenceClick(mAddGuestPreference); verify(mUserManager).createGuest(mActivity, "Guest"); Intent startedIntent = shadowOf(mActivity).getNextStartedActivity(); ShadowIntent shadowIntent = shadowOf(startedIntent); assertThat(shadowIntent.getIntentClass()).isEqualTo(SubSettings.class); assertThat(startedIntent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT)) .isEqualTo(UserDetailsSettings.class.getName()); Bundle arguments = startedIntent.getBundleExtra( SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS); assertThat(arguments).isNotNull(); assertThat(arguments.getInt(UserDetailsSettings.EXTRA_USER_ID, 0)) .isEqualTo(createdGuest.id); assertThat(arguments.getBoolean(AppRestrictionsFragment.EXTRA_NEW_USER, false)) .isEqualTo(true); } @Test public void getRealUsersCount_onlyAdmin_shouldCount() { givenUsers(getAdminUser(true)); Loading