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

Commit 38ec14c2 authored by Ying Zheng's avatar Ying Zheng Committed by Android (Google) Code Review
Browse files

Merge "Remove the deprecated UserManagerHelper, new one is in car user lib." into qt-dev

parents 2a4e6f6e 6e549279
Loading
Loading
Loading
Loading
+0 −499
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.settingslib.users;

import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.UserInfo;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;

import com.android.internal.util.UserIcons;

import java.util.Iterator;
import java.util.List;

/**
 * Helper class for managing users, providing methods for removing, adding and switching users.
 *
 * @deprecated - Do not use
 */
@Deprecated
public final class UserManagerHelper {
    private static final String TAG = "UserManagerHelper";
    private static final String HEADLESS_SYSTEM_USER = "android.car.systemuser.headless";
    private final Context mContext;
    private final UserManager mUserManager;
    private final ActivityManager mActivityManager;
    private OnUsersUpdateListener mUpdateListener;
    private final BroadcastReceiver mUserChangeReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            mUpdateListener.onUsersUpdate();
        }
    };

    public UserManagerHelper(Context context) {
        mContext = context;
        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
        mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
    }

    /**
     * Registers a listener for updates to all users - removing, adding users or changing user info.
     *
     * @param listener Instance of {@link OnUsersUpdateListener}.
     */
    public void registerOnUsersUpdateListener(OnUsersUpdateListener listener) {
        mUpdateListener = listener;
        registerReceiver();
    }

    /**
     * Unregisters listener by unregistering {@code BroadcastReceiver}.
     */
    public void unregisterOnUsersUpdateListener() {
        unregisterReceiver();
    }

    /**
     * Returns {@code true} if the system is in the headless user 0 model.
     *
     * @return {@boolean true} if headless system user.
     */
    public boolean isHeadlessSystemUser() {
        return SystemProperties.getBoolean(HEADLESS_SYSTEM_USER, false);
    }

    /**
     * Gets UserInfo for the foreground user.
     *
     * Concept of foreground user is relevant for the multi-user deployment. Foreground user
     * corresponds to the currently "logged in" user.
     *
     * @return {@link UserInfo} for the foreground user.
     */
    public UserInfo getForegroundUserInfo() {
        return mUserManager.getUserInfo(getForegroundUserId());
    }

    /**
     * @return Id of the foreground user.
     */
    public int getForegroundUserId() {
        return mActivityManager.getCurrentUser();
    }

    /**
     * Gets UserInfo for the user running the caller process.
     *
     * Differentiation between foreground user and current process user is relevant for multi-user
     * deployments.
     *
     * Some multi-user aware components (like SystemUI) might run as a singleton - one component
     * for all users. Current process user is then always the same for that component, even when
     * the foreground user changes.
     *
     * @return {@link UserInfo} for the user running the current process.
     */
    public UserInfo getCurrentProcessUserInfo() {
        return mUserManager.getUserInfo(getCurrentProcessUserId());
    }

    /**
     * @return Id for the user running the current process.
     */
    public int getCurrentProcessUserId() {
        return UserHandle.myUserId();
    }

    /**
     * Gets all the other users on the system that are not the user running the current process.
     *
     * @return List of {@code UserInfo} for each user that is not the user running the process.
     */
    public List<UserInfo> getAllUsersExcludesCurrentProcessUser() {
        return getAllUsersExceptUser(getCurrentProcessUserId());
    }

    /**
     * Gets all the existing users on the system that are not the currently running as the
     * foreground user.
     *
     * @return List of {@code UserInfo} for each user that is not the foreground user.
     */
    public List<UserInfo> getAllUsersExcludesForegroundUser() {
        return getAllUsersExceptUser(getForegroundUserId());
    }

    /**
     * Gets all the other users on the system that are not the system user.
     *
     * @return List of {@code UserInfo} for each user that is not the system user.
     */
    public List<UserInfo> getAllUsersExcludesSystemUser() {
        return getAllUsersExceptUser(UserHandle.USER_SYSTEM);
    }

    /**
     * Get all the users except the one with userId passed in.
     *
     * @param userId of the user not to be returned.
     * @return All users other than user with userId.
     */
    public List<UserInfo> getAllUsersExceptUser(int userId) {
        List<UserInfo> others = mUserManager.getUsers(/* excludeDying= */true);

        for (Iterator<UserInfo> iterator = others.iterator(); iterator.hasNext(); ) {
            UserInfo userInfo = iterator.next();
            if (userInfo.id == userId) {
                // Remove user with userId from the list.
                iterator.remove();
            }
        }
        return others;
    }

    /**
     * Gets all the users on the system that are not currently being removed.
     */
    public List<UserInfo> getAllUsers() {
        if (isHeadlessSystemUser()) {
            return getAllUsersExcludesSystemUser();
        }
        return mUserManager.getUsers(/* excludeDying= */true);
    }

    // User information accessors

    /**
     * Checks whether the user is system user (admin).
     *
     * @param userInfo User to check against system user.
     * @return {@code true} if system user, {@code false} otherwise.
     */
    public boolean userIsSystemUser(UserInfo userInfo) {
        return userInfo.id == UserHandle.USER_SYSTEM;
    }

    /**
     * Returns whether this user can be removed from the system.
     *
     * @param userInfo User to be removed
     * @return {@code true} if they can be removed, {@code false} otherwise.
     */
    public boolean userCanBeRemoved(UserInfo userInfo) {
        return !userIsSystemUser(userInfo);
    }

    /**
     * Checks whether passed in user is the foreground user.
     *
     * @param userInfo User to check.
     * @return {@code true} if foreground user, {@code false} otherwise.
     */
    public boolean userIsForegroundUser(UserInfo userInfo) {
        return getForegroundUserId() == userInfo.id;
    }

    /**
     * Checks whether passed in user is the user that's running the current process.
     *
     * @param userInfo User to check.
     * @return {@code true} if user running the process, {@code false} otherwise.
     */
    public boolean userIsRunningCurrentProcess(UserInfo userInfo) {
        return getCurrentProcessUserId() == userInfo.id;
    }

    // Foreground user information accessors.

    /**
     * Checks if the foreground user is a guest user.
     */
    public boolean foregroundUserIsGuestUser() {
      return getForegroundUserInfo().isGuest();
    }

    /**
     * Return whether the foreground user has a restriction.
     *
     * @param restriction Restriction to check. Should be a UserManager.* restriction.
     * @return Whether that restriction exists for the foreground user.
     */
    public boolean foregroundUserHasUserRestriction(String restriction) {
        return mUserManager.hasUserRestriction(restriction, getForegroundUserInfo().getUserHandle());
    }

    /**
     * Checks if the foreground user can add new users.
     */
    public boolean foregroundUserCanAddUsers() {
        return !foregroundUserHasUserRestriction(UserManager.DISALLOW_ADD_USER);
    }

    // Current process user information accessors

    /**
     * Checks if the calling app is running in a demo user.
     */
    public boolean currentProcessRunningAsDemoUser() {
        return mUserManager.isDemoUser();
    }

    /**
     * Checks if the calling app is running as a guest user.
     */
    public boolean currentProcessRunningAsGuestUser() {
        return mUserManager.isGuestUser();
    }

    /**
     * Checks whether this process is running under the system user.
     */
    public boolean currentProcessRunningAsSystemUser() {
        return mUserManager.isSystemUser();
    }

    // Current process user restriction accessors

    /**
     * Return whether the user running the current process has a restriction.
     *
     * @param restriction Restriction to check. Should be a UserManager.* restriction.
     * @return Whether that restriction exists for the user running the process.
     */
    public boolean currentProcessHasUserRestriction(String restriction) {
        return mUserManager.hasUserRestriction(restriction);
    }

    /**
     * Checks if the user running the current process can add new users.
     */
    public boolean currentProcessCanAddUsers() {
        return !currentProcessHasUserRestriction(UserManager.DISALLOW_ADD_USER);
    }

    /**
     * Checks if the user running the current process can remove users.
     */
    public boolean currentProcessCanRemoveUsers() {
        return !currentProcessHasUserRestriction(UserManager.DISALLOW_REMOVE_USER);
    }

    /**
     * Checks if the user running the current process is allowed to switch to another user.
     */
    public boolean currentProcessCanSwitchUsers() {
        return !currentProcessHasUserRestriction(UserManager.DISALLOW_USER_SWITCH);
    }

    /**
     * Checks if the current process user can modify accounts. Demo and Guest users cannot modify
     * accounts even if the DISALLOW_MODIFY_ACCOUNTS restriction is not applied.
     */
    public boolean currentProcessCanModifyAccounts() {
        return !currentProcessHasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS)
                && !currentProcessRunningAsDemoUser()
                && !currentProcessRunningAsGuestUser();
    }

    // User actions

    /**
     * Creates a new user on the system.
     *
     * @param userName Name to give to the newly created user.
     * @return Newly created user.
     */
    public UserInfo createNewUser(String userName) {
        UserInfo user = mUserManager.createUser(userName, 0 /* flags */);
        if (user == null) {
            // Couldn't create user, most likely because there are too many, but we haven't
            // been able to reload the list yet.
            Log.w(TAG, "can't create user.");
            return null;
        }
        assignDefaultIcon(user);
        return user;
    }

    /**
     * Tries to remove the user that's passed in. System user cannot be removed.
     * If the user to be removed is user currently running the process,
     * it switches to the system user first, and then removes the user.
     *
     * @param userInfo User to be removed
     * @return {@code true} if user is successfully removed, {@code false} otherwise.
     */
    public boolean removeUser(UserInfo userInfo) {
        if (userIsSystemUser(userInfo)) {
            Log.w(TAG, "User " + userInfo.id + " is system user, could not be removed.");
            return false;
        }

        if (userInfo.id == getCurrentProcessUserId()) {
            switchToUserId(UserHandle.USER_SYSTEM);
        }

        return mUserManager.removeUser(userInfo.id);
    }

    /**
     * Switches (logs in) to another user.
     *
     * @param userInfo User to switch to.
     */
    public void switchToUser(UserInfo userInfo) {
        if (userInfo.id == getForegroundUserId()) {
            return;
        }

        switchToUserId(userInfo.id);
    }

    /**
     * Creates a new guest session and switches into the guest session.
     *
     * @param guestName Username for the guest user.
     */
    public void startNewGuestSession(String guestName) {
        UserInfo guest = mUserManager.createGuest(mContext, guestName);
        if (guest == null) {
            // Couldn't create user, most likely because there are too many, but we haven't
            // been able to reload the list yet.
            Log.w(TAG, "can't create user.");
            return;
        }
        assignDefaultIcon(guest);
        switchToUserId(guest.id);
    }

    /**
     * Gets an icon for the user.
     *
     * @param userInfo User for which we want to get the icon.
     * @return a Bitmap for the icon
     */
    public Bitmap getUserIcon(UserInfo userInfo) {
        Bitmap picture = mUserManager.getUserIcon(userInfo.id);

        if (picture == null) {
            return assignDefaultIcon(userInfo);
        }

        return picture;
    }

    /**
     * Method for scaling a Bitmap icon to a desirable size.
     *
     * @param icon Bitmap to scale.
     * @param desiredSize Wanted size for the icon.
     * @return Drawable for the icon, scaled to the new size.
     */
    public Drawable scaleUserIcon(Bitmap icon, int desiredSize) {
        Bitmap scaledIcon = Bitmap.createScaledBitmap(
                icon, desiredSize, desiredSize, true /* filter */);
        return new BitmapDrawable(mContext.getResources(), scaledIcon);
    }

    /**
     * Sets new Username for the user.
     *
     * @param user User whose name should be changed.
     * @param name New username.
     */
    public void setUserName(UserInfo user, String name) {
        mUserManager.setUserName(user.id, name);
    }

    /**
     * Gets a bitmap representing the user's default avatar.
     *
     * @param userInfo User whose avatar should be returned.
     * @return Default user icon
     */
    public Bitmap getUserDefaultIcon(UserInfo userInfo) {
        return UserIcons.convertToBitmap(
                UserIcons.getDefaultUserIcon(mContext.getResources(), userInfo.id, false));
    }

    /**
     * Gets a bitmap representing the default icon for a Guest user.
     *
     * @return Degault guest icon
     */
    public Bitmap getGuestDefaultIcon() {
        return UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon(
                mContext.getResources(), UserHandle.USER_NULL, false));
    }

    private void registerReceiver() {
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_USER_REMOVED);
        filter.addAction(Intent.ACTION_USER_ADDED);
        filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
        filter.addAction(Intent.ACTION_USER_SWITCHED);
        filter.addAction(Intent.ACTION_USER_STOPPED);
        filter.addAction(Intent.ACTION_USER_UNLOCKED);
        mContext.registerReceiverAsUser(mUserChangeReceiver, UserHandle.ALL, filter, null, null);
    }

    /**
     * Assigns a default icon to a user according to the user's id.
     *
     * @param userInfo User to assign a default icon to.
     * @return Bitmap that has been assigned to the user.
     */
    private Bitmap assignDefaultIcon(UserInfo userInfo) {
        Bitmap bitmap = userInfo.isGuest() ? getGuestDefaultIcon() : getUserDefaultIcon(userInfo);
        mUserManager.setUserIcon(userInfo.id, bitmap);
        return bitmap;
    }

    private void switchToUserId(int id) {
        try {
            mActivityManager.switchUser(id);
        } catch (Exception e) {
            Log.e(TAG, "Couldn't switch user.", e);
        }
    }

    private void unregisterReceiver() {
        mContext.unregisterReceiver(mUserChangeReceiver);
    }

    /**
     * Interface for listeners that want to register for receiving updates to changes to the users
     * on the system including removing and adding users, and changing user info.
     */
    public interface OnUsersUpdateListener {
        /**
         * Method that will get called when users list has been changed.
         */
        void onUsersUpdate();
    }
}
+0 −332

