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

Commit 3e1eef26 authored by Tetiana Meronyk's avatar Tetiana Meronyk Committed by Android (Google) Code Review
Browse files

Merge "Update MainSwitch on User Settings page" into main

parents 9cdcaefe 04daaaff
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -25,6 +25,10 @@
        android:title="@string/user_settings_footer_text"
        settings:controller="com.android.settings.users.MultiUserTopIntroPreferenceController"/>

    <com.android.settings.widget.SettingsMainSwitchPreference
        android:key="multiple_users_main_switch"
        android:title="@string/multiple_users_main_switch_title"/>

    <PreferenceCategory
        android:key="guest_category"
        android:title="@string/guest_category_title"
+109 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.users;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.util.Log;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;

import androidx.preference.PreferenceScreen;


import com.android.settings.R;
import com.android.settings.core.TogglePreferenceController;
import com.android.settings.widget.SettingsMainSwitchPreference;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtilsInternal;

public class MultiUserMainSwitchPreferenceController extends TogglePreferenceController
        implements OnCheckedChangeListener {

    private static final String TAG = MultiUserMainSwitchPreferenceController.class.getSimpleName();

    @Nullable
    private SettingsMainSwitchPreference mPreference;
    private final UserCapabilities mUserCaps;

    MultiUserMainSwitchPreferenceController(Context context, String preferenceKey) {
        super(context, preferenceKey);
        mUserCaps = UserCapabilities.create(context);
    }

    @Override
    public boolean isChecked() {
        return mUserCaps.mUserSwitcherEnabled;
    }

    @Override
    public boolean setChecked(boolean isChecked) {
        Log.d(TAG, "Setting ALLOW_USER_SWITCH to " + isChecked);
        return Settings.Global.putInt(mContext.getContentResolver(),
                Settings.Global.USER_SWITCHER_ENABLED, isChecked ? 1 : 0);
    }

    @Override
    public int getSliceHighlightMenuRes() {
        return  R.string.menu_key_system;
    }

    @Override
    public int getAvailabilityStatus() {
        if (!mUserCaps.mIsGuest) {
            return AVAILABLE;
        } else {
            return DISABLED_FOR_USER;
        }
    }

    @Override
    public void displayPreference(@NonNull PreferenceScreen screen) {
        super.displayPreference(screen);

        mPreference = screen.findPreference(getPreferenceKey());
        if (mPreference != null) {
            mPreference.addOnSwitchChangeListener(this);
            updateState();
        }
    }

    void updateState() {
        if (mPreference != null) {
            mUserCaps.updateAddUserCapabilities(mContext);
            mPreference.setChecked(isChecked());
            RestrictedLockUtils.EnforcedAdmin enforcedAdmin = RestrictedLockUtilsInternal
                    .checkIfRestrictionEnforced(mContext, UserManager.DISALLOW_USER_SWITCH,
                            UserHandle.myUserId());
            if (enforcedAdmin != null) {
                mPreference.setDisabledByAdmin(enforcedAdmin);
            } else {
                mPreference.setSwitchBarEnabled(
                        mUserCaps.mIsMain && !mUserCaps.mDisallowSwitchUser);
            }
        }
    }

    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        setChecked(isChecked);
    }
}
+40 −14
Original line number Diff line number Diff line
@@ -146,6 +146,7 @@ public class UserSettings extends SettingsPreferenceFragment
    private static final String KEY_GUEST_USER_CATEGORY = "guest_user_category";
    private static final String KEY_ALLOW_MULTIPLE_USERS = "allow_multiple_users";
    private static final String KEY_USER_SETTINGS_SCREEN = "user_settings_screen";
    private static final String KEY_USER_SWITCH_TOGGLE = "multiple_users_main_switch";

    private static final String SETTING_GUEST_HAS_LOGGED_IN = "systemui.guest_has_logged_in";

@@ -230,6 +231,10 @@ public class UserSettings extends SettingsPreferenceFragment

    private MultiUserSwitchBarController mSwitchBarController;

    //TODO: Add @NonNull during Flags.changeSwitchBarIntoMainPreference() cleanup
    @SuppressWarnings("NullAway")
    private MultiUserMainSwitchPreferenceController mMainSwitchController;

    private GrantAdminDialogController mGrantAdminDialogController =
            new GrantAdminDialogController();
    private EditUserInfoController mEditUserInfoController =
