From 67e098b902643e9c3810349317d08786106f4675 Mon Sep 17 00:00:00 2001 From: Yasin Kilicdere Date: Wed, 26 Apr 2023 21:52:04 +0100 Subject: [PATCH] Prevent UserSwitchingDialog flashing when setup wizard is shown. When switching to a newly created user, or switching to a user with an uncompleted setup, setup wizard (SUW) is shown during the user switch and SUW is drawn over the user switching dialog. Then when the user switching dialog is dismissed it becomes visible again for a moment. This CL prevents that jank by freezing the screen while showing the user switching dialog, if the target user has not completed the SUW. Bug: 279773661 Test: Visual Change-Id: Ia611d3d062ba78c8def173ab177f183d5494c919 --- .../com/android/server/am/UserController.java | 3 +- .../server/am/UserSwitchingDialog.java | 63 +++++++++++++++---- 2 files changed, 53 insertions(+), 13 deletions(-) diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index a181402e2d9f1..b2fdee7a6f89d 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -3747,7 +3747,8 @@ class UserController implements Handler.Callback { synchronized (mUserSwitchingDialogLock) { dismissUserSwitchingDialog(null); mUserSwitchingDialog = new UserSwitchingDialog(mService.mContext, fromUser, toUser, - switchingFromSystemUserMessage, switchingToSystemUserMessage); + switchingFromSystemUserMessage, switchingToSystemUserMessage, + getWindowManager()); 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 649305f7ee015..6da6a6ecda521 100644 --- a/services/core/java/com/android/server/am/UserSwitchingDialog.java +++ b/services/core/java/com/android/server/am/UserSwitchingDialog.java @@ -19,7 +19,6 @@ package com.android.server.am; 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; @@ -38,6 +37,7 @@ import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; +import android.provider.Settings; import android.util.Slog; import android.util.TypedValue; import android.view.View; @@ -51,6 +51,7 @@ import android.widget.TextView; import com.android.internal.R; import com.android.internal.util.ObjectUtils; import com.android.internal.util.UserIcons; +import com.android.server.wm.WindowManagerService; /** * Dialog to show during the user switch. This dialog shows target user's name and their profile @@ -70,11 +71,14 @@ class UserSwitchingDialog extends Dialog { protected final UserInfo mNewUser; private final String mSwitchingFromSystemUserMessage; private final String mSwitchingToSystemUserMessage; + private final WindowManagerService mWindowManager; protected final Context mContext; private final int mTraceCookie; + private final boolean mNeedToFreezeScreen; UserSwitchingDialog(Context context, UserInfo oldUser, UserInfo newUser, - String switchingFromSystemUserMessage, String switchingToSystemUserMessage) { + String switchingFromSystemUserMessage, String switchingToSystemUserMessage, + WindowManagerService windowManager) { // 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); @@ -84,8 +88,10 @@ class UserSwitchingDialog extends Dialog { mNewUser = newUser; mSwitchingFromSystemUserMessage = switchingFromSystemUserMessage; mSwitchingToSystemUserMessage = switchingToSystemUserMessage; - mDisableAnimations = ActivityManager.isLowRamDeviceStatic() || SystemProperties.getBoolean( + mDisableAnimations = SystemProperties.getBoolean( "debug.usercontroller.disable_user_switching_dialog_animations", false); + mWindowManager = windowManager; + mNeedToFreezeScreen = !mDisableAnimations && !isUserSetupComplete(newUser); mTraceCookie = UserHandle.MAX_SECONDARY_USER_ID * oldUser.id + newUser.id; inflateContent(); @@ -167,6 +173,11 @@ class UserSwitchingDialog extends Dialog { : res.getString(R.string.user_switching_message, mNewUser.name); } + private boolean isUserSetupComplete(UserInfo user) { + return Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.USER_SETUP_COMPLETE, /* default= */ 0, user.id) == 1; + } + @Override public void show() { asyncTraceBegin("", 0); @@ -176,29 +187,24 @@ class UserSwitchingDialog extends Dialog { @Override public void dismiss() { super.dismiss(); + stopFreezingScreen(); asyncTraceEnd("", 0); } public void show(@NonNull Runnable onShown) { if (DEBUG) Slog.d(TAG, "show called"); show(); - - if (mDisableAnimations) { + startShowAnimation(() -> { + startFreezingScreen(); 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(); @@ -207,7 +213,31 @@ class UserSwitchingDialog extends Dialog { } } + private void startFreezingScreen() { + if (!mNeedToFreezeScreen) { + return; + } + if (DEBUG) Slog.d(TAG, "startFreezingScreen"); + Trace.traceBegin(TRACE_TAG, "startFreezingScreen"); + mWindowManager.startFreezingScreen(0, 0); + Trace.traceEnd(TRACE_TAG); + } + + private void stopFreezingScreen() { + if (!mNeedToFreezeScreen) { + return; + } + if (DEBUG) Slog.d(TAG, "stopFreezingScreen"); + Trace.traceBegin(TRACE_TAG, "stopFreezingScreen"); + mWindowManager.stopFreezingScreen(); + Trace.traceEnd(TRACE_TAG); + } + private void startShowAnimation(Runnable onAnimationEnd) { + if (mDisableAnimations) { + onAnimationEnd.run(); + return; + } asyncTraceBegin("-showAnimation", 1); startDialogAnimation(new AlphaAnimation(0, 1), () -> { asyncTraceEnd("-showAnimation", 1); @@ -222,6 +252,11 @@ class UserSwitchingDialog extends Dialog { } private void startDismissAnimation(Runnable onAnimationEnd) { + if (mDisableAnimations || mNeedToFreezeScreen) { + // animations are disabled or screen is frozen, no need to play an animation + onAnimationEnd.run(); + return; + } asyncTraceBegin("-dismissAnimation", 3); startDialogAnimation(new AlphaAnimation(1, 0), () -> { asyncTraceEnd("-dismissAnimation", 3); @@ -231,6 +266,10 @@ class UserSwitchingDialog extends Dialog { } private void startProgressAnimation(Runnable onAnimationEnd) { + if (mDisableAnimations) { + onAnimationEnd.run(); + return; + } final ImageView progressCircular = findViewById(R.id.progress_circular); final AnimatedVectorDrawable avd = (AnimatedVectorDrawable) progressCircular.getDrawable(); avd.registerAnimationCallback(new Animatable2.AnimationCallback() {