File deleted.

Preview size limit exceeded, changes collapsed.

+0 −218
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.settingslib.users;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

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

import com.android.settingslib.testutils.shadow.ShadowActivityManager;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;

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

@RunWith(RobolectricTestRunner.class)
@Config(shadows = { ShadowActivityManager.class, UserManagerHelperRoboTest.ShadowUserHandle.class})
public class UserManagerHelperRoboTest {
    @Mock
    private Context mContext;
    @Mock
    private UserManager mUserManager;

    private UserManagerHelper mHelper;

    @Before
    public void setUpMocksAndUserManagerHelper() {
        MockitoAnnotations.initMocks(this);
        when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
        when(mContext.getSystemService(Context.ACTIVITY_SERVICE)).thenReturn(
                RuntimeEnvironment.application.getSystemService(ActivityManager.class));
        mHelper = new UserManagerHelper(mContext);
    }

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

    @Test
    public void getForegroundUserId() {
        ShadowActivityManager.setCurrentUser(15);
        assertThat(mHelper.getForegroundUserId()).isEqualTo(15);
    }

    @Test
    public void getForegroundUserInfo() {
        ShadowActivityManager.setCurrentUser(17);
        when(mUserManager.getUserInfo(ActivityManager.getCurrentUser()))
                .thenReturn(createUserInfoForId(ActivityManager.getCurrentUser()));
        assertThat(mHelper.getForegroundUserInfo().id).isEqualTo(17);
    }

