From 2d5edc334444509925f8d3b9cad5ef997a900d23 Mon Sep 17 00:00:00 2001 From: Jordan Demeulenaere Date: Thu, 28 Oct 2021 15:01:44 +0200 Subject: [PATCH] Disable dialog exit animation when locking (1/2) Before this CL, when an animated dialog was dismissed because we were locking the device, we would run the exit animation while fading out the dialog window with the current doze amount. This did not look really good. This CL now disables the exit animation when the dialog is dismissed because the device was locked. See b/193634619#comment8 for before/after videos. Bug: 193634619 Test: Manual Change-Id: I516b5c0e9ccf9d5650b5708350472aeb209d71e5 --- .../animation/DialogLaunchAnimator.kt | 41 +++++++++---------- .../systemui/statusbar/phone/StatusBar.java | 8 +--- .../statusbar/phone/SystemUIDialog.java | 29 ++++++++++--- .../phone/SystemUIHostDialogProvider.kt | 8 +++- .../phone/dagger/StatusBarPhoneModule.java | 8 ++-- .../animation/DialogLaunchAnimatorTest.kt | 7 +--- .../statusbar/phone/StatusBarTest.java | 5 +-- 7 files changed, 57 insertions(+), 49 deletions(-) diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt index 669a054eaa2a7..53f29b6f963a8 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt @@ -38,9 +38,6 @@ private const val TAG = "DialogLaunchAnimator" /** * A class that allows dialogs to be started in a seamless way from a view that is transforming * nicely into the starting dialog. - * - * Important: Don't forget to call [DialogLaunchAnimator.onDozeAmountChanged] when the doze amount - * changes to gracefully handle dialogs fading out when the device is dozing. */ class DialogLaunchAnimator( private val context: Context, @@ -89,8 +86,17 @@ class DialogLaunchAnimator( // host dialog. if (dialog is ListenableDialog) { dialog.addListener(object : DialogListener { - override fun onDismiss() { + override fun onDismiss(reason: DialogListener.DismissReason) { dialog.removeListener(this) + + // We disable the exit animation if we are dismissing the dialog because the + // device is being locked, otherwise the animation looks bad if AOD is enabled. + // If AOD is disabled the screen will directly becomes black and we won't see + // the animation anyways. + if (reason == DialogListener.DismissReason.DEVICE_LOCKED) { + launchAnimation.exitAnimationDisabled = true + } + hostDialog.dismiss() } @@ -117,13 +123,6 @@ class DialogLaunchAnimator( return hostDialog } - /** Notify the current doze amount, to ensure that dialogs fade out when dozing. */ - // TODO(b/193634619): Replace this by some mandatory constructor parameter to make sure that we - // don't forget to call this when the doze amount changes. - fun onDozeAmountChanged(amount: Float) { - currentAnimations.forEach { it.onDozeAmountChanged(amount) } - } - /** * Ensure that all dialogs currently shown won't animate into their touch surface when * dismissed. @@ -168,8 +167,16 @@ interface ListenableDialog { } interface DialogListener { + /** The reason why a dialog was dismissed. */ + enum class DismissReason { + UNKNOWN, + + /** The device was locked, which dismissed this dialog. */ + DEVICE_LOCKED, + } + /** Called when this dialog dismiss() is called. */ - fun onDismiss() + fun onDismiss(reason: DismissReason) /** Called when this dialog hide() is called. */ fun onHide() @@ -638,14 +645,4 @@ private class DialogLaunchAnimation( return (touchSurface.parent as? View)?.isShown ?: true } - - internal fun onDozeAmountChanged(amount: Float) { - val alpha = Interpolators.ALPHA_OUT.getInterpolation(1 - amount) - val decorView = this.hostDialog.window?.decorView ?: return - if (decorView.hasOverlappingRendering() && alpha > 0.0f && - alpha < 1.0f && decorView.layerType != View.LAYER_TYPE_HARDWARE) { - decorView.setLayerType(View.LAYER_TYPE_HARDWARE, null) - } - decorView.alpha = alpha - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index c9dd9833999aa..41b64dd387ca7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -136,7 +136,6 @@ import com.android.systemui.R; import com.android.systemui.SystemUI; import com.android.systemui.animation.ActivityLaunchAnimator; import com.android.systemui.animation.DelegateLaunchAnimatorController; -import com.android.systemui.animation.DialogLaunchAnimator; import com.android.systemui.assist.AssistManager; import com.android.systemui.battery.BatteryMeterViewController; import com.android.systemui.biometrics.AuthRippleController; @@ -681,7 +680,6 @@ public class StatusBar extends SystemUI implements private HeadsUpAppearanceController mHeadsUpAppearanceController; private final ActivityLaunchAnimator mActivityLaunchAnimator; - private final DialogLaunchAnimator mDialogLaunchAnimator; private NotificationLaunchAnimatorControllerProvider mNotificationAnimationProvider; protected StatusBarNotificationPresenter mPresenter; private NotificationActivityStarter mNotificationActivityStarter; @@ -808,8 +806,7 @@ public class StatusBar extends SystemUI implements Optional startingSurfaceOptional, TunerService tunerService, DumpManager dumpManager, - ActivityLaunchAnimator activityLaunchAnimator, - DialogLaunchAnimator dialogLaunchAnimator) { + ActivityLaunchAnimator activityLaunchAnimator) { super(context); mNotificationsController = notificationsController; mLightBarController = lightBarController; @@ -924,7 +921,6 @@ public class StatusBar extends SystemUI implements mActivityIntentHelper = new ActivityIntentHelper(mContext); mActivityLaunchAnimator = activityLaunchAnimator; - mDialogLaunchAnimator = dialogLaunchAnimator; // The status bar background may need updating when the ongoing call status changes. mOngoingCallController.addCallback((animate) -> maybeUpdateBarMode()); @@ -4503,8 +4499,6 @@ public class StatusBar extends SystemUI implements && !mBiometricUnlockController.isWakeAndUnlock()) { mLightRevealScrim.setRevealAmount(1f - linear); } - - mDialogLaunchAnimator.onDozeAmountChanged(linear); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java index 18aa6893e7bc1..189abe2d55d06 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java @@ -35,6 +35,7 @@ import android.view.WindowManager.LayoutParams; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.animation.DialogListener; +import com.android.systemui.animation.DialogListener.DismissReason; import com.android.systemui.animation.ListenableDialog; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -62,6 +63,10 @@ public class SystemUIDialog extends AlertDialog implements ListenableDialog { } public SystemUIDialog(Context context, int theme) { + this(context, theme, true /* dismissOnDeviceLock */); + } + + public SystemUIDialog(Context context, int theme, boolean dismissOnDeviceLock) { super(context, theme); mContext = context; @@ -70,7 +75,7 @@ public class SystemUIDialog extends AlertDialog implements ListenableDialog { attrs.setTitle(getClass().getSimpleName()); getWindow().setAttributes(attrs); - mDismissReceiver = new DismissReceiver(this); + mDismissReceiver = dismissOnDeviceLock ? new DismissReceiver(this) : null; } @Override @@ -111,13 +116,19 @@ public class SystemUIDialog extends AlertDialog implements ListenableDialog { @Override protected void onStart() { super.onStart(); - mDismissReceiver.register(); + + if (mDismissReceiver != null) { + mDismissReceiver.register(); + } } @Override protected void onStop() { super.onStop(); - mDismissReceiver.unregister(); + + if (mDismissReceiver != null) { + mDismissReceiver.unregister(); + } } @Override @@ -132,10 +143,14 @@ public class SystemUIDialog extends AlertDialog implements ListenableDialog { @Override public void dismiss() { + dismiss(DismissReason.UNKNOWN); + } + + private void dismiss(DismissReason reason) { super.dismiss(); for (DialogListener listener : new LinkedHashSet<>(mDialogListeners)) { - listener.onDismiss(); + listener.onDismiss(reason); } } @@ -251,7 +266,11 @@ public class SystemUIDialog extends AlertDialog implements ListenableDialog { @Override public void onReceive(Context context, Intent intent) { - mDialog.dismiss(); + if (mDialog instanceof SystemUIDialog) { + ((SystemUIDialog) mDialog).dismiss(DismissReason.DEVICE_LOCKED); + } else { + mDialog.dismiss(); + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIHostDialogProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIHostDialogProvider.kt index 6a49a6da0d62a..7b65bccfa0e8e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIHostDialogProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIHostDialogProvider.kt @@ -16,12 +16,18 @@ class SystemUIHostDialogProvider : HostDialogProvider { return SystemUIHostDialog(context, theme, onCreateCallback, dismissOverride) } + /** + * This host dialog is a SystemUIDialog so that it's displayed above all SystemUI windows. Note + * that it is not automatically dismissed when the device is locked, but only when the hosted + * (original) dialog is dismissed. That way, the behavior of the dialog (dismissed when locking + * or not) is consistent with when the dialog is shown with or without the dialog animator. + */ private class SystemUIHostDialog( context: Context, theme: Int, private val onCreateCallback: () -> Unit, private val dismissOverride: (() -> Unit) -> Unit - ) : SystemUIDialog(context, theme) { + ) : SystemUIDialog(context, theme, false /* dismissOnDeviceLock */) { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) onCreateCallback() diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java index 076a9a9bb0121..7b56682f0577c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java @@ -29,7 +29,6 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.InitController; import com.android.systemui.animation.ActivityLaunchAnimator; -import com.android.systemui.animation.DialogLaunchAnimator; import com.android.systemui.assist.AssistManager; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.classifier.FalsingCollector; @@ -246,8 +245,7 @@ public interface StatusBarPhoneModule { Optional startingSurfaceOptional, TunerService tunerService, DumpManager dumpManager, - ActivityLaunchAnimator activityLaunchAnimator, - DialogLaunchAnimator dialogLaunchAnimator) { + ActivityLaunchAnimator activityLaunchAnimator) { return new StatusBar( context, notificationsController, @@ -349,7 +347,7 @@ public interface StatusBarPhoneModule { startingSurfaceOptional, tunerService, dumpManager, - activityLaunchAnimator, - dialogLaunchAnimator); + activityLaunchAnimator + ); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt index 5bcf828afe9f4..54278066b5d3c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt @@ -12,6 +12,7 @@ import android.view.WindowManager import android.widget.LinearLayout import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.animation.DialogListener.DismissReason import junit.framework.Assert.assertEquals import junit.framework.Assert.assertFalse import junit.framework.Assert.assertTrue @@ -63,10 +64,6 @@ class DialogLaunchAnimatorTest : SysuiTestCase() { assertEquals(1, hostDialogRoot.childCount) assertEquals(dialog.contentView, hostDialogRoot.getChildAt(0)) - // If we are dozing, the host dialog window also fades out. - runOnMainThreadAndWaitForIdleSync { dialogLaunchAnimator.onDozeAmountChanged(0.5f) } - assertTrue(hostDialog.window!!.decorView.alpha < 1f) - // Hiding/showing/dismissing the dialog should hide/show/dismiss the host dialog given that // it's a ListenableDialog. runOnMainThreadAndWaitForIdleSync { dialog.hide() } @@ -164,7 +161,7 @@ class DialogLaunchAnimatorTest : SysuiTestCase() { override fun dismiss() { super.dismiss() - notifyListeners { onDismiss() } + notifyListeners { onDismiss(DismissReason.UNKNOWN) } } override fun hide() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index d0d3d41abbc72..b77c3d6cfea02 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -78,7 +78,6 @@ import com.android.systemui.InitController; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.animation.ActivityLaunchAnimator; -import com.android.systemui.animation.DialogLaunchAnimator; import com.android.systemui.assist.AssistManager; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.classifier.FalsingCollectorFake; @@ -282,7 +281,6 @@ public class StatusBarTest extends SysuiTestCase { @Mock private OperatorNameViewController.Factory mOperatorNameViewControllerFactory; @Mock private PhoneStatusBarViewController.Factory mPhoneStatusBarViewControllerFactory; @Mock private ActivityLaunchAnimator mActivityLaunchAnimator; - @Mock private DialogLaunchAnimator mDialogLaunchAnimator; private ShadeController mShadeController; private final FakeSystemClock mFakeSystemClock = new FakeSystemClock(); private FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock); @@ -464,8 +462,7 @@ public class StatusBarTest extends SysuiTestCase { Optional.of(mStartingSurface), mTunerService, mock(DumpManager.class), - mActivityLaunchAnimator, - mDialogLaunchAnimator); + mActivityLaunchAnimator); when(mKeyguardViewMediator.registerStatusBar( any(StatusBar.class), any(NotificationPanelViewController.class),