From 1839645126c8e7e0909e8ed8f0686c2122ba6078 Mon Sep 17 00:00:00 2001 From: Evan Rosky Date: Wed, 27 Jul 2016 15:19:37 -0700 Subject: [PATCH 1/2] Add support for custom user-switch UI Given config_customUserSwitchUi, AM/UserController will not show any UI during user-switch (no dialog or screen-freeze). Provides a mechanism (WM.setSwitchingUser) by which a custom user-switch UI can notify WM/Keyguard when it expects a user-switch operation to be running. Bug: 29329555 Change-Id: Ic903fc251d7ec3a54bc6a77906d3afa45a6a5fac --- core/java/android/view/IWindowManager.aidl | 3 +++ .../android/view/WindowManagerPolicy.java | 9 +++++++ .../internal/policy/IKeyguardService.aidl | 1 + core/res/res/values/config.xml | 5 ++++ core/res/res/values/symbols.xml | 1 + .../keyguard/KeyguardUpdateMonitor.java | 15 ++++++----- .../systemui/keyguard/KeyguardService.java | 6 +++++ .../keyguard/KeyguardViewMediator.java | 7 ++--- .../server/am/ActivityManagerService.java | 26 ++++++++++++++----- .../com/android/server/am/UserController.java | 25 ++++++++++++------ .../server/am/UserSwitchingDialog.java | 3 ++- .../server/policy/PhoneWindowManager.java | 5 ++++ .../keyguard/KeyguardServiceDelegate.java | 6 +++++ .../keyguard/KeyguardServiceWrapper.java | 9 +++++++ .../server/wm/WindowManagerService.java | 13 ++++++++++ .../server/wm/TestWindowManagerPolicy.java | 5 ++++ 16 files changed, 115 insertions(+), 24 deletions(-) diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 3d786f18f293f..c31a1b8d7498a 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -210,6 +210,9 @@ interface IWindowManager void dismissKeyguard(); void keyguardGoingAway(int flags); + // Requires INTERACT_ACROSS_USERS_FULL permission + void setSwitchingUser(boolean switching); + void closeSystemDialogs(String reason); // These can only be called with the SET_ANIMATON_SCALE permission. diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index 87595f9f72239..f1fa216949766 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -1346,6 +1346,15 @@ public interface WindowManagerPolicy { */ public void setCurrentUserLw(int newUserId); + /** + * For a given user-switch operation, this will be called once with switching=true before the + * user-switch and once with switching=false afterwards (or if the user-switch was cancelled). + * This gives the policy a chance to alter its behavior for the duration of a user-switch. + * + * @param switching true if a user-switch is in progress + */ + void setSwitchingUser(boolean switching); + /** * Print the WindowManagerPolicy's state into the given stream. * diff --git a/core/java/com/android/internal/policy/IKeyguardService.aidl b/core/java/com/android/internal/policy/IKeyguardService.aidl index 83d75fba80f9a..02e8af0ab771f 100644 --- a/core/java/com/android/internal/policy/IKeyguardService.aidl +++ b/core/java/com/android/internal/policy/IKeyguardService.aidl @@ -80,6 +80,7 @@ oneway interface IKeyguardService { void setKeyguardEnabled(boolean enabled); void onSystemReady(); void doKeyguardTimeout(in Bundle options); + void setSwitchingUser(boolean switching); void setCurrentUser(int userId); void onBootCompleted(); diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 13e1ba7da0adb..d15b1750c8bff 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2540,4 +2540,9 @@ com.android.systemui/com.android.systemui.net.NetworkOverLimitActivity com.android.settings/com.android.settings.Settings$DataUsageSummaryActivity + + + false + diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index df8d61a98afd4..384e98503cdea 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1482,6 +1482,7 @@ + diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java index 1b83ccdefe620..daa1d88a65cbe 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -1185,9 +1185,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { * Handle {@link #MSG_USER_SWITCHING} */ protected void handleUserSwitching(int userId, IRemoteCallback reply) { - mSwitchingUser = true; - updateFingerprintListeningState(); - for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -1204,9 +1201,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { * Handle {@link #MSG_USER_SWITCH_COMPLETE} */ protected void handleUserSwitchComplete(int userId) { - mSwitchingUser = false; - updateFingerprintListeningState(); - for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -1511,6 +1505,15 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { sendUpdates(callback); } + public boolean isSwitchingUser() { + return mSwitchingUser; + } + + public void setSwitchingUser(boolean switching) { + mSwitchingUser = switching; + updateFingerprintListeningState(); + } + private void sendUpdates(KeyguardUpdateMonitorCallback callback) { // Notify listener of the current state callback.onRefreshBatteryInfo(mBatteryStatus); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java index 84901ee67e713..7ec6a0338a384 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java @@ -177,6 +177,12 @@ public class KeyguardService extends Service { mKeyguardViewMediator.doKeyguardTimeout(options); } + @Override // Binder interface + public void setSwitchingUser(boolean switching) { + checkPermission(); + mKeyguardViewMediator.setSwitchingUser(switching); + } + @Override // Binder interface public void setCurrentUser(int userId) { checkPermission(); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 0dc5f748c956a..ffa6a4faa3628 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -197,7 +197,6 @@ public class KeyguardViewMediator extends SystemUI { private AlarmManager mAlarmManager; private AudioManager mAudioManager; private StatusBarManager mStatusBarManager; - private boolean mSwitchingUser; private boolean mSystemReady; private boolean mBootCompleted; @@ -349,7 +348,6 @@ public class KeyguardViewMediator extends SystemUI { // We need to force a reset of the views, since lockNow (called by // ActivityManagerService) will not reconstruct the keyguard if it is already showing. synchronized (KeyguardViewMediator.this) { - mSwitchingUser = true; resetKeyguardDonePendingLocked(); resetStateLocked(); adjustStatusBarLocked(); @@ -358,7 +356,6 @@ public class KeyguardViewMediator extends SystemUI { @Override public void onUserSwitchComplete(int userId) { - mSwitchingUser = false; if (userId != UserHandle.USER_SYSTEM) { UserInfo info = UserManager.get(mContext).getUserInfo(userId); if (info != null && (info.isGuest() || info.isDemo())) { @@ -1368,6 +1365,10 @@ public class KeyguardViewMediator extends SystemUI { || KeyguardUpdateMonitor.getInstance(mContext).isSimPinSecure(); } + public void setSwitchingUser(boolean switching) { + KeyguardUpdateMonitor.getInstance(mContext).setSwitchingUser(switching); + } + /** * Update the newUserId. Call while holding WindowManagerService lock. * NOTE: Should only be called by KeyguardViewMediator in response to the user id changing. diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index dbff4be3700e5..908b8e0ea1ed4 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1533,6 +1533,7 @@ public final class ActivityManagerService extends ActivityManagerNative static final int VR_MODE_APPLY_IF_NEEDED_MSG = 69; static final int SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG = 70; static final int HANDLE_TRUST_STORAGE_UPDATE_MSG = 71; + static final int START_USER_SWITCH_FG_MSG = 712; static final int FIRST_ACTIVITY_STACK_MSG = 100; static final int FIRST_BROADCAST_QUEUE_MSG = 200; @@ -1954,6 +1955,10 @@ public final class ActivityManagerService extends ActivityManagerNative thread.start(); break; } + case START_USER_SWITCH_FG_MSG: { + mUserController.startUserInForeground(msg.arg1); + break; + } case REPORT_USER_SWITCH_MSG: { mUserController.dispatchUserSwitch((UserState) msg.obj, msg.arg1, msg.arg2); break; @@ -13110,6 +13115,8 @@ public final class ActivityManagerService extends ActivityManagerNative com.android.internal.R.string.config_defaultPictureInPictureBounds)); mAppErrors.loadAppsNotReportingCrashesFromConfigLocked(res.getString( com.android.internal.R.string.config_appsNotReportingCrashes)); + mUserController.mUserSwitchUiEnabled = !res.getBoolean( + com.android.internal.R.bool.config_customUserSwitchUi); if ((mConfiguration.uiMode & UI_MODE_TYPE_TELEVISION) == UI_MODE_TYPE_TELEVISION) { mFullscreenThumbnailScale = (float) res .getInteger(com.android.internal.R.integer.thumbnail_width_tv) / @@ -21526,11 +21533,10 @@ public final class ActivityManagerService extends ActivityManagerNative @Override public boolean switchUser(final int targetUserId) { enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, targetUserId); - UserInfo currentUserInfo; + int currentUserId; UserInfo targetUserInfo; synchronized (this) { - int currentUserId = mUserController.getCurrentUserIdLocked(); - currentUserInfo = mUserController.getUserInfo(currentUserId); + currentUserId = mUserController.getCurrentUserIdLocked(); targetUserInfo = mUserController.getUserInfo(targetUserId); if (targetUserInfo == null) { Slog.w(TAG, "No user info for user #" + targetUserId); @@ -21551,9 +21557,17 @@ public final class ActivityManagerService extends ActivityManagerNative } mUserController.setTargetUserIdLocked(targetUserId); } - Pair userNames = new Pair<>(currentUserInfo, targetUserInfo); - mUiHandler.removeMessages(START_USER_SWITCH_UI_MSG); - mUiHandler.sendMessage(mUiHandler.obtainMessage(START_USER_SWITCH_UI_MSG, userNames)); + if (mUserController.mUserSwitchUiEnabled) { + UserInfo currentUserInfo = mUserController.getUserInfo(currentUserId); + Pair userNames = new Pair<>(currentUserInfo, targetUserInfo); + mUiHandler.removeMessages(START_USER_SWITCH_UI_MSG); + mUiHandler.sendMessage(mHandler.obtainMessage( + START_USER_SWITCH_UI_MSG, userNames)); + } else { + mHandler.removeMessages(START_USER_SWITCH_FG_MSG); + mHandler.sendMessage(mHandler.obtainMessage( + START_USER_SWITCH_FG_MSG, targetUserId, 0)); + } return true; } diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index a5245a2d01a20..35b7a43ebcf0e 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -161,6 +161,8 @@ final class UserController { private final RemoteCallbackList mUserSwitchObservers = new RemoteCallbackList<>(); + boolean mUserSwitchUiEnabled; + /** * Currently active user switch callbacks. */ @@ -797,7 +799,7 @@ final class UserController { return false; } - if (foreground) { + if (foreground && mUserSwitchUiEnabled) { mInjector.getWindowManager().startFreezingScreen( R.anim.screen_user_exit, R.anim.screen_user_enter); } @@ -827,7 +829,10 @@ final class UserController { mInjector.getWindowManager().setCurrentUser(userId, mCurrentProfileIds); // Once the internal notion of the active user has switched, we lock the device // with the option to show the user switcher on the keyguard. - mInjector.getWindowManager().lockNow(null); + if (mUserSwitchUiEnabled) { + mInjector.getWindowManager().setSwitchingUser(true); + mInjector.getWindowManager().lockNow(null); + } } else { final Integer currentUserIdInt = mCurrentUserId; updateCurrentProfileIdsLocked(); @@ -920,10 +925,11 @@ final class UserController { /** * Start user, if its not already running, and bring it to foreground. */ - boolean startUserInForeground(final int userId, Dialog dlg) { - boolean result = startUser(userId, /* foreground */ true); - dlg.dismiss(); - return result; + void startUserInForeground(final int targetUserId) { + boolean success = startUser(targetUserId, /* foreground */ true); + if (!success) { + mInjector.getWindowManager().setSwitchingUser(false); + } } boolean unlockUser(final int userId, byte[] token, byte[] secret, IProgressListener listener) { @@ -1036,6 +1042,7 @@ final class UserController { /** Called on handler thread */ void dispatchUserSwitchComplete(int userId) { + mInjector.getWindowManager().setSwitchingUser(false); final int observerCount = mUserSwitchObservers.beginBroadcast(); for (int i = 0; i < observerCount; i++) { try { @@ -1126,8 +1133,10 @@ final class UserController { void continueUserSwitch(UserState uss, int oldUserId, int newUserId) { Slog.d(TAG, "Continue user switch oldUser #" + oldUserId + ", newUser #" + newUserId); - synchronized (mLock) { - mInjector.getWindowManager().stopFreezingScreen(); + if (mUserSwitchUiEnabled) { + synchronized (mLock) { + mInjector.getWindowManager().stopFreezingScreen(); + } } uss.switching = false; mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG); diff --git a/services/core/java/com/android/server/am/UserSwitchingDialog.java b/services/core/java/com/android/server/am/UserSwitchingDialog.java index 70228560cc51c..3e6934f67e4ec 100644 --- a/services/core/java/com/android/server/am/UserSwitchingDialog.java +++ b/services/core/java/com/android/server/am/UserSwitchingDialog.java @@ -112,7 +112,8 @@ final class UserSwitchingDialog extends AlertDialog void startUser() { synchronized (this) { if (!mStartedUser) { - mService.mUserController.startUserInForeground(mUserId, this); + mService.mUserController.startUserInForeground(mUserId); + dismiss(); mStartedUser = true; final View decorView = getWindow().getDecorView(); if (decorView != null) { diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 122990a7643c0..c1b5102d10ef5 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -7779,6 +7779,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { setLastInputMethodWindowLw(null, null); } + @Override + public void setSwitchingUser(boolean switching) { + mKeyguardDelegate.setSwitchingUser(switching); + } + @Override public boolean canMagnifyWindow(int windowType) { switch (windowType) { diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java index 0c76aeb58f7d8..ef6d92f3a7731 100644 --- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java +++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java @@ -346,6 +346,12 @@ public class KeyguardServiceDelegate { mKeyguardState.currentUser = newUserId; } + public void setSwitchingUser(boolean switching) { + if (mKeyguardService != null) { + mKeyguardService.setSwitchingUser(switching); + } + } + public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) { if (mKeyguardService != null) { mKeyguardService.startKeyguardExitAnimation(startTime, fadeoutDuration); diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java index bea31673a58bb..0274cb5763bf5 100644 --- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java +++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java @@ -188,6 +188,15 @@ public class KeyguardServiceWrapper implements IKeyguardService { } } + @Override // Binder interface + public void setSwitchingUser(boolean switching) { + try { + mService.setSwitchingUser(switching); + } catch (RemoteException e) { + Slog.w(TAG , "Remote Exception", e); + } + } + @Override // Binder interface public void setCurrentUser(int userId) { mKeyguardStateMonitor.setCurrentUser(userId); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 6648b1cd2dacf..fc1e1d66c765e 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -581,6 +581,7 @@ public class WindowManagerService extends IWindowManager.Stub int mLastDisplayFreezeDuration = 0; Object mLastFinishedFreezeSource = null; boolean mWaitingForConfig = false; + boolean mSwitchingUser = false; final static int WINDOWS_FREEZING_SCREENS_NONE = 0; final static int WINDOWS_FREEZING_SCREENS_ACTIVE = 1; @@ -4506,6 +4507,18 @@ public class WindowManagerService extends IWindowManager.Stub } } + @Override + public void setSwitchingUser(boolean switching) { + if (!checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, + "setSwitchingUser()")) { + throw new SecurityException("Requires INTERACT_ACROSS_USERS_FULL permission"); + } + mPolicy.setSwitchingUser(switching); + synchronized (mWindowMap) { + mSwitchingUser = switching; + } + } + void showGlobalActions() { mPolicy.showGlobalActions(); } diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java index aa97b3541a659..8c6b0078c17c3 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -662,6 +662,11 @@ public class TestWindowManagerPolicy implements WindowManagerPolicy { } + @Override + public void setSwitchingUser(boolean switching) { + + } + @Override public void dump(String prefix, PrintWriter writer, String[] args) { From 13a58a91d362e74933b3064a65be4bf4449cfdc4 Mon Sep 17 00:00:00 2001 From: Evan Rosky Date: Wed, 27 Jul 2016 15:51:09 -0700 Subject: [PATCH 2/2] Make user-switch transitions customizable Make UserSwitcherController subclassable Add ability for keyguard to animate in without a screen freeze by adding a keyguardAnimatingIn state that WindowAnimator and WallpaperController can use to prevent graphical glitches Bug: 29329555 Change-Id: Idfd40156538b4bfb1777ad1a9a566e7da54e8f32 --- core/java/android/os/UserManager.java | 19 +++++++ core/java/android/view/IWindowManager.aidl | 10 ++++ .../keyguard/KeyguardViewMediator.java | 17 +++++-- .../statusbar/phone/KeyguardBouncer.java | 2 +- .../statusbar/phone/LockscreenWallpaper.java | 4 +- .../statusbar/phone/PhoneStatusBar.java | 11 +++- .../policy/UserSwitcherController.java | 51 ++++++++++++------- .../com/android/server/wm/WindowAnimator.java | 4 +- .../server/wm/WindowManagerService.java | 17 +++++++ .../com/android/server/wm/WindowToken.java | 6 ++- 10 files changed, 114 insertions(+), 27 deletions(-) diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 3fcc253b45491..cfd016ede0628 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -748,6 +748,15 @@ public class UserManager { return SystemProperties.getBoolean("ro.fw.system_user_split", false); } + /** + * @return Whether guest user is always ephemeral + * @hide + */ + public static boolean isGuestUserEphemeral() { + return Resources.getSystem() + .getBoolean(com.android.internal.R.bool.config_guestUserEphemeral); + } + /** * Returns whether switching users is currently allowed. *