    @Test
    public void getCurrentProcessUserId() {
        ShadowUserHandle.setUid(11);
        assertThat(mHelper.getCurrentProcessUserId()).isEqualTo(11);
    }

    @Test
    public void getCurrentProcessUserInfo() {
        ShadowUserHandle.setUid(12);
        when(mUserManager.getUserInfo(UserHandle.myUserId()))
                .thenReturn(createUserInfoForId(UserHandle.myUserId()));
        assertThat(mHelper.getCurrentProcessUserInfo().id).isEqualTo(12);
    }

    @Test
    public void getAllUsersExcludesCurrentProcessUser() {
        ShadowUserHandle.setUid(12);
        UserInfo currentProcessUser = createUserInfoForId(12);

        UserInfo otherUser1 = createUserInfoForId(13);
        UserInfo otherUser2 = createUserInfoForId(11);
        UserInfo otherUser3 = createUserInfoForId(14);

        List<UserInfo> testUsers = new ArrayList<>();
        testUsers.add(otherUser1);
        testUsers.add(otherUser2);
        testUsers.add(currentProcessUser);
        testUsers.add(otherUser3);

        when(mUserManager.getUsers(true)).thenReturn(testUsers);

        // Should return 3 users that don't have currentProcessUser id.
        assertThat(mHelper.getAllUsersExcludesCurrentProcessUser()).hasSize(3);
        assertThat(mHelper.getAllUsersExcludesCurrentProcessUser())
                .containsExactly(otherUser1, otherUser2, otherUser3);
    }

