Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4e2a0717 authored by Andras Kloczl's avatar Andras Kloczl
Browse files

Change user setup prompt dialog showing logic

- Extract user setup prompt dialog creation logic
- Move user setup prompt dialog showing to UserDetailsSettings
- Rename user click and creation related methods to improve readability
- Set "disabled by admin" for switch pref when switch is disabled
- Cleanup UserSettings and UserDetailsSettings onPreferenceClick
- After a guest is created the details page opens instead of switching

Test: Manual test and robo tests with this command:
  make -j64 RunSettingsRoboTests
Demo: http://shortn/_ACYsnbIKO9
Bug: 156867277
Change-Id: Ifa0cdefcd49d5b865e940a7cc332136ed26ecf57
parent 03b20f86
Loading
Loading
Loading
Loading
+43 −5
Original line number Diff line number Diff line
@@ -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;

@@ -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;
@@ -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());
@@ -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;
    }
@@ -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;
        }
@@ -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);
    }
@@ -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);
@@ -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();
    }
}
+17 −0
Original line number Diff line number Diff line
@@ -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();
    }
}
+28 −116
Original line number Diff line number Diff line
@@ -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";
@@ -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;
@@ -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;
@@ -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;
@@ -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;
            }
        }
    };
@@ -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);
            }
@@ -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);
    }

@@ -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())
@@ -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() {
@@ -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>();
@@ -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:
@@ -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;
                }
@@ -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.
     */
@@ -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.
@@ -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;
    }
@@ -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);
    }
}
+35 −1
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -91,7 +94,7 @@ public class UserDetailsSettingsTest {
    private ShadowUserManager mUserManager;

    @Mock
    private Preference mSwitchUserPref;
    private RestrictedPreference mSwitchUserPref;
    @Mock
    private SwitchPreference mPhonePref;
    @Mock
@@ -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;
@@ -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();

@@ -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();

@@ -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();
+30 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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;
@@ -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));