For instance switching users is not allowed if the current user is in a phone call, @@ -870,6 +879,16 @@ public class UserManager { } } + /** + * Checks if a user is a guest user. + * @return whether user is a guest user. + * @hide + */ + public boolean isGuestUser(int id) { + UserInfo user = getUserInfo(id); + return user != null && user.isGuest(); + } + /** * Checks if the calling app is running as a guest user. * @return whether the caller is a guest user. diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index c31a1b8d7498a..7de7d8aa22522 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -210,6 +210,16 @@ interface IWindowManager void dismissKeyguard(); void keyguardGoingAway(int flags); + /** + * Called to tell WindowManager whether the keyguard is animating in. While this property + * is true, WindowManager won't assume that the keyguard is opaque (eg. WindowAnimator won't + * force-hide windows just because keyguard is visible and WallpaperController won't occlude + * app windows with the system wallpaper. + * + *

Requires CONTROL_KEYGUARD permission

+ */ + void setKeyguardAnimatingIn(boolean animating); + // Requires INTERACT_ACROSS_USERS_FULL permission void setSwitchingUser(boolean switching); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index ffa6a4faa3628..8b592c2335e34 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -191,6 +191,12 @@ public class KeyguardViewMediator extends SystemUI { */ private static final String KEYGUARD_ANALYTICS_SETTING = "keyguard_analytics"; + /** + * Boolean option for doKeyguardLocked/doKeyguardTimeout which, when set to true, forces the + * keyguard to show even if it is disabled for the current user. + */ + public static final String OPTION_FORCE_SHOW = "force_show"; + /** The stream type that the lock sounds are tied to. */ private int mUiSoundsStreamType; @@ -1240,8 +1246,9 @@ public class KeyguardViewMediator extends SystemUI { return; } + boolean forceShow = options != null && options.getBoolean(OPTION_FORCE_SHOW, false); if (mLockPatternUtils.isLockScreenDisabled(KeyguardUpdateMonitor.getCurrentUser()) - && !lockedOrMissing) { + && !lockedOrMissing && !forceShow) { if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off"); return; } @@ -1361,8 +1368,12 @@ public class KeyguardViewMediator extends SystemUI { } public boolean isSecure() { - return mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser()) - || KeyguardUpdateMonitor.getInstance(mContext).isSimPinSecure(); + return isSecure(KeyguardUpdateMonitor.getCurrentUser()); + } + + public boolean isSecure(int userId) { + return mLockPatternUtils.isSecure(userId) + || KeyguardUpdateMonitor.getInstance(mContext).isSimPinSecure(); } public void setSwitchingUser(boolean switching) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java index bc05ff178d252..706abdc978626 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java @@ -97,7 +97,7 @@ public class KeyguardBouncer { final int activeUserId = ActivityManager.getCurrentUser(); final boolean allowDismissKeyguard = - !(UserManager.isSplitSystemUser() && activeUserId == UserHandle.USER_SYSTEM) + !UserManager.isSplitSystemUser() && activeUserId == keyguardUserId; // If allowed, try to dismiss the Keyguard. If no security auth (password/pin/pattern) is // set, this will dismiss the whole Keyguard. Otherwise, show the bouncer. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java index 586741e75582c..4638c8558ff7e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java @@ -129,7 +129,9 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen public void setCurrentUser(int user) { if (user != mCurrentUserId) { - mCached = false; + if (mSelectedUser == null || user != mSelectedUser.getIdentifier()) { + mCached = false; + } mCurrentUserId = user; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 10ca5bd5626e8..dd856efb4c1aa 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -892,8 +892,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mLightStatusBarController = new LightStatusBarController(mIconController, mBatteryController); mKeyguardMonitor = new KeyguardMonitor(mContext); - mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor, - mHandler, this); + mUserSwitcherController = createUserSwitcherController(); if (UserManager.get(mContext).isUserSwitcherEnabled()) { createUserSwitcher(); } @@ -1096,6 +1095,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mKeyguardStatusBar, mNotificationPanel, mUserSwitcherController); } + protected UserSwitcherController createUserSwitcherController() { + return new UserSwitcherController(mContext, mKeyguardMonitor, mHandler, this); + } + protected void inflateStatusBarWindow(Context context) { mStatusBarWindow = (StatusBarWindowView) View.inflate(context, R.layout.super_status_bar, null); @@ -3621,6 +3624,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, resetUserSetupObserver(); setControllerUsers(); clearCurrentMediaNotification(); + setLockscreenUser(newUserId); + } + + protected void setLockscreenUser(int newUserId) { mLockscreenWallpaper.setCurrentUser(newUserId); mScrimController.setCurrentUser(newUserId); updateMediaMetaData(true, false); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index c883bbabc7cc0..c3becb08e031b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -50,6 +50,7 @@ import android.widget.BaseAdapter; import com.android.internal.logging.MetricsProto.MetricsEvent; import com.android.internal.util.UserIcons; +import com.android.keyguard.KeyguardUpdateMonitor; import com.android.settingslib.RestrictedLockUtils; import com.android.systemui.GuestResumeSessionReceiver; import com.android.systemui.R; @@ -86,13 +87,13 @@ public class UserSwitcherController { private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF"; - private final Context mContext; - private final UserManager mUserManager; + protected final Context mContext; + protected final UserManager mUserManager; private final ArrayList> mAdapters = new ArrayList<>(); private final GuestResumeSessionReceiver mGuestResumeSessionReceiver = new GuestResumeSessionReceiver(); private final KeyguardMonitor mKeyguardMonitor; - private final Handler mHandler; + protected final Handler mHandler; private final ActivityStarter mActivityStarter; private ArrayList mUsers = new ArrayList<>(); @@ -363,13 +364,23 @@ public class UserSwitcherController { id = record.info.id; } - if (ActivityManager.getCurrentUser() == id) { + int currUserId = ActivityManager.getCurrentUser(); + if (currUserId == id) { if (record.isGuest) { showExitGuestDialog(id); } return; } + if (UserManager.isGuestUserEphemeral()) { + // If switching from guest, we want to bring up the guest exit dialog instead of switching + UserInfo currUserInfo = mUserManager.getUserInfo(currUserId); + if (currUserInfo != null && currUserInfo.isGuest()) { + showExitGuestDialog(currUserId, record.resolveId()); + return; + } + } + switchToUserId(id); } @@ -398,7 +409,7 @@ public class UserSwitcherController { return count; } - private void switchToUserId(int id) { + protected void switchToUserId(int id) { try { pauseRefreshUsers(); ActivityManagerNative.getDefault().switchUser(id); @@ -408,10 +419,21 @@ public class UserSwitcherController { } private void showExitGuestDialog(int id) { + int newId = UserHandle.USER_SYSTEM; + if (mResumeUserOnGuestLogout && mLastNonGuestUser != UserHandle.USER_SYSTEM) { + UserInfo info = mUserManager.getUserInfo(mLastNonGuestUser); + if (info != null && info.isEnabled() && info.supportsSwitchToByUser()) { + newId = info.id; + } + } + showExitGuestDialog(id, newId); + } + + protected void showExitGuestDialog(int id, int targetId) { if (mExitGuestDialog != null && mExitGuestDialog.isShowing()) { mExitGuestDialog.cancel(); } - mExitGuestDialog = new ExitGuestDialog(mContext, id); + mExitGuestDialog = new ExitGuestDialog(mContext, id, targetId); mExitGuestDialog.show(); } @@ -423,15 +445,8 @@ public class UserSwitcherController { mAddUserDialog.show(); } - private void exitGuest(int id) { - int newId = UserHandle.USER_SYSTEM; - if (mResumeUserOnGuestLogout && mLastNonGuestUser != UserHandle.USER_SYSTEM) { - UserInfo info = mUserManager.getUserInfo(mLastNonGuestUser); - if (info != null && info.isEnabled() && info.supportsSwitchToByUser()) { - newId = info.id; - } - } - switchToUserId(newId); + protected void exitGuest(int id, int targetId) { + switchToUserId(targetId); mUserManager.removeUser(id); } @@ -830,8 +845,9 @@ public class UserSwitcherController { DialogInterface.OnClickListener { private final int mGuestId; + private final int mTargetId; - public ExitGuestDialog(Context context, int guestId) { + public ExitGuestDialog(Context context, int guestId, int targetId) { super(context); setTitle(R.string.guest_exit_guest_dialog_title); setMessage(context.getString(R.string.guest_exit_guest_dialog_message)); @@ -841,6 +857,7 @@ public class UserSwitcherController { context.getString(R.string.guest_exit_guest_dialog_remove), this); setCanceledOnTouchOutside(false); mGuestId = guestId; + mTargetId = targetId; } @Override @@ -849,7 +866,7 @@ public class UserSwitcherController { cancel(); } else { dismiss(); - exitGuest(mGuestId); + exitGuest(mGuestId, mTargetId); } } } diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java index feb5c68e48fc1..dee9cc3e2bd48 100644 --- a/services/core/java/com/android/server/wm/WindowAnimator.java +++ b/services/core/java/com/android/server/wm/WindowAnimator.java @@ -104,6 +104,7 @@ public class WindowAnimator { boolean mKeyguardGoingAway; int mKeyguardGoingAwayFlags; + boolean mKeyguardAnimatingIn; /** Use one animation for all entering activities after keyguard is dismissed. */ Animation mPostKeyguardExitAnimation; @@ -241,7 +242,8 @@ public class WindowAnimator { // Only hide windows if the keyguard is active and not animating away. boolean keyguardOn = mPolicy.isKeyguardShowingOrOccluded() - && mForceHiding != KEYGUARD_ANIMATING_OUT; + && mForceHiding != KEYGUARD_ANIMATING_OUT + && !mKeyguardAnimatingIn; boolean hideDockDivider = win.mAttrs.type == TYPE_DOCK_DIVIDER && win.getDisplayContent().getDockedStackLocked() == null; return keyguardOn && !allowWhenLocked && (win.getDisplayId() == Display.DEFAULT_DISPLAY) diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index fc1e1d66c765e..74c596832d1ac 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -4507,6 +4507,23 @@ public class WindowManagerService extends IWindowManager.Stub } } + @Override + public void setKeyguardAnimatingIn(boolean animating) { + if (!checkCallingPermission(Manifest.permission.CONTROL_KEYGUARD, + "keyguardAnimatingIn()")) { + throw new SecurityException("Requires CONTROL_KEYGUARD permission"); + } + synchronized (mWindowMap) { + mAnimator.mKeyguardAnimatingIn = animating; + } + } + + public boolean isKeyguardAnimatingIn() { + synchronized (mWindowMap) { + return mAnimator.mKeyguardAnimatingIn; + } + } + @Override public void setSwitchingUser(boolean switching) { if (!checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index 9f019acc31d8b..7ed16f53461ac 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -608,12 +608,14 @@ class WindowToken { } // Now stick it in. For apps over wallpaper keep the wallpaper at the bottommost - // layer. For keyguard over wallpaper put the wallpaper under the keyguard. + // layer. For keyguard over wallpaper put the wallpaper under the keyguard unless + // the keyguard is still animating in. int insertionIndex = 0; if (visible && wallpaperTarget != null) { final int type = wallpaperTarget.mAttrs.type; final int privateFlags = wallpaperTarget.mAttrs.privateFlags; - if ((privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 || type == TYPE_KEYGUARD_SCRIM) { + if (((privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 || type == TYPE_KEYGUARD_SCRIM) + && !mService.isKeyguardAnimatingIn()) { insertionIndex = windowList.indexOf(wallpaperTarget); } }