    @Test
    public void getAllUsersExcludesForegroundUser() {
        ShadowActivityManager.setCurrentUser(17);
        UserInfo foregroundUser = createUserInfoForId(17);

        UserInfo otherUser1 = createUserInfoForId(11);
        UserInfo otherUser2 = createUserInfoForId(18);
        UserInfo otherUser3 = createUserInfoForId(16);

        List<UserInfo> testUsers = new ArrayList<>();
        testUsers.add(otherUser1);
        testUsers.add(otherUser2);
        testUsers.add(foregroundUser);
        testUsers.add(otherUser3);

        when(mUserManager.getUsers(true)).thenReturn(testUsers);

        // Should return 3 users that don't have foregroundUser id.
        assertThat(mHelper.getAllUsersExcludesForegroundUser()).hasSize(3);
        assertThat(mHelper.getAllUsersExcludesForegroundUser())
                .containsExactly(otherUser1, otherUser2, otherUser3);
    }

    @Test
    public void userIsForegroundUser() {
        ShadowActivityManager.setCurrentUser(10);
        assertThat(mHelper.userIsForegroundUser(createUserInfoForId(10))).isTrue();
        assertThat(mHelper.userIsForegroundUser(createUserInfoForId(11))).isFalse();

        ShadowActivityManager.setCurrentUser(11);
        assertThat(mHelper.userIsForegroundUser(createUserInfoForId(11))).isTrue();
    }