@@ -298,6 +303,14 @@ public class UserSettings extends SettingsPreferenceFragment
        super.onActivityCreated(savedInstanceState);
        // Assume we are in a SettingsActivity. This is only safe because we currently use
        // SettingsActivity as base for all preference fragments.
        boolean openUserEditDialog = getIntent().getBooleanExtra(
                EXTRA_OPEN_DIALOG_USER_PROFILE_EDITOR, false);

        if (Flags.changeSwitchBarIntoMainPreference()) {
            if (openUserEditDialog) {
                showDialog(DIALOG_USER_PROFILE_EDITOR);
            }
        } else {
            final SettingsActivity activity = (SettingsActivity) getActivity();
            final SettingsMainSwitchBar switchBar = activity.getSwitchBar();
            switchBar.setTitle(getContext().getString(R.string.multiple_users_main_switch_title));
@@ -309,12 +322,11 @@ public class UserSettings extends SettingsPreferenceFragment
            mSwitchBarController = new MultiUserSwitchBarController(activity,
                    new MainSwitchBarController(switchBar), this /* listener */);
            getSettingsLifecycle().addObserver(mSwitchBarController);
        boolean openUserEditDialog = getIntent().getBooleanExtra(
                EXTRA_OPEN_DIALOG_USER_PROFILE_EDITOR, false);
            if (switchBar.isChecked() && openUserEditDialog) {
                showDialog(DIALOG_USER_PROFILE_EDITOR);
            }
        }
    }

    @Override
    public void onCreate(Bundle icicle) {
@@ -344,12 +356,22 @@ public class UserSettings extends SettingsPreferenceFragment
        mTimeoutToDockUserPreferenceController = new TimeoutToDockUserPreferenceController(
                activity, KEY_TIMEOUT_TO_DOCK_USER);

        if (Flags.changeSwitchBarIntoMainPreference()) {
            mMainSwitchController = new MultiUserMainSwitchPreferenceController(
                    activity, KEY_USER_SWITCH_TOGGLE);
        }

        final PreferenceScreen screen = getPreferenceScreen();
        mAddUserWhenLockedPreferenceController.displayPreference(screen);
        mGuestTelephonyPreferenceController.displayPreference(screen);
        mRemoveGuestOnExitPreferenceController.displayPreference(screen);
        mMultiUserTopIntroPreferenceController.displayPreference(screen);
        mTimeoutToDockUserPreferenceController.displayPreference(screen);
        if (Flags.changeSwitchBarIntoMainPreference()) {
            mMainSwitchController.displayPreference(screen);
        } else {
            screen.findPreference(KEY_USER_SWITCH_TOGGLE).setVisible(false);
        }

        screen.findPreference(mAddUserWhenLockedPreferenceController.getPreferenceKey())
                .setOnPreferenceChangeListener(mAddUserWhenLockedPreferenceController);
@@ -433,7 +455,11 @@ public class UserSettings extends SettingsPreferenceFragment
                mTimeoutToDockUserPreferenceController.getPreferenceKey()));
        mRemoveGuestOnExitPreferenceController.updateState(screen.findPreference(
                mRemoveGuestOnExitPreferenceController.getPreferenceKey()));
        if (Flags.changeSwitchBarIntoMainPreference()) {
            mMainSwitchController.updateState();
        } else {
            mSwitchBarController.updateState();
        }
        if (mShouldUpdateUserList) {
            updateUI();
        }
+197 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.users;

import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.DISABLED_FOR_USER;

import static junit.framework.Assert.assertEquals;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;

import android.content.Context;
import android.content.pm.UserInfo;
import android.os.UserHandle;
import android.os.UserManager;

import androidx.preference.PreferenceScreen;

import com.android.settings.testutils.shadow.ShadowDevicePolicyManager;
import com.android.settings.testutils.shadow.ShadowUserManager;
import com.android.settings.widget.SettingsMainSwitchPreference;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;

import java.util.ArrayList;
import java.util.List;

@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowUserManager.class, ShadowDevicePolicyManager.class})
public class MultiUserMainSwitchPreferenceControllerTest {

    private Context mContext;
    private ShadowUserManager mUserManager;
    private SettingsMainSwitchPreference mPreference;
    private static final String KEY_USER_SWITCH_TOGGLE = "multiple_users_main_switch";

    private PreferenceScreen mScreen;

    @Before
    public void setUp() {
        mContext = RuntimeEnvironment.application;
        mScreen = mock(PreferenceScreen.class);
        mPreference = mock(SettingsMainSwitchPreference.class);

        mUserManager = ShadowUserManager.getShadow();
        mUserManager.setSupportsMultipleUsers(true);

        doReturn(mPreference).when(mScreen).findPreference(KEY_USER_SWITCH_TOGGLE);
    }

    @After
    public void tearDown() {
        ShadowUserManager.reset();
    }

    @Test
    public void displayPreference_disallowUserSwitchByAdmin_shouldSetDisabledByAdminUnchecked() {
        int userId = UserHandle.myUserId();
        List<UserManager.EnforcingUser> enforcingUsers = new ArrayList<>();
        enforcingUsers.add(new UserManager.EnforcingUser(userId,
                UserManager.RESTRICTION_SOURCE_DEVICE_OWNER));
        // Ensure that RestrictedLockUtils.checkIfRestrictionEnforced doesn't return null.
        ShadowUserManager.getShadow().setUserRestrictionSources(
                UserManager.DISALLOW_USER_SWITCH,
                UserHandle.of(userId),
                enforcingUsers);

        MultiUserMainSwitchPreferenceController multiUserMainSwitchPreferenceController =
                new MultiUserMainSwitchPreferenceController(mContext, KEY_USER_SWITCH_TOGGLE);
        multiUserMainSwitchPreferenceController.displayPreference(mScreen);

        verify(mPreference).setChecked(false);
        verify(mPreference).setDisabledByAdmin(any());
    }

