Merge "[User Switcher] Add user and guest on bg thread." into tm-qpr-dev am: 57f5c6bcf1 am: 76b091fd09
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/19324250 Change-Id: I87b626f671cf38d753d057d4d7e4da345e6c2fd6 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -62,7 +62,6 @@ import com.android.internal.logging.UiEventLogger;
|
||||
import com.android.internal.util.LatencyTracker;
|
||||
import com.android.settingslib.RestrictedLockUtilsInternal;
|
||||
import com.android.settingslib.users.UserCreatingDialog;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
import com.android.systemui.Dumpable;
|
||||
import com.android.systemui.GuestResetOrExitSessionReceiver;
|
||||
import com.android.systemui.GuestResumeSessionReceiver;
|
||||
@@ -939,15 +938,17 @@ public class UserSwitcherController implements Dumpable {
|
||||
guestCreationProgressDialog.show();
|
||||
|
||||
// userManager.createGuest will block the thread so post is needed for the dialog to show
|
||||
ThreadUtils.postOnMainThread(() -> {
|
||||
mBgExecutor.execute(() -> {
|
||||
final int guestId = createGuest();
|
||||
guestCreationProgressDialog.dismiss();
|
||||
if (guestId == UserHandle.USER_NULL) {
|
||||
Toast.makeText(mContext,
|
||||
com.android.settingslib.R.string.add_guest_failed,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
callback.accept(guestId);
|
||||
mUiExecutor.execute(() -> {
|
||||
guestCreationProgressDialog.dismiss();
|
||||
if (guestId == UserHandle.USER_NULL) {
|
||||
Toast.makeText(mContext,
|
||||
com.android.settingslib.R.string.add_guest_failed,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
callback.accept(guestId);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* 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 com.android.systemui.user;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.UserManager;
|
||||
|
||||
import com.android.internal.util.UserIcons;
|
||||
import com.android.settingslib.users.UserCreatingDialog;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* A class to do the user creation process. It shows a progress dialog, and manages the user
|
||||
* creation
|
||||
*/
|
||||
public class UserCreator {
|
||||
|
||||
private final Context mContext;
|
||||
private final UserManager mUserManager;
|
||||
|
||||
@Inject
|
||||
public UserCreator(Context context, UserManager userManager) {
|
||||
mContext = context;
|
||||
mUserManager = userManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a progress dialog then starts the user creation process on the main thread.
|
||||
*
|
||||
* @param successCallback is called when the user creation is successful.
|
||||
* @param errorCallback is called when userManager.createUser returns null.
|
||||
* (Exceptions are not handled by this class)
|
||||
*/
|
||||
public void createUser(String userName, Drawable userIcon, Consumer<UserInfo> successCallback,
|
||||
Runnable errorCallback) {
|
||||
|
||||
Dialog userCreationProgressDialog = new UserCreatingDialog(mContext);
|
||||
userCreationProgressDialog.show();
|
||||
|
||||
// userManager.createUser will block the thread so post is needed for the dialog to show
|
||||
ThreadUtils.postOnMainThread(() -> {
|
||||
UserInfo user =
|
||||
mUserManager.createUser(userName, UserManager.USER_TYPE_FULL_SECONDARY, 0);
|
||||
if (user == null) {
|
||||
// Couldn't create user for some reason
|
||||
userCreationProgressDialog.dismiss();
|
||||
errorCallback.run();
|
||||
return;
|
||||
}
|
||||
|
||||
Drawable newUserIcon = userIcon;
|
||||
Resources res = mContext.getResources();
|
||||
if (newUserIcon == null) {
|
||||
newUserIcon = UserIcons.getDefaultUserIcon(res, user.id, false);
|
||||
}
|
||||
mUserManager.setUserIcon(
|
||||
user.id, UserIcons.convertToBitmapAtUserIconSize(res, newUserIcon));
|
||||
|
||||
userCreationProgressDialog.dismiss();
|
||||
successCallback.accept(user);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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 com.android.systemui.user
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.content.pm.UserInfo
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.UserManager
|
||||
import com.android.internal.util.UserIcons
|
||||
import com.android.settingslib.users.UserCreatingDialog
|
||||
import com.android.systemui.dagger.qualifiers.Background
|
||||
import com.android.systemui.dagger.qualifiers.Main
|
||||
import java.util.concurrent.Executor
|
||||
import java.util.function.Consumer
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* A class to do the user creation process. It shows a progress dialog, and manages the user
|
||||
* creation
|
||||
*/
|
||||
class UserCreator @Inject constructor(
|
||||
private val context: Context,
|
||||
private val userManager: UserManager,
|
||||
@Main private val mainExecutor: Executor,
|
||||
@Background private val bgExecutor: Executor
|
||||
) {
|
||||
/**
|
||||
* Shows a progress dialog then starts the user creation process on the main thread.
|
||||
*
|
||||
* @param successCallback is called when the user creation is successful.
|
||||
* @param errorCallback is called when userManager.createUser returns null.
|
||||
* (Exceptions are not handled by this class)
|
||||
*/
|
||||
fun createUser(
|
||||
userName: String?,
|
||||
userIcon: Drawable?,
|
||||
successCallback: Consumer<UserInfo?>,
|
||||
errorCallback: Runnable
|
||||
) {
|
||||
val userCreationProgressDialog: Dialog = UserCreatingDialog(context)
|
||||
userCreationProgressDialog.show()
|
||||
|
||||
// userManager.createUser will block the thread so post is needed for the dialog to show
|
||||
bgExecutor.execute {
|
||||
val user = userManager.createUser(userName, UserManager.USER_TYPE_FULL_SECONDARY, 0)
|
||||
mainExecutor.execute main@{
|
||||
if (user == null) {
|
||||
// Couldn't create user for some reason
|
||||
userCreationProgressDialog.dismiss()
|
||||
errorCallback.run()
|
||||
return@main
|
||||
}
|
||||
bgExecutor.execute {
|
||||
var newUserIcon = userIcon
|
||||
val res = context.resources
|
||||
if (newUserIcon == null) {
|
||||
newUserIcon = UserIcons.getDefaultUserIcon(res, user.id, false)
|
||||
}
|
||||
userManager.setUserIcon(
|
||||
user.id, UserIcons.convertToBitmapAtUserIconSize(res, newUserIcon))
|
||||
}
|
||||
userCreationProgressDialog.dismiss()
|
||||
successCallback.accept(user)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,6 +77,7 @@ import org.mockito.Mockito.doNothing
|
||||
import org.mockito.Mockito.doReturn
|
||||
import org.mockito.Mockito.eq
|
||||
import org.mockito.Mockito.mock
|
||||
import org.mockito.Mockito.never
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.MockitoAnnotations
|
||||
@@ -269,6 +270,8 @@ class UserSwitcherControllerTest : SysuiTestCase() {
|
||||
`when`(userManager.createGuest(any())).thenReturn(guestInfo)
|
||||
|
||||
userSwitcherController.onUserListItemClicked(emptyGuestUserRecord, null)
|
||||
bgExecutor.runAllReady()
|
||||
uiExecutor.runAllReady()
|
||||
testableLooper.processAllMessages()
|
||||
verify(interactionJankMonitor).begin(any())
|
||||
verify(latencyTracker).onActionStart(LatencyTracker.ACTION_USER_SWITCH)
|
||||
@@ -294,6 +297,8 @@ class UserSwitcherControllerTest : SysuiTestCase() {
|
||||
`when`(userManager.createGuest(any())).thenReturn(guestInfo)
|
||||
|
||||
userSwitcherController.onUserListItemClicked(emptyGuestUserRecord, dialogShower)
|
||||
bgExecutor.runAllReady()
|
||||
uiExecutor.runAllReady()
|
||||
testableLooper.processAllMessages()
|
||||
verify(dialogShower).dismiss()
|
||||
}
|
||||
@@ -584,4 +589,24 @@ class UserSwitcherControllerTest : SysuiTestCase() {
|
||||
broadcastReceiverCaptor.value.onReceive(context, intent)
|
||||
verify(cb).onUserSwitched()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onUserItemClicked_guest_runsOnBgThread() {
|
||||
val dialogShower = mock(UserSwitchDialogController.DialogShower::class.java)
|
||||
val guestUserRecord = UserSwitcherController.UserRecord(
|
||||
null,
|
||||
picture,
|
||||
true /* guest */,
|
||||
false /* current */,
|
||||
false /* isAddUser */,
|
||||
false /* isRestricted */,
|
||||
true /* isSwitchToEnabled */,
|
||||
false /* isAddSupervisedUser */)
|
||||
|
||||
userSwitcherController.onUserListItemClicked(guestUserRecord, dialogShower)
|
||||
assertTrue(bgExecutor.numPending() > 0)
|
||||
verify(userManager, never()).createGuest(context)
|
||||
bgExecutor.runAllReady()
|
||||
verify(userManager).createGuest(context)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.android.systemui.user
|
||||
|
||||
import android.content.pm.UserInfo
|
||||
import android.graphics.Bitmap
|
||||
import android.os.UserManager
|
||||
import android.test.suitebuilder.annotation.SmallTest
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.util.concurrency.FakeExecutor
|
||||
import com.android.systemui.util.mockito.any
|
||||
import com.android.systemui.util.time.FakeSystemClock
|
||||
import java.util.function.Consumer
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentMatchers.anyInt
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.Mockito.never
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@TestableLooper.RunWithLooper(setAsMainLooper = true)
|
||||
class UserCreatorTest : SysuiTestCase() {
|
||||
companion object {
|
||||
const val USER_NAME = "abc"
|
||||
}
|
||||
|
||||
@Mock
|
||||
private lateinit var userCreator: UserCreator
|
||||
@Mock
|
||||
private lateinit var userManager: UserManager
|
||||
private lateinit var mainExecutor: FakeExecutor
|
||||
private lateinit var bgExecutor: FakeExecutor
|
||||
private lateinit var user: UserInfo
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
mainExecutor = FakeExecutor(FakeSystemClock())
|
||||
bgExecutor = FakeExecutor(FakeSystemClock())
|
||||
userCreator = UserCreator(context, userManager, mainExecutor, bgExecutor)
|
||||
user = Mockito.mock(UserInfo::class.java)
|
||||
Mockito.`when`(userManager.createUser(USER_NAME, UserManager.USER_TYPE_FULL_SECONDARY, 0))
|
||||
.thenReturn(user)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCreateUser_threadingOrder() {
|
||||
val successCallback = Mockito.mock(Consumer::class.java)
|
||||
val errorCallback = Mockito.mock(Runnable::class.java)
|
||||
|
||||
userCreator.createUser(
|
||||
USER_NAME,
|
||||
null,
|
||||
successCallback as Consumer<UserInfo?>,
|
||||
errorCallback)
|
||||
|
||||
verify(userManager, never()).createUser(USER_NAME, UserManager.USER_TYPE_FULL_SECONDARY, 0)
|
||||
bgExecutor.runAllReady()
|
||||
verify(successCallback, never()).accept(user)
|
||||
mainExecutor.runAllReady()
|
||||
verify(userManager, never()).setUserIcon(anyInt(), any(Bitmap::class.java))
|
||||
bgExecutor.runAllReady()
|
||||
|
||||
verify(userManager).createUser(USER_NAME, UserManager.USER_TYPE_FULL_SECONDARY, 0)
|
||||
verify(userManager).setUserIcon(anyInt(), any(Bitmap::class.java))
|
||||
verify(successCallback).accept(user)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user