    @Test
    public void userIsRunningCurrentProcess() {
        ShadowUserHandle.setUid(10);
        assertThat(mHelper.userIsRunningCurrentProcess(createUserInfoForId(10))).isTrue();
        assertThat(mHelper.userIsRunningCurrentProcess(createUserInfoForId(11))).isFalse();

        ShadowUserHandle.setUid(11);
        assertThat(mHelper.userIsRunningCurrentProcess(createUserInfoForId(11))).isTrue();
    }

    @Test
    public void removingCurrentProcessUserSwitchesToSystemUser() {
        // Set currentProcess user to be user 10.
        ShadowUserHandle.setUid(10);

        // Removing a currentProcess user, calls "switch" to system user
        mHelper.removeUser(createUserInfoForId(10));
        assertThat(ShadowActivityManager.getShadow().getSwitchUserCalled()).isTrue();
        assertThat(ShadowActivityManager.getShadow().getUserSwitchedTo()).isEqualTo(0);

        verify(mUserManager).removeUser(10);
    }

    @Test
    public void switchToUser() {
        ShadowActivityManager.setCurrentUser(20);

        // Switching to foreground user doesn't do anything.
        mHelper.switchToUser(createUserInfoForId(20));
        assertThat(ShadowActivityManager.getShadow().getSwitchUserCalled()).isFalse();

        // Switching to non-foreground user, simply calls switchUser.
        UserInfo userToSwitchTo = new UserInfo(22, "Test User", 0);
        mHelper.switchToUser(userToSwitchTo);
        assertThat(ShadowActivityManager.getShadow().getSwitchUserCalled()).isTrue();
        assertThat(ShadowActivityManager.getShadow().getUserSwitchedTo()).isEqualTo(22);
    }

    private UserInfo createUserInfoForId(int id) {
        UserInfo userInfo = new UserInfo();
        userInfo.id = id;
        return userInfo;
    }

    @Implements(UserHandle.class)
    public static class ShadowUserHandle {
        private static int sUid = 0; // SYSTEM by default

        public static void setUid(int uid) {
            sUid = uid;
        }

        @Implementation
        public static int myUserId() {
            return sUid;
        }

        @Resetter
        public static void reset() {
            sUid = 0;
        }
    }
}