diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java index 051dde01c64e0..b732da29b7544 100644 --- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java +++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java @@ -127,6 +127,7 @@ public class UserLifecycleTests { private BroadcastWaiter mBroadcastWaiter; private UserSwitchWaiter mUserSwitchWaiter; private String mUserSwitchTimeoutMs; + private String mDisableUserSwitchingDialogAnimations; private final BenchmarkRunner mRunner = new BenchmarkRunner(); @Rule @@ -153,16 +154,17 @@ public class UserLifecycleTests { Log.w(TAG, "WARNING: Tests are being run from user " + mAm.getCurrentUser() + " rather than the system user"); } - mUserSwitchTimeoutMs = setSystemProperty("debug.usercontroller.user_switch_timeout_ms", - "100000"); - if (TextUtils.isEmpty(mUserSwitchTimeoutMs)) { - mUserSwitchTimeoutMs = "invalid"; - } + mUserSwitchTimeoutMs = setSystemProperty( + "debug.usercontroller.user_switch_timeout_ms", "100000"); + mDisableUserSwitchingDialogAnimations = setSystemProperty( + "debug.usercontroller.disable_user_switching_dialog_animations", "true"); } @After public void tearDown() throws Exception { setSystemProperty("debug.usercontroller.user_switch_timeout_ms", mUserSwitchTimeoutMs); + setSystemProperty("debug.usercontroller.disable_user_switching_dialog_animations", + mDisableUserSwitchingDialogAnimations); mBroadcastWaiter.close(); mUserSwitchWaiter.close(); for (int userId : mUsersToRemove) { @@ -1538,7 +1540,7 @@ public class UserLifecycleTests { private String setSystemProperty(String name, String value) throws Exception { final String oldValue = ShellHelper.runShellCommand("getprop " + name); assertEquals("", ShellHelper.runShellCommand("setprop " + name + " " + value)); - return oldValue; + return TextUtils.firstNotEmpty(oldValue, "invalid"); } private void waitForBroadcastIdle() { diff --git a/core/res/res/drawable/loading_spinner.xml b/core/res/res/drawable/loading_spinner.xml new file mode 100644 index 0000000000000..49603d857a1a8 --- /dev/null +++ b/core/res/res/drawable/loading_spinner.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/res/res/layout/user_switching_dialog.xml b/core/res/res/layout/user_switching_dialog.xml index 2e041f5f2be2f..496179aefc914 100644 --- a/core/res/res/layout/user_switching_dialog.xml +++ b/core/res/res/layout/user_switching_dialog.xml @@ -14,17 +14,48 @@ See the License for the specific language governing permissions and limitations under the License. --> + - + android:orientation="vertical" + android:paddingBottom="77dp"> + + + + + + + + + + + + + diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index d926c2c7c7a87..a181402e2d9f1 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -141,6 +141,7 @@ import java.util.Objects; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; /** * Helper class for {@link ActivityManagerService} responsible for multi-user functionality. @@ -157,7 +158,7 @@ class UserController implements Handler.Callback { private static final String TAG = TAG_WITH_CLASS_NAME ? "UserController" : TAG_AM; // Amount of time we wait for observers to handle a user switch before - // giving up on them and unfreezing the screen. + // giving up on them and dismissing the user switching dialog. static final int DEFAULT_USER_SWITCH_TIMEOUT_MS = 3 * 1000; /** @@ -207,7 +208,7 @@ class UserController implements Handler.Callback { /** * Amount of time waited for {@link WindowManagerService#dismissKeyguard} callbacks to be * called after dismissing the keyguard. - * Otherwise, we should move on to unfreeze the screen {@link #unfreezeScreen} + * Otherwise, we should move on to dismiss the dialog {@link #dismissUserSwitchDialog()} * and report user switch is complete {@link #REPORT_USER_SWITCH_COMPLETE_MSG}. */ private static final int DISMISS_KEYGUARD_TIMEOUT_MS = 2 * 1000; @@ -1695,14 +1696,6 @@ class UserController implements Handler.Callback { return false; } - if (foreground && isUserSwitchUiEnabled()) { - t.traceBegin("startFreezingScreen"); - mInjector.getWindowManager().startFreezingScreen( - R.anim.screen_user_exit, R.anim.screen_user_enter); - t.traceEnd(); - } - dismissUserSwitchDialog(); // so that we don't hold a reference to mUserSwitchingDialog - boolean needStart = false; boolean updateUmState = false; UserState uss; @@ -1877,7 +1870,7 @@ class UserController implements Handler.Callback { if (!success) { mInjector.getWindowManager().setSwitchingUser(false); mTargetUserId = UserHandle.USER_NULL; - dismissUserSwitchDialog(); + dismissUserSwitchDialog(null); } } @@ -2015,22 +2008,26 @@ class UserController implements Handler.Callback { mUiHandler.sendMessage(mUiHandler.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)); + sendStartUserSwitchFgMessage(targetUserId); } return true; } - private void dismissUserSwitchDialog() { - mInjector.dismissUserSwitchingDialog(); + private void sendStartUserSwitchFgMessage(int targetUserId) { + mHandler.removeMessages(START_USER_SWITCH_FG_MSG); + mHandler.sendMessage(mHandler.obtainMessage(START_USER_SWITCH_FG_MSG, targetUserId, 0)); + } + + private void dismissUserSwitchDialog(Runnable onDismissed) { + mInjector.dismissUserSwitchingDialog(onDismissed); } private void showUserSwitchDialog(Pair fromToUserPair) { // The dialog will show and then initiate the user switch by calling startUserInForeground mInjector.showUserSwitchingDialog(fromToUserPair.first, fromToUserPair.second, getSwitchingFromSystemUserMessageUnchecked(), - getSwitchingToSystemUserMessageUnchecked()); + getSwitchingToSystemUserMessageUnchecked(), + /* onShown= */ () -> sendStartUserSwitchFgMessage(fromToUserPair.second.id)); } private void dispatchForegroundProfileChanged(@UserIdInt int userId) { @@ -2236,7 +2233,7 @@ class UserController implements Handler.Callback { EventLog.writeEvent(EventLogTags.UC_CONTINUE_USER_SWITCH, oldUserId, newUserId); - // Do the keyguard dismiss and unfreeze later + // Do the keyguard dismiss and dismiss the user switching dialog later mHandler.removeMessages(COMPLETE_USER_SWITCH_MSG); mHandler.sendMessage(mHandler.obtainMessage( COMPLETE_USER_SWITCH_MSG, oldUserId, newUserId)); @@ -2251,35 +2248,31 @@ class UserController implements Handler.Callback { @VisibleForTesting void completeUserSwitch(int oldUserId, int newUserId) { final boolean isUserSwitchUiEnabled = isUserSwitchUiEnabled(); - final Runnable runnable = () -> { - if (isUserSwitchUiEnabled) { - unfreezeScreen(); - } - mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG); - mHandler.sendMessage(mHandler.obtainMessage( - REPORT_USER_SWITCH_COMPLETE_MSG, oldUserId, newUserId)); - }; - - // If there is no challenge set, dismiss the keyguard right away - if (isUserSwitchUiEnabled && !mInjector.getKeyguardManager().isDeviceSecure(newUserId)) { - // Wait until the keyguard is dismissed to unfreeze - mInjector.dismissKeyguard(runnable); - } else { - runnable.run(); - } + // serialize each conditional step + await( + // STEP 1 - If there is no challenge set, dismiss the keyguard right away + isUserSwitchUiEnabled && !mInjector.getKeyguardManager().isDeviceSecure(newUserId), + mInjector::dismissKeyguard, + () -> await( + // STEP 2 - If user switch ui was enabled, dismiss user switch dialog + isUserSwitchUiEnabled, + this::dismissUserSwitchDialog, + () -> { + // STEP 3 - Send REPORT_USER_SWITCH_COMPLETE_MSG to broadcast + // ACTION_USER_SWITCHED & call UserSwitchObservers.onUserSwitchComplete + mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG); + mHandler.sendMessage(mHandler.obtainMessage( + REPORT_USER_SWITCH_COMPLETE_MSG, oldUserId, newUserId)); + } + )); } - /** - * Tell WindowManager we're ready to unfreeze the screen, at its leisure. Note that there is - * likely a lot going on, and WM won't unfreeze until the drawing is all done, so - * the actual unfreeze may still not happen for a long time; this is expected. - */ - @VisibleForTesting - void unfreezeScreen() { - TimingsTraceAndSlog t = new TimingsTraceAndSlog(); - t.traceBegin("stopFreezingScreen"); - mInjector.getWindowManager().stopFreezingScreen(); - t.traceEnd(); + private void await(boolean condition, Consumer conditionalStep, Runnable nextStep) { + if (condition) { + conditionalStep.accept(nextStep); + } else { + nextStep.run(); + } } private void moveUserToForeground(UserState uss, int newUserId) { @@ -3731,17 +3724,18 @@ class UserController implements Handler.Callback { mService.mCpHelper.installEncryptionUnawareProviders(userId); } - void dismissUserSwitchingDialog() { + void dismissUserSwitchingDialog(@Nullable Runnable onDismissed) { synchronized (mUserSwitchingDialogLock) { if (mUserSwitchingDialog != null) { - mUserSwitchingDialog.dismiss(); + mUserSwitchingDialog.dismiss(onDismissed); mUserSwitchingDialog = null; } } } void showUserSwitchingDialog(UserInfo fromUser, UserInfo toUser, - String switchingFromSystemUserMessage, String switchingToSystemUserMessage) { + String switchingFromSystemUserMessage, String switchingToSystemUserMessage, + @NonNull Runnable onShown) { if (mService.mContext.getPackageManager() .hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) { // config_customUserSwitchUi is set to true on Automotive as CarSystemUI is @@ -3751,11 +3745,10 @@ class UserController implements Handler.Callback { + "condition if it's shown by CarSystemUI as well"); } synchronized (mUserSwitchingDialogLock) { - dismissUserSwitchingDialog(); - mUserSwitchingDialog = new UserSwitchingDialog(mService, mService.mContext, - fromUser, toUser, true /* above system */, switchingFromSystemUserMessage, - switchingToSystemUserMessage); - mUserSwitchingDialog.show(); + dismissUserSwitchingDialog(null); + mUserSwitchingDialog = new UserSwitchingDialog(mService.mContext, fromUser, toUser, + switchingFromSystemUserMessage, switchingToSystemUserMessage); + mUserSwitchingDialog.show(onShown); } } diff --git a/services/core/java/com/android/server/am/UserSwitchingDialog.java b/services/core/java/com/android/server/am/UserSwitchingDialog.java index a5651bfa3dde2..649305f7ee015 100644 --- a/services/core/java/com/android/server/am/UserSwitchingDialog.java +++ b/services/core/java/com/android/server/am/UserSwitchingDialog.java @@ -16,160 +16,258 @@ package com.android.server.am; -import android.app.AlertDialog; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.UserIdInt; +import android.app.ActivityManager; +import android.app.Dialog; import android.content.Context; import android.content.pm.UserInfo; import android.content.res.Resources; -import android.os.Handler; -import android.os.Message; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.RectF; +import android.graphics.Shader; +import android.graphics.drawable.Animatable2; +import android.graphics.drawable.AnimatedVectorDrawable; +import android.graphics.drawable.Drawable; +import android.os.SystemProperties; +import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; import android.util.Slog; -import android.view.LayoutInflater; +import android.util.TypedValue; import android.view.View; -import android.view.ViewTreeObserver; +import android.view.Window; import android.view.WindowManager; +import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; +import android.widget.ImageView; import android.widget.TextView; import com.android.internal.R; -import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.ObjectUtils; +import com.android.internal.util.UserIcons; /** - * Dialog to show when a user switch it about to happen. The intent is to snapshot the screen - * immediately after the dialog shows so that the user is informed that something is happening - * in the background rather than just freeze the screen and not know if the user-switch affordance - * was being handled. + * Dialog to show during the user switch. This dialog shows target user's name and their profile + * picture with a circular spinner animation around it if the animations for this dialog are not + * disabled. And covers the whole screen so that all the UI jank caused by the switch are hidden. */ -class UserSwitchingDialog extends AlertDialog - implements ViewTreeObserver.OnWindowShownListener { - private static final String TAG = "ActivityManagerUserSwitchingDialog"; - - // Time to wait for the onWindowShown() callback before continuing the user switch - private static final int WINDOW_SHOWN_TIMEOUT_MS = 3000; +class UserSwitchingDialog extends Dialog { + private static final String TAG = "UserSwitchingDialog"; + private static final long TRACE_TAG = Trace.TRACE_TAG_ACTIVITY_MANAGER; // User switching doesn't happen that frequently, so it doesn't hurt to have it always on protected static final boolean DEBUG = true; + private static final long DIALOG_SHOW_HIDE_ANIMATION_DURATION_MS = 300; + private final boolean mDisableAnimations; - private final ActivityManagerService mService; - private final int mUserId; - private static final int MSG_START_USER = 1; - @GuardedBy("this") - private boolean mStartedUser; - final protected UserInfo mOldUser; - final protected UserInfo mNewUser; - final private String mSwitchingFromSystemUserMessage; - final private String mSwitchingToSystemUserMessage; - final protected Context mContext; + protected final UserInfo mOldUser; + protected final UserInfo mNewUser; + private final String mSwitchingFromSystemUserMessage; + private final String mSwitchingToSystemUserMessage; + protected final Context mContext; + private final int mTraceCookie; - public UserSwitchingDialog(ActivityManagerService service, Context context, UserInfo oldUser, - UserInfo newUser, boolean aboveSystem, String switchingFromSystemUserMessage, - String switchingToSystemUserMessage) { - super(context); + UserSwitchingDialog(Context context, UserInfo oldUser, UserInfo newUser, + String switchingFromSystemUserMessage, String switchingToSystemUserMessage) { + // TODO(b/278857848): Make full screen user switcher cover top part of the screen as well. + // This problem is seen only on phones, it works fine on tablets. + super(context, R.style.Theme_Material_NoActionBar_Fullscreen); mContext = context; - mService = service; - mUserId = newUser.id; mOldUser = oldUser; mNewUser = newUser; mSwitchingFromSystemUserMessage = switchingFromSystemUserMessage; mSwitchingToSystemUserMessage = switchingToSystemUserMessage; + mDisableAnimations = ActivityManager.isLowRamDeviceStatic() || SystemProperties.getBoolean( + "debug.usercontroller.disable_user_switching_dialog_animations", false); + mTraceCookie = UserHandle.MAX_SECONDARY_USER_ID * oldUser.id + newUser.id; inflateContent(); + configureWindow(); + } - if (aboveSystem) { - getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR); - } - - WindowManager.LayoutParams attrs = getWindow().getAttributes(); + private void configureWindow() { + final Window window = getWindow(); + final WindowManager.LayoutParams attrs = window.getAttributes(); attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR | - WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; - getWindow().setAttributes(attrs); + WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; + window.setAttributes(attrs); + window.setBackgroundDrawableResource(android.R.color.transparent); + window.setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR); } void inflateContent() { - // Set up the dialog contents setCancelable(false); - Resources res = getContext().getResources(); - // Custom view due to alignment and font size requirements - TextView view = (TextView) LayoutInflater.from(getContext()).inflate( - R.layout.user_switching_dialog, null); + setContentView(R.layout.user_switching_dialog); - String viewMessage = null; - if (UserManager.isDeviceInDemoMode(mContext)) { - if (mOldUser.isDemo()) { - viewMessage = res.getString(R.string.demo_restarting_message); - } else { - viewMessage = res.getString(R.string.demo_starting_message); - } - } else { - if (mOldUser.id == UserHandle.USER_SYSTEM) { - viewMessage = mSwitchingFromSystemUserMessage; - } else if (mNewUser.id == UserHandle.USER_SYSTEM) { - viewMessage = mSwitchingToSystemUserMessage; - } - - // If switchingFromSystemUserMessage or switchingToSystemUserMessage is null, fallback - // to system message. - if (viewMessage == null) { - viewMessage = res.getString(R.string.user_switching_message, mNewUser.name); - } - - view.setCompoundDrawablesWithIntrinsicBounds(null, - getContext().getDrawable(R.drawable.ic_swap_horiz), null, null); + final TextView textView = findViewById(R.id.message); + if (textView != null) { + final String message = getTextMessage(); + textView.setAccessibilityPaneTitle(message); + textView.setText(message); } - view.setAccessibilityPaneTitle(viewMessage); - view.setText(viewMessage); - setView(view); + + final ImageView imageView = findViewById(R.id.icon); + if (imageView != null) { + imageView.setImageBitmap(getUserIconRounded()); + } + + final ImageView progressCircular = findViewById(R.id.progress_circular); + if (progressCircular != null) { + if (mDisableAnimations) { + progressCircular.setVisibility(View.GONE); + } else { + final TypedValue value = new TypedValue(); + getContext().getTheme().resolveAttribute(R.attr.colorAccentPrimary, value, true); + progressCircular.setColorFilter(value.data); + } + } + } + + private Bitmap getUserIconRounded() { + final Bitmap bmp = ObjectUtils.getOrElse(BitmapFactory.decodeFile(mNewUser.iconPath), + defaultUserIcon(mNewUser.id)); + final int w = bmp.getWidth(); + final int h = bmp.getHeight(); + final Bitmap bmpRounded = Bitmap.createBitmap(w, h, bmp.getConfig()); + final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + paint.setShader(new BitmapShader(bmp, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)); + new Canvas(bmpRounded).drawRoundRect((new RectF(0, 0, w, h)), w / 2f, h / 2f, paint); + return bmpRounded; + } + + private Bitmap defaultUserIcon(@UserIdInt int userId) { + final Resources res = getContext().getResources(); + final Drawable icon = UserIcons.getDefaultUserIcon(res, userId, /* light= */ false); + return UserIcons.convertToBitmapAtUserIconSize(res, icon); + } + + private String getTextMessage() { + final Resources res = getContext().getResources(); + + if (UserManager.isDeviceInDemoMode(mContext)) { + return res.getString(mOldUser.isDemo() + ? R.string.demo_restarting_message + : R.string.demo_starting_message); + } + + final String message = + mOldUser.id == UserHandle.USER_SYSTEM ? mSwitchingFromSystemUserMessage + : mNewUser.id == UserHandle.USER_SYSTEM ? mSwitchingToSystemUserMessage : null; + + return message != null ? message + // If switchingFromSystemUserMessage or switchingToSystemUserMessage is null, + // fallback to system message. + : res.getString(R.string.user_switching_message, mNewUser.name); } @Override public void show() { - if (DEBUG) Slog.d(TAG, "show called"); + asyncTraceBegin("", 0); super.show(); - final View decorView = getWindow().getDecorView(); - if (decorView != null) { - decorView.getViewTreeObserver().addOnWindowShownListener(this); - } - // Add a timeout as a safeguard, in case a race in screen on/off causes the window - // callback to never come. - mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_USER), - WINDOW_SHOWN_TIMEOUT_MS); } @Override - public void onWindowShown() { - if (DEBUG) Slog.d(TAG, "onWindowShown called"); - startUser(); + public void dismiss() { + super.dismiss(); + asyncTraceEnd("", 0); } - void startUser() { - synchronized (this) { - if (!mStartedUser) { - Slog.i(TAG, "starting user " + mUserId); - mService.mUserController.startUserInForeground(mUserId); + public void show(@NonNull Runnable onShown) { + if (DEBUG) Slog.d(TAG, "show called"); + show(); + + if (mDisableAnimations) { + onShown.run(); + } else { + startShowAnimation(onShown); + } + } + + public void dismiss(@Nullable Runnable onDismissed) { + if (DEBUG) Slog.d(TAG, "dismiss called"); + + if (onDismissed == null) { + // no animation needed + dismiss(); + } else if (mDisableAnimations) { + dismiss(); + onDismissed.run(); + } else { + startDismissAnimation(() -> { dismiss(); - mStartedUser = true; - final View decorView = getWindow().getDecorView(); - if (decorView != null) { - decorView.getViewTreeObserver().removeOnWindowShownListener(this); - } - mHandler.removeMessages(MSG_START_USER); - } else { - Slog.i(TAG, "user " + mUserId + " already started"); - } + onDismissed.run(); + }); } } - private final Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_START_USER: - Slog.w(TAG, "user switch window not shown in " - + WINDOW_SHOWN_TIMEOUT_MS + " ms"); - startUser(); - break; + private void startShowAnimation(Runnable onAnimationEnd) { + asyncTraceBegin("-showAnimation", 1); + startDialogAnimation(new AlphaAnimation(0, 1), () -> { + asyncTraceEnd("-showAnimation", 1); + + asyncTraceBegin("-spinnerAnimation", 2); + startProgressAnimation(() -> { + asyncTraceEnd("-spinnerAnimation", 2); + + onAnimationEnd.run(); + }); + }); + } + + private void startDismissAnimation(Runnable onAnimationEnd) { + asyncTraceBegin("-dismissAnimation", 3); + startDialogAnimation(new AlphaAnimation(1, 0), () -> { + asyncTraceEnd("-dismissAnimation", 3); + + onAnimationEnd.run(); + }); + } + + private void startProgressAnimation(Runnable onAnimationEnd) { + final ImageView progressCircular = findViewById(R.id.progress_circular); + final AnimatedVectorDrawable avd = (AnimatedVectorDrawable) progressCircular.getDrawable(); + avd.registerAnimationCallback(new Animatable2.AnimationCallback() { + @Override + public void onAnimationEnd(Drawable drawable) { + onAnimationEnd.run(); } - } - }; + }); + avd.start(); + } + + private void startDialogAnimation(Animation animation, Runnable onAnimationEnd) { + animation.setDuration(DIALOG_SHOW_HIDE_ANIMATION_DURATION_MS); + animation.setAnimationListener(new Animation.AnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + + } + + @Override + public void onAnimationEnd(Animation animation) { + onAnimationEnd.run(); + } + + @Override + public void onAnimationRepeat(Animation animation) { + + } + }); + findViewById(R.id.content).startAnimation(animation); + } + + private void asyncTraceBegin(String subTag, int subCookie) { + Trace.asyncTraceBegin(TRACE_TAG, TAG + subTag, mTraceCookie + subCookie); + } + + private void asyncTraceEnd(String subTag, int subCookie) { + Trace.asyncTraceEnd(TRACE_TAG, TAG + subTag, mTraceCookie + subCookie); + } } 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 ab8f3f2279fe5..d12741ac8bd67 100644 --- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java @@ -211,8 +211,7 @@ public class UserControllerTest { @Test public void testStartUser_foreground() { mUserController.startUser(TEST_USER_ID, USER_START_MODE_FOREGROUND); - verify(mInjector.getWindowManager()).startFreezingScreen(anyInt(), anyInt()); - verify(mInjector.getWindowManager(), never()).stopFreezingScreen(); + verify(mInjector, never()).dismissUserSwitchingDialog(any()); verify(mInjector.getWindowManager(), times(1)).setSwitchingUser(anyBoolean()); verify(mInjector.getWindowManager()).setSwitchingUser(true); verify(mInjector).clearAllLockedTasks(anyString()); @@ -224,7 +223,8 @@ public class UserControllerTest { public void testStartUser_background() { boolean started = mUserController.startUser(TEST_USER_ID, USER_START_MODE_BACKGROUND); assertWithMessage("startUser(%s, foreground=false)", TEST_USER_ID).that(started).isTrue(); - verify(mInjector.getWindowManager(), never()).startFreezingScreen(anyInt(), anyInt()); + verify(mInjector, never()).showUserSwitchingDialog( + any(), any(), anyString(), anyString(), any()); verify(mInjector.getWindowManager(), never()).setSwitchingUser(anyBoolean()); verify(mInjector, never()).clearAllLockedTasks(anyString()); startBackgroundUserAssertions(); @@ -276,7 +276,8 @@ public class UserControllerTest { assertWithMessage("startUserOnDisplay(%s, %s)", TEST_USER_ID, 42).that(started).isTrue(); verifyUserAssignedToDisplay(TEST_USER_ID, 42); - verify(mInjector.getWindowManager(), never()).startFreezingScreen(anyInt(), anyInt()); + verify(mInjector, never()).showUserSwitchingDialog( + any(), any(), anyString(), anyString(), any()); verify(mInjector.getWindowManager(), never()).setSwitchingUser(anyBoolean()); verify(mInjector, never()).clearAllLockedTasks(anyString()); startBackgroundUserAssertions(); @@ -288,8 +289,9 @@ public class UserControllerTest { /* maxRunningUsers= */ 3, /* delayUserDataLocking= */ false); mUserController.startUser(TEST_USER_ID, USER_START_MODE_FOREGROUND); - verify(mInjector.getWindowManager(), never()).startFreezingScreen(anyInt(), anyInt()); - verify(mInjector.getWindowManager(), never()).stopFreezingScreen(); + verify(mInjector, never()).showUserSwitchingDialog( + any(), any(), anyString(), anyString(), any()); + verify(mInjector, never()).dismissUserSwitchingDialog(any()); verify(mInjector.getWindowManager(), never()).setSwitchingUser(anyBoolean()); startForegroundUserAssertions(); } @@ -310,7 +312,8 @@ public class UserControllerTest { // Make sure no intents have been fired for pre-created users. assertTrue(mInjector.mSentIntents.isEmpty()); - verify(mInjector.getWindowManager(), never()).startFreezingScreen(anyInt(), anyInt()); + verify(mInjector, never()).showUserSwitchingDialog( + any(), any(), anyString(), anyString(), any()); verify(mInjector.getWindowManager(), never()).setSwitchingUser(anyBoolean()); verify(mInjector, never()).clearAllLockedTasks(anyString()); @@ -442,7 +445,7 @@ public class UserControllerTest { // Verify that continueUserSwitch worked as expected continueAndCompleteUserSwitch(userState, oldUserId, newUserId); verify(mInjector, times(0)).dismissKeyguard(any()); - verify(mInjector.getWindowManager(), times(1)).stopFreezingScreen(); + verify(mInjector, times(1)).dismissUserSwitchingDialog(any()); continueUserSwitchAssertions(oldUserId, TEST_USER_ID, false); verifySystemUserVisibilityChangesNeverNotified(); } @@ -463,7 +466,7 @@ public class UserControllerTest { // Verify that continueUserSwitch worked as expected continueAndCompleteUserSwitch(userState, oldUserId, newUserId); verify(mInjector, times(1)).dismissKeyguard(any()); - verify(mInjector.getWindowManager(), times(1)).stopFreezingScreen(); + verify(mInjector, times(1)).dismissUserSwitchingDialog(any()); continueUserSwitchAssertions(oldUserId, TEST_USER_ID, false); verifySystemUserVisibilityChangesNeverNotified(); } @@ -483,7 +486,7 @@ public class UserControllerTest { mInjector.mHandler.clearAllRecordedMessages(); // Verify that continueUserSwitch worked as expected continueAndCompleteUserSwitch(userState, oldUserId, newUserId); - verify(mInjector.getWindowManager(), never()).stopFreezingScreen(); + verify(mInjector, never()).dismissUserSwitchingDialog(any()); continueUserSwitchAssertions(oldUserId, TEST_USER_ID, false); } @@ -985,8 +988,7 @@ public class UserControllerTest { mInjector.mHandler.clearAllRecordedMessages(); // Verify that continueUserSwitch worked as expected continueAndCompleteUserSwitch(userState, oldUserId, newUserId); - verify(mInjector.getWindowManager(), times(expectedNumberOfCalls)) - .stopFreezingScreen(); + verify(mInjector, times(expectedNumberOfCalls)).dismissUserSwitchingDialog(any()); continueUserSwitchAssertions(oldUserId, newUserId, expectOldUserStopping); } @@ -1188,6 +1190,22 @@ public class UserControllerTest { runnable.run(); } + @Override + void showUserSwitchingDialog(UserInfo fromUser, UserInfo toUser, + String switchingFromSystemUserMessage, String switchingToSystemUserMessage, + Runnable onShown) { + if (onShown != null) { + onShown.run(); + } + } + + @Override + void dismissUserSwitchingDialog(Runnable onDismissed) { + if (onDismissed != null) { + onDismissed.run(); + } + } + @Override protected LockPatternUtils getLockPatternUtils() { return mLockPatternUtilsMock;