blob: 1bda1bdbff78db1a9da47afd2d32d47ffc35342b [file] [log] [blame]
/*
* Copyright (C) 2020 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 android.multiuser.cts;
import static android.Manifest.permission.CREATE_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.QUERY_USERS;
import static android.content.pm.PackageManager.FEATURE_MANAGED_USERS;
import static android.multiuser.cts.PermissionHelper.adoptShellPermissionIdentity;
import static android.multiuser.cts.TestingUtils.getBooleanProperty;
import static android.os.UserManager.USER_OPERATION_SUCCESS;
import static android.os.UserManager.USER_TYPE_FULL_SECONDARY;
import static android.os.UserManager.USER_TYPE_PROFILE_CLONE;
import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED;
import static com.android.bedstead.harrier.OptionalBoolean.FALSE;
import static com.android.bedstead.harrier.OptionalBoolean.TRUE;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.assertThrows;
import static org.junit.Assume.assumeNoException;
import static org.junit.Assume.assumeNotNull;
import static org.junit.Assume.assumeTrue;
import android.app.ActivityManager;
import android.app.Instrumentation;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.content.pm.UserProperties;
import android.graphics.Bitmap;
import android.os.NewUserRequest;
import android.os.NewUserResponse;
import android.os.PersistableBundle;
import android.os.UserHandle;
import android.os.UserManager;
import android.platform.test.annotations.AppModeFull;
import android.platform.test.annotations.SystemUserOnly;
import android.util.Log;
import androidx.test.filters.FlakyTest;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.bedstead.harrier.BedsteadJUnit4;
import com.android.bedstead.harrier.DeviceState;
import com.android.bedstead.harrier.annotations.EnsureDoesNotHavePermission;
import com.android.bedstead.harrier.annotations.EnsureHasPermission;
import com.android.bedstead.harrier.annotations.EnsureHasWorkProfile;
import com.android.bedstead.harrier.annotations.RequireFeature;
import com.android.bedstead.harrier.annotations.RequireNotMultipleUsersOnMultipleDisplays;
import com.android.bedstead.harrier.annotations.RequireRunOnPrimaryUser;
import com.android.bedstead.harrier.annotations.RequireRunOnSecondaryUser;
import com.android.bedstead.harrier.annotations.RequireRunOnWorkProfile;
import com.android.bedstead.nene.TestApis;
import com.android.bedstead.nene.users.UserReference;
import com.android.compatibility.common.util.ApiTest;
import com.android.compatibility.common.util.BlockingBroadcastReceiver;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
@RunWith(BedsteadJUnit4.class)
public final class UserManagerTest {
private static final String TAG = UserManagerTest.class.getSimpleName();
@ClassRule
@Rule
public static final DeviceState sDeviceState = new DeviceState();
private static final Context sContext = TestApis.context().instrumentedContext();
private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
private UserManager mUserManager;
private final String mAccountName = "test_account_name";
private final String mAccountType = "test_account_type";
@Before
public void setUp() {
mUserManager = sContext.getSystemService(UserManager.class);
assertWithMessage("UserManager service").that(mUserManager).isNotNull();
}
private void removeUser(UserHandle userHandle) {
if (userHandle == null) {
return;
}
try (PermissionHelper ph = adoptShellPermissionIdentity(mInstrumentation, CREATE_USERS)) {
assertThat(mUserManager.removeUser(userHandle)).isTrue();
}
}
/**
* Verify that the isUserAGoat() method always returns false for API level 30. This is
* because apps targeting R no longer have access to package queries by default.
*/
@Test
public void testUserGoat_api30() {
assertWithMessage("isUserAGoat()").that(mUserManager.isUserAGoat()).isFalse();
}
@Test
public void testIsRemoveResultSuccessful() {
assertThat(UserManager.isRemoveResultSuccessful(UserManager.REMOVE_RESULT_REMOVED))
.isTrue();
assertThat(UserManager.isRemoveResultSuccessful(UserManager.REMOVE_RESULT_DEFERRED))
.isTrue();
assertThat(UserManager
.isRemoveResultSuccessful(UserManager.REMOVE_RESULT_ALREADY_BEING_REMOVED))
.isTrue();
assertThat(UserManager.isRemoveResultSuccessful(UserManager.REMOVE_RESULT_ERROR_UNKNOWN))
.isFalse();
assertThat(UserManager
.isRemoveResultSuccessful(UserManager.REMOVE_RESULT_ERROR_USER_RESTRICTION))
.isFalse();
assertThat(UserManager
.isRemoveResultSuccessful(UserManager.REMOVE_RESULT_ERROR_USER_NOT_FOUND))
.isFalse();
assertThat(
UserManager.isRemoveResultSuccessful(UserManager.REMOVE_RESULT_ERROR_SYSTEM_USER))
.isFalse();
}
@Test
public void testIsHeadlessSystemUserMode() throws Exception {
boolean expected = getBooleanProperty(mInstrumentation,
"ro.fw.mu.headless_system_user");
assertWithMessage("isHeadlessSystemUserMode()")
.that(UserManager.isHeadlessSystemUserMode()).isEqualTo(expected);
}
@Test
@ApiTest(apis = {"android.os.UserManager#isUserForeground"})
// TODO(b/240281790): should be @RequireRunOnDefaultUser instead of @RequireRunOnPrimaryUser
@RequireRunOnPrimaryUser(switchedToUser = TRUE)
public void testIsUserForeground_differentContext_noPermission() throws Exception {
Context context = getContextForOtherUser();
UserManager um = context.getSystemService(UserManager.class);
assertThrows(SecurityException.class, () -> um.isUserForeground());
}
@Test
@ApiTest(apis = {"android.os.UserManager#isUserForeground"})
@EnsureHasPermission(INTERACT_ACROSS_USERS)
public void testIsUserForeground_differentContext_withPermission() throws Exception {
Context userContext = sContext.createContextAsUser(UserHandle.of(-42), /* flags= */ 0);
UserManager um = userContext.getSystemService(UserManager.class);
assertWithMessage("isUserForeground() for unknown user").that(um.isUserForeground())
.isFalse();
}
@Test
@ApiTest(apis = {"android.os.UserManager#isUserForeground"})
// TODO(b/240281790): should be @RequireRunOnDefaultUser instead of @RequireRunOnPrimaryUser
public void testIsUserForeground_currentUser() throws Exception {
assertWithMessage("isUserForeground() for current user")
.that(mUserManager.isUserForeground()).isTrue();
}
@Test
@ApiTest(apis = {"android.os.UserManager#isUserForeground"})
@RequireRunOnSecondaryUser(switchedToUser = FALSE)
public void testIsUserForeground_backgroundUser() throws Exception {
assertWithMessage("isUserForeground() for bg user (%s)", sContext.getUser())
.that(mUserManager.isUserForeground()).isFalse();
}
@Test
@ApiTest(apis = {"android.os.UserManager#isUserForeground"})
@RequireRunOnWorkProfile // TODO(b/239961027): should be @RequireRunOnProfile instead
public void testIsUserForeground_profileOfCurrentUser() throws Exception {
assertWithMessage("isUserForeground() for profile(%s) of current user", sContext.getUser())
.that(mUserManager.isUserForeground()).isFalse();
}
@Test
@ApiTest(apis = {"android.os.UserManager#isUserRunning"})
// TODO(b/240281790): should be @RequireRunOnDefaultUser instead of @RequireRunOnPrimaryUser
@RequireRunOnPrimaryUser(switchedToUser = TRUE)
// TODO(b/239961027): should be @EnsureHasProfile instead of @EnsureHasWorkProfile
@EnsureHasWorkProfile(installInstrumentedApp = TRUE)
@EnsureHasPermission(INTERACT_ACROSS_USERS) // needed to call isUserRunning()
public void testIsUserRunning_stoppedProfileOfCurrentUser() {
UserReference profile = sDeviceState.workProfile();
Log.d(TAG, "Stopping profile " + profile + " (called from " + sContext.getUser() + ")");
profile.stop();
Context context = getContextForUser(profile.userHandle().getIdentifier());
UserManager um = context.getSystemService(UserManager.class);
assertWithMessage("isUserRunning() for stopped profile (id=%s) of current user",
profile.id()).that(um.isUserRunning(profile.userHandle()))
.isFalse();
}
@Test
@ApiTest(apis = {"android.os.UserManager#isUserRunning"})
@RequireRunOnSecondaryUser(switchedToUser = FALSE)
@EnsureHasPermission(INTERACT_ACROSS_USERS) // needed to call isUserRunning()
public void testIsUserRunning_stoppedSecondaryUser() {
UserReference user = TestApis.users().instrumented();
Log.d(TAG, "Stopping user " + user + " (called from " + sContext.getUser() + ")");
user.stop();
Context context = getContextForUser(user.userHandle().getIdentifier());
UserManager um = context.getSystemService(UserManager.class);
assertWithMessage("isUserRunning() for stopped secondary user (id=%s)",
user.id()).that(um.isUserRunning(user.userHandle())).isFalse();
}
@Test
@ApiTest(apis = {"android.os.UserManager#isUserVisible"})
@EnsureDoesNotHavePermission(INTERACT_ACROSS_USERS)
public void testIsUserVisible_differentContext_noPermission() throws Exception {
Context context = sContext.createContextAsUser(UserHandle.of(-42), /* flags= */ 0);
UserManager um = context.getSystemService(UserManager.class);
assertThrows(SecurityException.class, () -> um.isUserVisible());
}
@Test
@ApiTest(apis = {"android.os.UserManager#isUserVisible"})
@EnsureHasPermission(INTERACT_ACROSS_USERS)
public void testIsUserVisible_differentContext_withPermission() throws Exception {
Context context = getContextForOtherUser();
UserManager um = context.getSystemService(UserManager.class);
assertWithMessage("isUserVisible() for unknown user").that(um.isUserVisible()).isFalse();
}
@Test
@ApiTest(apis = {"android.os.UserManager#isUserVisible"})
// TODO(b/240281790): should be @RequireRunOnDefaultUser instead of @RequireRunOnPrimaryUser
@RequireRunOnPrimaryUser(switchedToUser = TRUE)
public void testIsUserVisible_currentUser() throws Exception {
assertWithMessage("isUserVisible() for current user (id=%s)", sContext.getUser())
.that(mUserManager.isUserVisible()).isTrue();
}
@Test
@ApiTest(apis = {"android.os.UserManager#isUserVisible"})
@RequireRunOnSecondaryUser(switchedToUser = FALSE)
public void testIsUserVisible_backgroundUser() throws Exception {
assertWithMessage("isUserVisible() for background user (id=%s)", sContext.getUser())
.that(mUserManager.isUserVisible()).isFalse();
}
@Test
@ApiTest(apis = {"android.os.UserManager#isUserVisible"})
// TODO(b/239961027): should be @RequireRunOnProfile instead
@RequireRunOnWorkProfile(switchedToParentUser = TRUE)
public void testIsUserVisible_startedProfileOfCurrentUser() throws Exception {
assertWithMessage("isUserVisible() for profile of current user (%s)",
sContext.getUser()).that(mUserManager.isUserVisible()).isTrue();
}
@FlakyTest(bugId = 242364454)
@Test
@ApiTest(apis = {"android.os.UserManager#isUserVisible"})
// TODO(b/240281790): should be @RequireRunOnDefaultUser instead of @RequireRunOnPrimaryUser
// Cannot use @RunOnProfile as it will stop the profile
@RequireRunOnPrimaryUser(switchedToUser = TRUE)
// TODO(b/239961027): should be @EnsureHasProfile instead of @EnsureHasWorkProfile
@EnsureHasWorkProfile(installInstrumentedApp = TRUE)
@EnsureHasPermission(INTERACT_ACROSS_USERS) // needed to call isUserVisible() on other context
public void testIsUserVisible_stoppedProfileOfCurrentUser() throws Exception {
UserReference profile = sDeviceState.workProfile();
Log.d(TAG, "Stopping profile " + profile + " (called from " + sContext.getUser() + ")");
profile.stop();
Context context = getContextForUser(profile.userHandle().getIdentifier());
UserManager um = context.getSystemService(UserManager.class);
assertWithMessage("isUserVisible() for stopped profile (id=%s) of current user",
profile.id()).that(um.isUserVisible()).isFalse();
}
@Test
@ApiTest(apis = {"android.os.UserManager#getVisibleUsers"})
@EnsureDoesNotHavePermission(INTERACT_ACROSS_USERS)
public void testGetVisibleUsers_noPermission() throws Exception {
Context context = getContextForOtherUser();
UserManager um = context.getSystemService(UserManager.class);
assertThrows(SecurityException.class, () -> um.getVisibleUsers());
}
@Test
@ApiTest(apis = {"android.os.UserManager#getVisibleUsers"})
// TODO(b/240281790): should be @RequireRunOnDefaultUser instead of @RequireRunOnPrimaryUser
@RequireRunOnPrimaryUser(switchedToUser = TRUE)
@EnsureHasPermission(INTERACT_ACROSS_USERS) // needed to call getVisibleUsers()
public void testGetVisibleUsers_currentUser() throws Exception {
List<UserHandle> visibleUsers = mUserManager.getVisibleUsers();
assertWithMessage("getVisibleUsers()").that(visibleUsers)
.contains(TestApis.users().current().userHandle());
}
@Test
@ApiTest(apis = {"android.os.UserManager#getVisibleUsers"})
@RequireRunOnSecondaryUser(switchedToUser = FALSE)
@EnsureHasPermission(INTERACT_ACROSS_USERS) // needed to call getVisibleUsers()
public void testGetVisibleUsers_backgroundUser() throws Exception {
List<UserHandle> visibleUsers = mUserManager.getVisibleUsers();
assertWithMessage("getVisibleUsers()").that(visibleUsers)
.contains(TestApis.users().current().userHandle());
}
@Test
@ApiTest(apis = {"android.os.UserManager#getVisibleUsers"})
// TODO(b/239961027): should be @RequireRunOnProfile instead
@RequireRunOnWorkProfile(switchedToParentUser = TRUE)
@EnsureHasPermission(INTERACT_ACROSS_USERS) // needed to call getVisibleUsers()
public void testGetVisibleUsers_startedProfileOfCurrentUser() throws Exception {
UserReference myUser = TestApis.users().instrumented();
List<UserHandle> visibleUsers = mUserManager.getVisibleUsers();
assertWithMessage("getVisibleUsers()").that(visibleUsers)
.containsAtLeast(myUser.userHandle(), myUser.parent().userHandle());
}
@FlakyTest(bugId = 242364454)
@Test
@ApiTest(apis = {"android.os.UserManager#getVisibleUsers"})
// TODO(b/240281790): should be @RequireRunOnDefaultUser instead of @RequireRunOnPrimaryUser
// Cannot use @RunOnProfile as it will stop the profile
@RequireRunOnPrimaryUser(switchedToUser = TRUE)
// TODO(b/239961027): should be @EnsureHasProfile instead of @EnsureHasWorkProfile
@EnsureHasWorkProfile(installInstrumentedApp = TRUE)
@EnsureHasPermission(INTERACT_ACROSS_USERS) // needed to call getVisibleUsers()
public void testGetVisibleUsers_stoppedProfileOfCurrentUser() throws Exception {
UserReference profile = sDeviceState.workProfile();
Log.d(TAG, "Stopping profile " + profile + " (called from " + sContext.getUser() + ")");
profile.stop();
Context context = getContextForUser(profile.userHandle().getIdentifier());
UserManager um = context.getSystemService(UserManager.class);
List<UserHandle> visibleUsers = mUserManager.getVisibleUsers();
assertWithMessage("getVisibleUsers()").that(visibleUsers)
.contains(TestApis.users().current().userHandle());
assertWithMessage("getVisibleUsers()").that(visibleUsers)
.doesNotContain(profile.userHandle());
}
@Test
@RequireNotMultipleUsersOnMultipleDisplays(reason = "Because API is not supported")
@ApiTest(apis = {"android.app.ActivityManager#startUserInBackgroundOnSecondaryDisplay"})
public void testStartUserInBackgroundOnSecondaryDisplay() {
// ids doen't really matter, as it should throw right away
assertThrows(UnsupportedOperationException.class,
() -> tryToStartBackgroundUserOnSecondaryDisplay(42, 108));
}
@Test
@ApiTest(apis = {"android.os.UserManager#createProfile"})
public void testCloneProfile() throws Exception {
assumeTrue(mUserManager.supportsMultipleUsers());
UserHandle userHandle = null;
// Need CREATE_USERS permission to create user in test
try (PermissionHelper ph = adoptShellPermissionIdentity(mInstrumentation, CREATE_USERS)) {
try {
userHandle = mUserManager.createProfile(
"Clone profile", USER_TYPE_PROFILE_CLONE, new HashSet<>());
} catch (UserManager.UserOperationException e) {
// Not all devices and user types support these profiles; skip if this one doesn't.
assumeNoException("Couldn't create clone profile", e);
return;
}
assertThat(userHandle).isNotNull();
final Context userContext = sContext.createPackageContextAsUser("system", 0,
userHandle);
final UserManager cloneUserManager = userContext.getSystemService(UserManager.class);
assertThat(cloneUserManager.isMediaSharedWithParent()).isTrue();
assertThat(cloneUserManager.isCredentialSharableWithParent()).isTrue();
assertThat(cloneUserManager.isCloneProfile()).isTrue();
assertThat(cloneUserManager.isProfile()).isTrue();
assertThat(cloneUserManager.isUserOfType(UserManager.USER_TYPE_PROFILE_CLONE)).isTrue();
final List<UserInfo> list = mUserManager.getUsers(true, true, true);
final UserHandle finalUserHandle = userHandle;
final List<UserInfo> cloneUsers = list.stream().filter(
user -> (user.id == finalUserHandle.getIdentifier()
&& user.isCloneProfile()))
.collect(Collectors.toList());
assertThat(cloneUsers.size()).isEqualTo(1);
} finally {
removeUser(userHandle);
}
}
@Test
@ApiTest(apis = {"android.os.UserManager#createProfile"})
@AppModeFull
public void testAddCloneProfile_shouldSendProfileAddedBroadcast() {
assumeTrue(mUserManager.supportsMultipleUsers());
BlockingBroadcastReceiver broadcastReceiver = sDeviceState
.registerBroadcastReceiver(Intent.ACTION_PROFILE_ADDED, /* checker= */null);
UserHandle userHandle = null;
try (PermissionHelper ph = adoptShellPermissionIdentity(mInstrumentation, CREATE_USERS)) {
try {
userHandle = mUserManager.createProfile("Clone profile",
USER_TYPE_PROFILE_CLONE, new HashSet<>());
assumeNotNull(userHandle);
broadcastReceiver.awaitForBroadcastOrFail();
} catch (UserManager.UserOperationException e) {
assumeNoException("Couldn't create clone profile", e);
} finally {
removeUser(userHandle);
}
}
}
@Test
@ApiTest(apis = {"android.os.UserManager#createProfile"})
@AppModeFull
@RequireFeature(FEATURE_MANAGED_USERS)
public void testCreateManagedProfile_shouldSendProfileAddedBroadcast() {
BlockingBroadcastReceiver broadcastReceiver = sDeviceState
.registerBroadcastReceiver(Intent.ACTION_PROFILE_ADDED, /* checker= */null);
UserHandle userHandle = null;
try (PermissionHelper ph = adoptShellPermissionIdentity(mInstrumentation, CREATE_USERS)) {
try {
userHandle = mUserManager.createProfile("Managed profile",
USER_TYPE_PROFILE_MANAGED, new HashSet<>());
assumeNotNull(userHandle);
broadcastReceiver.awaitForBroadcastOrFail();
} catch (UserManager.UserOperationException e) {
assumeNoException("Couldn't create managed profile", e);
} finally {
removeUser(userHandle);
}
}
}
@Test
@ApiTest(apis = {"android.os.UserManager#createProfile"})
@AppModeFull
public void testRemoveCloneProfile_shouldSendProfileRemovedBroadcast() {
assumeTrue(mUserManager.supportsMultipleUsers());
BlockingBroadcastReceiver broadcastReceiver = null;
UserHandle userHandle = null;
try (PermissionHelper ph = adoptShellPermissionIdentity(mInstrumentation, CREATE_USERS)) {
try {
userHandle = mUserManager.createProfile("Clone profile",
USER_TYPE_PROFILE_CLONE, new HashSet<>());
broadcastReceiver = sDeviceState
.registerBroadcastReceiver(
Intent.ACTION_PROFILE_REMOVED, userIsEqual(userHandle)
);
assumeNotNull(userHandle);
removeUser(userHandle);
broadcastReceiver.awaitForBroadcastOrFail();
} catch (UserManager.UserOperationException e) {
assumeNoException("Couldn't create clone profile", e);
}
}
}
@Test
@ApiTest(apis = {"android.os.UserManager#createProfile"})
@AppModeFull
@RequireFeature(FEATURE_MANAGED_USERS)
public void testRemoveManagedProfile_shouldSendProfileRemovedBroadcast() {
BlockingBroadcastReceiver broadcastReceiver = null;
UserHandle userHandle = null;
try (PermissionHelper ph = adoptShellPermissionIdentity(mInstrumentation, CREATE_USERS)) {
try {
userHandle = mUserManager.createProfile("Managed profile",
USER_TYPE_PROFILE_MANAGED, new HashSet<>());
broadcastReceiver = sDeviceState
.registerBroadcastReceiver(
Intent.ACTION_PROFILE_REMOVED, userIsEqual(userHandle)
);
assumeNotNull(userHandle);
removeUser(userHandle);
broadcastReceiver.awaitForBroadcastOrFail();
} catch (UserManager.UserOperationException e) {
assumeNoException("Couldn't create managed profile", e);
}
}
}
@Test
@RequireFeature(FEATURE_MANAGED_USERS)
@EnsureHasPermission({CREATE_USERS, QUERY_USERS})
@ApiTest(apis = {
"android.os.UserManager#createProfile",
"android.os.UserManager#isManagedProfile",
"android.os.UserManager#isProfile",
"android.os.UserManager#isUserOfType"})
public void testManagedProfile() throws Exception {
UserHandle userHandle = null;
try {
try {
userHandle = mUserManager.createProfile(
"Managed profile", UserManager.USER_TYPE_PROFILE_MANAGED, new HashSet<>());
} catch (UserManager.UserOperationException e) {
// Not all devices and user types support these profiles; skip if this one doesn't.
assumeNoException("Couldn't create managed profile", e);
return;
}
assertThat(userHandle).isNotNull();
final UserManager umOfProfile = sContext
.createPackageContextAsUser("android", 0, userHandle)
.getSystemService(UserManager.class);
assertThat(umOfProfile.isManagedProfile()).isTrue();
assertThat(umOfProfile.isManagedProfile(userHandle.getIdentifier())).isTrue();
assertThat(umOfProfile.isProfile()).isTrue();
assertThat(umOfProfile.isUserOfType(UserManager.USER_TYPE_PROFILE_MANAGED)).isTrue();
} finally {
removeUser(userHandle);
}
}
@Test
@EnsureHasPermission({QUERY_USERS})
@ApiTest(apis = {
"android.os.UserManager#isSystemUser",
"android.os.UserManager#isUserOfType",
"android.os.UserManager#isProfile",
"android.os.UserManager#isManagedProfile",
"android.os.UserManager#isCloneProfile"})
public void testSystemUser() throws Exception {
final UserManager umOfSys = sContext
.createPackageContextAsUser("android", 0, UserHandle.SYSTEM)
.getSystemService(UserManager.class);
assertThat(umOfSys.isSystemUser()).isTrue();
// We cannot demand what type of user SYSTEM is, but we can say some things it isn't.
assertThat(umOfSys.isUserOfType(UserManager.USER_TYPE_PROFILE_CLONE)).isFalse();
assertThat(umOfSys.isUserOfType(UserManager.USER_TYPE_PROFILE_MANAGED)).isFalse();
assertThat(umOfSys.isUserOfType(UserManager.USER_TYPE_FULL_GUEST)).isFalse();
assertThat(umOfSys.isProfile()).isFalse();
assertThat(umOfSys.isManagedProfile()).isFalse();
assertThat(umOfSys.isManagedProfile(UserHandle.USER_SYSTEM)).isFalse();
assertThat(umOfSys.isCloneProfile()).isFalse();
}
@Test
@SystemUserOnly(reason = "Restricted users are only supported on system user.")
@ApiTest(apis = {
"android.os.UserManager#isRestrictedProfile",
"android.os.UserManager#getRestrictedProfileParent",
"android.os.UserManager#createRestrictedProfile"})
public void testRestrictedUser() throws Exception {
UserHandle user = null;
try (PermissionHelper ph = adoptShellPermissionIdentity(mInstrumentation, CREATE_USERS)) {
// Check that the SYSTEM user is not restricted.
assertThat(mUserManager.isRestrictedProfile()).isFalse();
assertThat(mUserManager.isRestrictedProfile(UserHandle.SYSTEM)).isFalse();
assertThat(mUserManager.getRestrictedProfileParent()).isNull();
final UserInfo info = mUserManager.createRestrictedProfile("Restricted user");
// If the device supports Restricted users, it must report it correctly.
assumeTrue("Couldn't create a restricted profile", info != null);
user = UserHandle.of(info.id);
assertThat(mUserManager.isRestrictedProfile(user)).isTrue();
final Context userContext = sContext.createPackageContextAsUser("system", 0, user);
final UserManager userUm = userContext.getSystemService(UserManager.class);
assertThat(userUm.isRestrictedProfile()).isTrue();
assertThat(userUm.getRestrictedProfileParent().isSystem()).isTrue();
} finally {
removeUser(user);
}
}
private NewUserRequest newUserRequest() {
final PersistableBundle accountOptions = new PersistableBundle();
accountOptions.putString("test_account_option_key", "test_account_option_value");
return new NewUserRequest.Builder()
.setName("test_user")
.setUserType(USER_TYPE_FULL_SECONDARY)
.setUserIcon(Bitmap.createBitmap(32, 32, Bitmap.Config.RGB_565))
.setAccountName(mAccountName)
.setAccountType(mAccountType)
.setAccountOptions(accountOptions)
.build();
}
@Test
public void testSomeUserHasAccount() {
// TODO: (b/233197356): Replace with bedstead annotation.
assumeTrue(mUserManager.supportsMultipleUsers());
UserHandle user = null;
try (PermissionHelper ph = adoptShellPermissionIdentity(mInstrumentation, CREATE_USERS)) {
assertThat(mUserManager.someUserHasAccount(mAccountName, mAccountType)).isFalse();
user = mUserManager.createUser(newUserRequest()).getUser();
assertThat(mUserManager.someUserHasAccount(mAccountName, mAccountType)).isTrue();
} finally {
removeUser(user);
}
}
@Test
public void testSomeUserHasAccount_shouldIgnoreToBeRemovedUsers() {
// TODO: (b/233197356): Replace with bedstead annotation.
assumeTrue(mUserManager.supportsMultipleUsers());
try (PermissionHelper ph = adoptShellPermissionIdentity(mInstrumentation, CREATE_USERS)) {
final NewUserResponse response = mUserManager.createUser(newUserRequest());
assertThat(response.getOperationResult()).isEqualTo(USER_OPERATION_SUCCESS);
mUserManager.removeUser(response.getUser());
assertThat(mUserManager.someUserHasAccount(mAccountName, mAccountType)).isFalse();
}
}
@Test
@ApiTest(apis = {
"android.os.UserManager#supportsMultipleUsers",
"android.os.UserManager#createUser",
"android.os.UserManager#getUserName",
"android.os.UserManager#isUserNameSet",
"android.os.UserManager#getUserType",
"android.os.UserManager#isUserOfType"})
public void testCreateUser_withNewUserRequest_shouldCreateUserWithCorrectProperties()
throws PackageManager.NameNotFoundException {
// TODO: (b/233197356): Replace with bedstead annotation.
assumeTrue(mUserManager.supportsMultipleUsers());
UserHandle user = null;
try (PermissionHelper ph = adoptShellPermissionIdentity(mInstrumentation, CREATE_USERS)) {
final NewUserRequest request = newUserRequest();
final NewUserResponse response = mUserManager.createUser(request);
user = response.getUser();
assertThat(response.getOperationResult()).isEqualTo(USER_OPERATION_SUCCESS);
assertThat(response.isSuccessful()).isTrue();
assertThat(user).isNotNull();
UserManager userManagerOfNewUser = sContext
.createPackageContextAsUser("android", 0, user)
.getSystemService(UserManager.class);
assertThat(userManagerOfNewUser.getUserName()).isEqualTo(request.getName());
assertThat(userManagerOfNewUser.isUserNameSet()).isTrue();
assertThat(userManagerOfNewUser.getUserType()).isEqualTo(request.getUserType());
assertThat(userManagerOfNewUser.isUserOfType(request.getUserType())).isEqualTo(true);
// We can not test userIcon and accountOptions,
// because getters require MANAGE_USERS permission.
// And we are already testing accountName and accountType
// are set correctly in testSomeUserHasAccount method.
} finally {
removeUser(user);
}
}
@Test
public void testCreateUser_withNewUserRequest_shouldNotAllowDuplicateUserAccounts() {
// TODO: (b/233197356): Replace with bedstead annotation.
assumeTrue(mUserManager.supportsMultipleUsers());
UserHandle user1 = null;
UserHandle user2 = null;
try (PermissionHelper ph = adoptShellPermissionIdentity(mInstrumentation, CREATE_USERS)) {
final NewUserResponse response1 = mUserManager.createUser(newUserRequest());
user1 = response1.getUser();
assertThat(response1.getOperationResult()).isEqualTo(USER_OPERATION_SUCCESS);
assertThat(response1.isSuccessful()).isTrue();
assertThat(user1).isNotNull();
final NewUserResponse response2 = mUserManager.createUser(newUserRequest());
user2 = response2.getUser();
assertThat(response2.getOperationResult()).isEqualTo(
UserManager.USER_OPERATION_ERROR_USER_ACCOUNT_ALREADY_EXISTS);
assertThat(response2.isSuccessful()).isFalse();
assertThat(user2).isNull();
} finally {
removeUser(user1);
removeUser(user2);
}
}
@Test
@AppModeFull
@EnsureHasWorkProfile
@EnsureHasPermission(INTERACT_ACROSS_USERS)
public void getProfileParent_returnsParent() {
final UserReference parent = TestApis.users().instrumented();
for (UserHandle profile : mUserManager.getUserProfiles()) {
if (!profile.equals(parent.userHandle())) {
assertThat(mUserManager.getProfileParent(profile)).isEqualTo(parent.userHandle());
}
}
}
@Test
@AppModeFull
@EnsureHasPermission(INTERACT_ACROSS_USERS)
public void getProfileParent_returnsNullForNonProfile() {
assertThat(mUserManager.getProfileParent(TestApis.users().system().userHandle())).isNull();
}
@Test
@EnsureHasPermission({CREATE_USERS, QUERY_USERS})
public void testGetRemainingCreatableUserCount() {
final int maxAllowedIterations = 15;
final String userType = USER_TYPE_FULL_SECONDARY;
final NewUserRequest request = new NewUserRequest.Builder().build();
final ArrayDeque<UserHandle> usersCreated = new ArrayDeque<>();
try {
final int initialRemainingCount = mUserManager.getRemainingCreatableUserCount(userType);
assertThat(initialRemainingCount).isAtLeast(0);
final int numUsersToAdd = Math.min(maxAllowedIterations, initialRemainingCount);
for (int i = 0; i < numUsersToAdd; i++) {
usersCreated.push(mUserManager.createUser(request).getUser());
assertThat(mUserManager.getRemainingCreatableUserCount(userType))
.isEqualTo(initialRemainingCount - usersCreated.size());
}
for (int i = 0; i < numUsersToAdd; i++) {
mUserManager.removeUser(usersCreated.pop());
assertThat(mUserManager.getRemainingCreatableUserCount(userType))
.isEqualTo(initialRemainingCount - usersCreated.size());
}
} finally {
usersCreated.forEach(this::removeUser);
}
}
@Test
@EnsureHasPermission({CREATE_USERS, QUERY_USERS})
public void testGetRemainingCreatableProfileCount() {
final int maxAllowedIterations = 15;
final String type = USER_TYPE_PROFILE_MANAGED;
final ArrayDeque<UserHandle> profilesCreated = new ArrayDeque<>();
final Set<String> disallowedPackages = new HashSet<>();
try {
final int initialRemainingCount =
mUserManager.getRemainingCreatableProfileCount(type);
assertThat(initialRemainingCount).isAtLeast(0);
final int numUsersToAdd = Math.min(maxAllowedIterations, initialRemainingCount);
for (int i = 0; i < numUsersToAdd; i++) {
profilesCreated.push(mUserManager.createProfile(null, type, disallowedPackages));
assertThat(mUserManager.getRemainingCreatableProfileCount(type))
.isEqualTo(initialRemainingCount - profilesCreated.size());
}
for (int i = 0; i < numUsersToAdd; i++) {
mUserManager.removeUser(profilesCreated.pop());
assertThat(mUserManager.getRemainingCreatableProfileCount(type))
.isEqualTo(initialRemainingCount - profilesCreated.size());
}
} finally {
profilesCreated.forEach(this::removeUser);
}
}
@Test
@ApiTest(apis = {"android.os.UserManager#getUserProperties"})
@AppModeFull
@EnsureHasPermission({CREATE_USERS, QUERY_USERS})
public void testGetUserProperties_system() {
final UserHandle fullUser = TestApis.users().instrumented().userHandle();
final UserProperties properties = mUserManager.getUserProperties(fullUser);
assertThat(properties).isNotNull();
assertThat(properties.getShowInLauncher()).isIn(Arrays.asList(
UserProperties.SHOW_IN_LAUNCHER_WITH_PARENT));
}
@Test
@ApiTest(apis = {"android.os.UserManager#getUserProperties"})
@AppModeFull
@EnsureHasWorkProfile
@RequireFeature(FEATURE_MANAGED_USERS)
@EnsureHasPermission({CREATE_USERS, QUERY_USERS})
public void testGetUserProperties_managedProfile() {
final UserHandle profile = sDeviceState.workProfile().userHandle();
final UserProperties properties = mUserManager.getUserProperties(profile);
assertThat(properties).isNotNull();
assertThat(properties.getShowInLauncher()).isIn(Arrays.asList(
UserProperties.SHOW_IN_LAUNCHER_WITH_PARENT,
UserProperties.SHOW_IN_LAUNCHER_SEPARATE));
}
static Context getContextForOtherUser() {
// TODO(b/240207590): TestApis.context().instrumentedContextForUser(TestApis.users()
// .nonExisting() doesn't work, it throws:
// IllegalStateException: Own package not found for user 1: package=android.multiuser.cts
// There might be some bug (or WAI :-) on ContextImpl that makes it behave different for
// negative user ids. Anyways, for the purpose of this test, this workaround is fine (i.e.
// the context user id is passed to the binder call and the service checks if it matches the
// caller or the caller has the proper permission when it doesn't.
return getContextForUser(-42);
}
static Context getContextForUser(int userId) {
Log.d(TAG, "Getting context for user " + userId);
Context context = sContext.createContextAsUser(UserHandle.of(userId), /* flags= */ 0);
Log.d(TAG, "Got it: " + context);
return context;
}
private Function<Intent, Boolean> userIsEqual(UserHandle userHandle) {
try {
return (intent) -> userHandle.equals(intent.getParcelableExtra(intent.EXTRA_USER));
} catch (NullPointerException e) {
assumeNoException("User handle is null", e);
}
return (intent) -> false;
}
// TODO(b/240736142): should be provided by Test Bedstead
private boolean tryToStartBackgroundUserOnSecondaryDisplay(int userId, int displayId) {
Log.d(TAG, "tryToStartBackgroundUserOnSecondaryDisplay(): user=" + userId + ", display="
+ displayId);
try (PermissionHelper ph = adoptShellPermissionIdentity(mInstrumentation, CREATE_USERS)) {
boolean started = sContext.getSystemService(ActivityManager.class)
.startUserInBackgroundOnSecondaryDisplay(userId, displayId);
Log.d(TAG, "Started: " + started);
return started;
}
}
}