    @Test
    public void displayPreference_disallowUserSwitch_userNotMain_shouldSetDisabledUnchecked() {
        mUserManager.setUserRestriction(UserHandle.of(UserHandle.myUserId()),
                UserManager.DISALLOW_USER_SWITCH, true);

        MultiUserMainSwitchPreferenceController multiUserMainSwitchPreferenceController =
                new MultiUserMainSwitchPreferenceController(mContext, KEY_USER_SWITCH_TOGGLE);
        multiUserMainSwitchPreferenceController.displayPreference(mScreen);

        verify(mPreference).setChecked(false);
        verify(mPreference).setSwitchBarEnabled(false);
        verify(mPreference, never()).setDisabledByAdmin(any());
    }

    @Test
    public void displayPreference_allowUserSwitch_notMainUser_shouldSetDisabled() {
        mUserManager.setUserRestriction(UserHandle.of(UserHandle.myUserId()),
                UserManager.DISALLOW_USER_SWITCH, false);
        mUserManager.addUser(10, "Test", UserInfo.FLAG_ADMIN);
        mUserManager.switchUser(10);

        MultiUserMainSwitchPreferenceController multiUserMainSwitchPreferenceController =
                new MultiUserMainSwitchPreferenceController(mContext, KEY_USER_SWITCH_TOGGLE);
        multiUserMainSwitchPreferenceController.displayPreference(mScreen);

        verify(mPreference).setSwitchBarEnabled(false);
    }

    @Test
    public void displayPreference_allowUserSwitch_shouldNotSetDisabledByAdmin() {
        mUserManager.setUserRestriction(UserHandle.of(UserHandle.myUserId()),
                UserManager.DISALLOW_USER_SWITCH, false);

        MultiUserMainSwitchPreferenceController multiUserMainSwitchPreferenceController =
                new MultiUserMainSwitchPreferenceController(mContext, KEY_USER_SWITCH_TOGGLE);
        multiUserMainSwitchPreferenceController.displayPreference(mScreen);

        assertEquals(AVAILABLE, multiUserMainSwitchPreferenceController.getAvailabilityStatus());
        verify(mPreference, never()).setDisabledByAdmin(any());
    }

    @Test
    public void displayPreference_userIsNotMain_shouldNotBeEnabled() {

        mUserManager.setUserRestriction(UserHandle.of(UserHandle.myUserId()),
                UserManager.DISALLOW_USER_SWITCH, false);
        mUserManager.addUser(10, "Test", UserInfo.FLAG_ADMIN);
        mUserManager.switchUser(10);

        MultiUserMainSwitchPreferenceController multiUserMainSwitchPreferenceController =
                new MultiUserMainSwitchPreferenceController(mContext, KEY_USER_SWITCH_TOGGLE);
        multiUserMainSwitchPreferenceController.displayPreference(mScreen);

        assertEquals(AVAILABLE, multiUserMainSwitchPreferenceController.getAvailabilityStatus());
        verify(mPreference, never()).setDisabledByAdmin(any());
        verify(mPreference).setSwitchBarEnabled(false);
    }

    @Test
    public void displayPreference_userIsMain_shouldBeEnabled() {
        mUserManager.setUserRestriction(UserHandle.of(UserHandle.myUserId()),
                UserManager.DISALLOW_USER_SWITCH, false);

        MultiUserMainSwitchPreferenceController multiUserMainSwitchPreferenceController =
                new MultiUserMainSwitchPreferenceController(mContext, KEY_USER_SWITCH_TOGGLE);
        multiUserMainSwitchPreferenceController.displayPreference(mScreen);

        verify(mPreference, never()).setDisabledByAdmin(any());
        verify(mPreference).setSwitchBarEnabled(true);
    }

    @Test
    public void userIsGuest_shouldBeHidden() {
        mUserManager.setUserRestriction(UserHandle.of(UserHandle.myUserId()),
                UserManager.DISALLOW_USER_SWITCH, false);
        mUserManager.addUser(10, "Test", UserInfo.FLAG_GUEST);
        mUserManager.switchUser(10);

        MultiUserMainSwitchPreferenceController multiUserMainSwitchPreferenceController =
                new MultiUserMainSwitchPreferenceController(mContext, KEY_USER_SWITCH_TOGGLE);

        assertEquals(DISABLED_FOR_USER,
                multiUserMainSwitchPreferenceController.getAvailabilityStatus());
    }

    @Test
    public void userIsMain_shouldBeHidden() {
        mUserManager.setUserRestriction(UserHandle.of(UserHandle.myUserId()),
                UserManager.DISALLOW_USER_SWITCH, false);
        mUserManager.setIsAdminUser(true);

        MultiUserMainSwitchPreferenceController multiUserMainSwitchPreferenceController =
                new MultiUserMainSwitchPreferenceController(mContext, KEY_USER_SWITCH_TOGGLE);

        assertEquals(AVAILABLE,
                multiUserMainSwitchPreferenceController.getAvailabilityStatus());
    }
}