Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 67e098b9 authored by Yasin Kilicdere's avatar Yasin Kilicdere
Browse files

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
parent d8c71e5d
Loading
Loading
Loading
Loading
+2 −1
Original line number Original line Diff line number Diff line
@@ -3747,7 +3747,8 @@ class UserController implements Handler.Callback {
            synchronized (mUserSwitchingDialogLock) {
            synchronized (mUserSwitchingDialogLock) {
                dismissUserSwitchingDialog(null);
                dismissUserSwitchingDialog(null);
                mUserSwitchingDialog = new UserSwitchingDialog(mService.mContext, fromUser, toUser,
                mUserSwitchingDialog = new UserSwitchingDialog(mService.mContext, fromUser, toUser,
                        switchingFromSystemUserMessage, switchingToSystemUserMessage);
                        switchingFromSystemUserMessage, switchingToSystemUserMessage,
                        getWindowManager());
                mUserSwitchingDialog.show(onShown);
                mUserSwitchingDialog.show(onShown);
            }
            }
        }
        }
+51 −12
Original line number Original line Diff line number Diff line
@@ -19,7 +19,6 @@ package com.android.server.am;
import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.Dialog;
import android.app.Dialog;
import android.content.Context;
import android.content.Context;
import android.content.pm.UserInfo;
import android.content.pm.UserInfo;
@@ -38,6 +37,7 @@ import android.os.SystemProperties;
import android.os.Trace;
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManager;
import android.provider.Settings;
import android.util.Slog;
import android.util.Slog;
import android.util.TypedValue;
import android.util.TypedValue;
import android.view.View;
import android.view.View;
@@ -51,6 +51,7 @@ import android.widget.TextView;
import com.android.internal.R;
import com.android.internal.R;
import com.android.internal.util.ObjectUtils;
import com.android.internal.util.ObjectUtils;
import com.android.internal.util.UserIcons;
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
 * 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;
    protected final UserInfo mNewUser;
    private final String mSwitchingFromSystemUserMessage;
    private final String mSwitchingFromSystemUserMessage;
    private final String mSwitchingToSystemUserMessage;
    private final String mSwitchingToSystemUserMessage;
    private final WindowManagerService mWindowManager;
    protected final Context mContext;
    protected final Context mContext;
    private final int mTraceCookie;
    private final int mTraceCookie;
    private final boolean mNeedToFreezeScreen;


    UserSwitchingDialog(Context context, UserInfo oldUser, UserInfo newUser,
    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.
        // 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.
        //                    This problem is seen only on phones, it works fine on tablets.
        super(context, R.style.Theme_Material_NoActionBar_Fullscreen);
        super(context, R.style.Theme_Material_NoActionBar_Fullscreen);
@@ -84,8 +88,10 @@ class UserSwitchingDialog extends Dialog {
        mNewUser = newUser;
        mNewUser = newUser;
        mSwitchingFromSystemUserMessage = switchingFromSystemUserMessage;
        mSwitchingFromSystemUserMessage = switchingFromSystemUserMessage;
        mSwitchingToSystemUserMessage = switchingToSystemUserMessage;
        mSwitchingToSystemUserMessage = switchingToSystemUserMessage;
        mDisableAnimations = ActivityManager.isLowRamDeviceStatic() || SystemProperties.getBoolean(
        mDisableAnimations = SystemProperties.getBoolean(
                "debug.usercontroller.disable_user_switching_dialog_animations", false);
                "debug.usercontroller.disable_user_switching_dialog_animations", false);
        mWindowManager = windowManager;
        mNeedToFreezeScreen = !mDisableAnimations && !isUserSetupComplete(newUser);
        mTraceCookie = UserHandle.MAX_SECONDARY_USER_ID * oldUser.id + newUser.id;
        mTraceCookie = UserHandle.MAX_SECONDARY_USER_ID * oldUser.id + newUser.id;


        inflateContent();
        inflateContent();
@@ -167,6 +173,11 @@ class UserSwitchingDialog extends Dialog {
                : res.getString(R.string.user_switching_message, mNewUser.name);
                : 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
    @Override
    public void show() {
    public void show() {
        asyncTraceBegin("", 0);
        asyncTraceBegin("", 0);
@@ -176,29 +187,24 @@ class UserSwitchingDialog extends Dialog {
    @Override
    @Override
    public void dismiss() {
    public void dismiss() {
        super.dismiss();
        super.dismiss();
        stopFreezingScreen();
        asyncTraceEnd("", 0);
        asyncTraceEnd("", 0);
    }
    }


    public void show(@NonNull Runnable onShown) {
    public void show(@NonNull Runnable onShown) {
        if (DEBUG) Slog.d(TAG, "show called");
        if (DEBUG) Slog.d(TAG, "show called");
        show();
        show();

        startShowAnimation(() -> {
        if (mDisableAnimations) {
            startFreezingScreen();
            onShown.run();
            onShown.run();
        } else {
        });
            startShowAnimation(onShown);
        }
    }
    }


    public void dismiss(@Nullable Runnable onDismissed) {
    public void dismiss(@Nullable Runnable onDismissed) {
        if (DEBUG) Slog.d(TAG, "dismiss called");
        if (DEBUG) Slog.d(TAG, "dismiss called");

        if (onDismissed == null) {
        if (onDismissed == null) {
            // no animation needed
            // no animation needed
            dismiss();
            dismiss();
        } else if (mDisableAnimations) {
            dismiss();
            onDismissed.run();
        } else {
        } else {
            startDismissAnimation(() -> {
            startDismissAnimation(() -> {
                dismiss();
                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) {
    private void startShowAnimation(Runnable onAnimationEnd) {
        if (mDisableAnimations) {
            onAnimationEnd.run();
            return;
        }
        asyncTraceBegin("-showAnimation", 1);
        asyncTraceBegin("-showAnimation", 1);
        startDialogAnimation(new AlphaAnimation(0, 1), () -> {
        startDialogAnimation(new AlphaAnimation(0, 1), () -> {
            asyncTraceEnd("-showAnimation", 1);
            asyncTraceEnd("-showAnimation", 1);
@@ -222,6 +252,11 @@ class UserSwitchingDialog extends Dialog {
    }
    }


    private void startDismissAnimation(Runnable onAnimationEnd) {
    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);
        asyncTraceBegin("-dismissAnimation", 3);
        startDialogAnimation(new AlphaAnimation(1, 0), () -> {
        startDialogAnimation(new AlphaAnimation(1, 0), () -> {
            asyncTraceEnd("-dismissAnimation", 3);
            asyncTraceEnd("-dismissAnimation", 3);
@@ -231,6 +266,10 @@ class UserSwitchingDialog extends Dialog {
    }
    }


    private void startProgressAnimation(Runnable onAnimationEnd) {
    private void startProgressAnimation(Runnable onAnimationEnd) {
        if (mDisableAnimations) {
            onAnimationEnd.run();
            return;
        }
        final ImageView progressCircular = findViewById(R.id.progress_circular);
        final ImageView progressCircular = findViewById(R.id.progress_circular);
        final AnimatedVectorDrawable avd = (AnimatedVectorDrawable) progressCircular.getDrawable();
        final AnimatedVectorDrawable avd = (AnimatedVectorDrawable) progressCircular.getDrawable();
        avd.registerAnimationCallback(new Animatable2.AnimationCallback() {
        avd.registerAnimationCallback(new Animatable2.AnimationCallback() {