Merge "Dismiss keyguard when target user has no password"
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index a075a13..d52f52e 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -103,6 +103,7 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.widget.LockPatternUtils;
@@ -162,6 +163,7 @@
static final int USER_UNLOCKED_MSG = 105;
static final int REPORT_LOCKED_BOOT_COMPLETE_MSG = 110;
static final int START_USER_SWITCH_FG_MSG = 120;
+ static final int COMPLETE_USER_SWITCH_MSG = 130;
// Message constant to clear {@link UserJourneySession} from {@link mUserIdToUserJourneyMap} if
// the user journey, defined in the UserLifecycleJourneyReported atom for statsd, is not
@@ -385,6 +387,7 @@
@VisibleForTesting
UserController(Injector injector) {
mInjector = injector;
+ // This should be called early to avoid a null mHandler inside the injector
mHandler = mInjector.getHandler(this);
mUiHandler = mInjector.getUiHandler(this);
// User 0 is the first and only user that runs at boot.
@@ -1535,7 +1538,10 @@
// with the option to show the user switcher on the keyguard.
if (userSwitchUiEnabled) {
mInjector.getWindowManager().setSwitchingUser(true);
- mInjector.getWindowManager().lockNow(null);
+ // Only lock if the user has a secure keyguard PIN/Pattern/Pwd
+ if (mInjector.getKeyguardManager().isDeviceSecure(userId)) {
+ mInjector.getWindowManager().lockNow(null);
+ }
}
} else {
final Integer currentUserIdInt = mCurrentUserId;
@@ -1967,11 +1973,10 @@
EventLog.writeEvent(EventLogTags.UC_CONTINUE_USER_SWITCH, oldUserId, newUserId);
- if (isUserSwitchUiEnabled()) {
- t.traceBegin("stopFreezingScreen");
- mInjector.getWindowManager().stopFreezingScreen();
- t.traceEnd();
- }
+ // Do the keyguard dismiss and unfreeze later
+ mHandler.removeMessages(COMPLETE_USER_SWITCH_MSG);
+ mHandler.sendMessage(mHandler.obtainMessage(COMPLETE_USER_SWITCH_MSG, newUserId, 0));
+
uss.switching = false;
mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG);
mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_COMPLETE_MSG, newUserId, 0));
@@ -1981,6 +1986,34 @@
t.traceEnd(); // end continueUserSwitch
}
+ @VisibleForTesting
+ void completeUserSwitch(int newUserId) {
+ if (isUserSwitchUiEnabled()) {
+ // If there is no challenge set, dismiss the keyguard right away
+ if (!mInjector.getKeyguardManager().isDeviceSecure(newUserId)) {
+ // Wait until the keyguard is dismissed to unfreeze
+ mInjector.dismissKeyguard(
+ new Runnable() {
+ public void run() {
+ unfreezeScreen();
+ }
+ },
+ "User Switch");
+ return;
+ } else {
+ unfreezeScreen();
+ }
+ }
+ }
+
+ @VisibleForTesting
+ void unfreezeScreen() {
+ TimingsTraceAndSlog t = new TimingsTraceAndSlog();
+ t.traceBegin("stopFreezingScreen");
+ mInjector.getWindowManager().stopFreezingScreen();
+ t.traceEnd();
+ }
+
private void moveUserToForeground(UserState uss, int oldUserId, int newUserId) {
boolean homeInFront = mInjector.taskSupervisorSwitchUser(newUserId, uss);
if (homeInFront) {
@@ -2772,6 +2805,9 @@
case CLEAR_USER_JOURNEY_SESSION_MSG:
logAndClearSessionId(msg.arg1);
break;
+ case COMPLETE_USER_SWITCH_MSG:
+ completeUserSwitch(msg.arg1);
+ break;
}
return false;
}
@@ -2961,13 +2997,14 @@
private final ActivityManagerService mService;
private UserManagerService mUserManager;
private UserManagerInternal mUserManagerInternal;
+ private Handler mHandler;
Injector(ActivityManagerService service) {
mService = service;
}
protected Handler getHandler(Handler.Callback callback) {
- return new Handler(mService.mHandlerThread.getLooper(), callback);
+ return mHandler = new Handler(mService.mHandlerThread.getLooper(), callback);
}
protected Handler getUiHandler(Handler.Callback callback) {
@@ -3165,5 +3202,24 @@
protected IStorageManager getStorageManager() {
return IStorageManager.Stub.asInterface(ServiceManager.getService("mount"));
}
+
+ protected void dismissKeyguard(Runnable runnable, String reason) {
+ getWindowManager().dismissKeyguard(new IKeyguardDismissCallback.Stub() {
+ @Override
+ public void onDismissError() throws RemoteException {
+ mHandler.post(runnable);
+ }
+
+ @Override
+ public void onDismissSucceeded() throws RemoteException {
+ mHandler.post(runnable);
+ }
+
+ @Override
+ public void onDismissCancelled() throws RemoteException {
+ mHandler.post(runnable);
+ }
+ }, reason);
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index 9ffb5017..f1a63bc 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -21,6 +21,7 @@
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static com.android.server.am.UserController.COMPLETE_USER_SWITCH_MSG;
import static com.android.server.am.UserController.CONTINUE_USER_SWITCH_MSG;
import static com.android.server.am.UserController.REPORT_LOCKED_BOOT_COMPLETE_MSG;
import static com.android.server.am.UserController.REPORT_USER_SWITCH_COMPLETE_MSG;
@@ -59,6 +60,7 @@
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.IUserSwitchObserver;
+import android.app.KeyguardManager;
import android.content.Context;
import android.content.IIntentReceiver;
import android.content.Intent;
@@ -325,8 +327,16 @@
assertWithMessage("No messages should be sent").that(actualCodes).isEmpty();
}
+ private void continueAndCompleteUserSwitch(UserState userState, int oldUserId, int newUserId) {
+ mUserController.continueUserSwitch(userState, oldUserId, newUserId);
+ mInjector.mHandler.removeMessages(UserController.COMPLETE_USER_SWITCH_MSG);
+ mUserController.completeUserSwitch(newUserId);
+ }
+
@Test
public void testContinueUserSwitch() throws RemoteException {
+ mUserController.setInitialConfig(/* userSwitchUiEnabled= */ true,
+ /* maxRunningUsers= */ 3, /* delayUserDataLocking= */ false);
// Start user -- this will update state of mUserController
mUserController.startUser(TEST_USER_ID, true);
Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG);
@@ -336,7 +346,28 @@
int newUserId = reportMsg.arg2;
mInjector.mHandler.clearAllRecordedMessages();
// Verify that continueUserSwitch worked as expected
- mUserController.continueUserSwitch(userState, oldUserId, newUserId);
+ continueAndCompleteUserSwitch(userState, oldUserId, newUserId);
+ verify(mInjector, times(0)).dismissKeyguard(any(), anyString());
+ verify(mInjector.getWindowManager(), times(1)).stopFreezingScreen();
+ continueUserSwitchAssertions(TEST_USER_ID, false);
+ }
+
+ @Test
+ public void testContinueUserSwitchDismissKeyguard() throws RemoteException {
+ when(mInjector.mKeyguardManagerMock.isDeviceSecure(anyInt())).thenReturn(false);
+ mUserController.setInitialConfig(/* userSwitchUiEnabled= */ true,
+ /* maxRunningUsers= */ 3, /* delayUserDataLocking= */ false);
+ // Start user -- this will update state of mUserController
+ mUserController.startUser(TEST_USER_ID, true);
+ Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG);
+ assertNotNull(reportMsg);
+ UserState userState = (UserState) reportMsg.obj;
+ int oldUserId = reportMsg.arg1;
+ int newUserId = reportMsg.arg2;
+ mInjector.mHandler.clearAllRecordedMessages();
+ // Verify that continueUserSwitch worked as expected
+ continueAndCompleteUserSwitch(userState, oldUserId, newUserId);
+ verify(mInjector, times(1)).dismissKeyguard(any(), anyString());
verify(mInjector.getWindowManager(), times(1)).stopFreezingScreen();
continueUserSwitchAssertions(TEST_USER_ID, false);
}
@@ -355,7 +386,7 @@
int newUserId = reportMsg.arg2;
mInjector.mHandler.clearAllRecordedMessages();
// Verify that continueUserSwitch worked as expected
- mUserController.continueUserSwitch(userState, oldUserId, newUserId);
+ continueAndCompleteUserSwitch(userState, oldUserId, newUserId);
verify(mInjector.getWindowManager(), never()).stopFreezingScreen();
continueUserSwitchAssertions(TEST_USER_ID, false);
}
@@ -363,6 +394,7 @@
private void continueUserSwitchAssertions(int expectedUserId, boolean backgroundUserStopping)
throws RemoteException {
Set<Integer> expectedCodes = new LinkedHashSet<>();
+ expectedCodes.add(COMPLETE_USER_SWITCH_MSG);
expectedCodes.add(REPORT_USER_SWITCH_COMPLETE_MSG);
if (backgroundUserStopping) {
expectedCodes.add(0); // this is for directly posting in stopping.
@@ -397,7 +429,7 @@
}
@Test
- public void testExplicitSystenUserStartInBackground() {
+ public void testExplicitSystemUserStartInBackground() {
setUpUser(UserHandle.USER_SYSTEM, 0);
assertFalse(mUserController.isSystemUserStarted());
assertTrue(mUserController.startUser(UserHandle.USER_SYSTEM, false, null));
@@ -646,7 +678,7 @@
mUserStates.put(newUserId, userState);
mInjector.mHandler.clearAllRecordedMessages();
// Verify that continueUserSwitch worked as expected
- mUserController.continueUserSwitch(userState, oldUserId, newUserId);
+ continueAndCompleteUserSwitch(userState, oldUserId, newUserId);
verify(mInjector.getWindowManager(), times(expectedNumberOfCalls))
.stopFreezingScreen();
continueUserSwitchAssertions(newUserId, expectOldUserStopping);
@@ -701,6 +733,7 @@
private final IStorageManager mStorageManagerMock;
private final UserManagerInternal mUserManagerInternalMock;
private final WindowManagerService mWindowManagerMock;
+ private final KeyguardManager mKeyguardManagerMock;
private final Context mCtx;
@@ -715,6 +748,8 @@
mUserManagerInternalMock = mock(UserManagerInternal.class);
mWindowManagerMock = mock(WindowManagerService.class);
mStorageManagerMock = mock(IStorageManager.class);
+ mKeyguardManagerMock = mock(KeyguardManager.class);
+ when(mKeyguardManagerMock.isDeviceSecure(anyInt())).thenReturn(true);
}
@Override
@@ -754,6 +789,11 @@
}
@Override
+ KeyguardManager getKeyguardManager() {
+ return mKeyguardManagerMock;
+ }
+
+ @Override
void updateUserConfiguration() {
Log.i(TAG, "updateUserConfiguration");
}
@@ -787,6 +827,11 @@
protected IStorageManager getStorageManager() {
return mStorageManagerMock;
}
+
+ @Override
+ protected void dismissKeyguard(Runnable runnable, String reason) {
+ runnable.run();
+ }
}
private static class TestHandler extends Handler {