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
This commit is contained in:
@@ -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
|
* A class that allows dialogs to be started in a seamless way from a view that is transforming
|
||||||
* nicely into the starting dialog.
|
* 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(
|
class DialogLaunchAnimator(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
@@ -89,8 +86,17 @@ class DialogLaunchAnimator(
|
|||||||
// host dialog.
|
// host dialog.
|
||||||
if (dialog is ListenableDialog) {
|
if (dialog is ListenableDialog) {
|
||||||
dialog.addListener(object : DialogListener {
|
dialog.addListener(object : DialogListener {
|
||||||
override fun onDismiss() {
|
override fun onDismiss(reason: DialogListener.DismissReason) {
|
||||||
dialog.removeListener(this)
|
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()
|
hostDialog.dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,13 +123,6 @@ class DialogLaunchAnimator(
|
|||||||
return hostDialog
|
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
|
* Ensure that all dialogs currently shown won't animate into their touch surface when
|
||||||
* dismissed.
|
* dismissed.
|
||||||
@@ -168,8 +167,16 @@ interface ListenableDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface DialogListener {
|
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. */
|
/** Called when this dialog dismiss() is called. */
|
||||||
fun onDismiss()
|
fun onDismiss(reason: DismissReason)
|
||||||
|
|
||||||
/** Called when this dialog hide() is called. */
|
/** Called when this dialog hide() is called. */
|
||||||
fun onHide()
|
fun onHide()
|
||||||
@@ -638,14 +645,4 @@ private class DialogLaunchAnimation(
|
|||||||
|
|
||||||
return (touchSurface.parent as? View)?.isShown ?: true
|
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,7 +136,6 @@ import com.android.systemui.R;
|
|||||||
import com.android.systemui.SystemUI;
|
import com.android.systemui.SystemUI;
|
||||||
import com.android.systemui.animation.ActivityLaunchAnimator;
|
import com.android.systemui.animation.ActivityLaunchAnimator;
|
||||||
import com.android.systemui.animation.DelegateLaunchAnimatorController;
|
import com.android.systemui.animation.DelegateLaunchAnimatorController;
|
||||||
import com.android.systemui.animation.DialogLaunchAnimator;
|
|
||||||
import com.android.systemui.assist.AssistManager;
|
import com.android.systemui.assist.AssistManager;
|
||||||
import com.android.systemui.battery.BatteryMeterViewController;
|
import com.android.systemui.battery.BatteryMeterViewController;
|
||||||
import com.android.systemui.biometrics.AuthRippleController;
|
import com.android.systemui.biometrics.AuthRippleController;
|
||||||
@@ -681,7 +680,6 @@ public class StatusBar extends SystemUI implements
|
|||||||
|
|
||||||
private HeadsUpAppearanceController mHeadsUpAppearanceController;
|
private HeadsUpAppearanceController mHeadsUpAppearanceController;
|
||||||
private final ActivityLaunchAnimator mActivityLaunchAnimator;
|
private final ActivityLaunchAnimator mActivityLaunchAnimator;
|
||||||
private final DialogLaunchAnimator mDialogLaunchAnimator;
|
|
||||||
private NotificationLaunchAnimatorControllerProvider mNotificationAnimationProvider;
|
private NotificationLaunchAnimatorControllerProvider mNotificationAnimationProvider;
|
||||||
protected StatusBarNotificationPresenter mPresenter;
|
protected StatusBarNotificationPresenter mPresenter;
|
||||||
private NotificationActivityStarter mNotificationActivityStarter;
|
private NotificationActivityStarter mNotificationActivityStarter;
|
||||||
@@ -808,8 +806,7 @@ public class StatusBar extends SystemUI implements
|
|||||||
Optional<StartingSurface> startingSurfaceOptional,
|
Optional<StartingSurface> startingSurfaceOptional,
|
||||||
TunerService tunerService,
|
TunerService tunerService,
|
||||||
DumpManager dumpManager,
|
DumpManager dumpManager,
|
||||||
ActivityLaunchAnimator activityLaunchAnimator,
|
ActivityLaunchAnimator activityLaunchAnimator) {
|
||||||
DialogLaunchAnimator dialogLaunchAnimator) {
|
|
||||||
super(context);
|
super(context);
|
||||||
mNotificationsController = notificationsController;
|
mNotificationsController = notificationsController;
|
||||||
mLightBarController = lightBarController;
|
mLightBarController = lightBarController;
|
||||||
@@ -924,7 +921,6 @@ public class StatusBar extends SystemUI implements
|
|||||||
|
|
||||||
mActivityIntentHelper = new ActivityIntentHelper(mContext);
|
mActivityIntentHelper = new ActivityIntentHelper(mContext);
|
||||||
mActivityLaunchAnimator = activityLaunchAnimator;
|
mActivityLaunchAnimator = activityLaunchAnimator;
|
||||||
mDialogLaunchAnimator = dialogLaunchAnimator;
|
|
||||||
|
|
||||||
// The status bar background may need updating when the ongoing call status changes.
|
// The status bar background may need updating when the ongoing call status changes.
|
||||||
mOngoingCallController.addCallback((animate) -> maybeUpdateBarMode());
|
mOngoingCallController.addCallback((animate) -> maybeUpdateBarMode());
|
||||||
@@ -4503,8 +4499,6 @@ public class StatusBar extends SystemUI implements
|
|||||||
&& !mBiometricUnlockController.isWakeAndUnlock()) {
|
&& !mBiometricUnlockController.isWakeAndUnlock()) {
|
||||||
mLightRevealScrim.setRevealAmount(1f - linear);
|
mLightRevealScrim.setRevealAmount(1f - linear);
|
||||||
}
|
}
|
||||||
|
|
||||||
mDialogLaunchAnimator.onDozeAmountChanged(linear);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import android.view.WindowManager.LayoutParams;
|
|||||||
import com.android.systemui.Dependency;
|
import com.android.systemui.Dependency;
|
||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
import com.android.systemui.animation.DialogListener;
|
import com.android.systemui.animation.DialogListener;
|
||||||
|
import com.android.systemui.animation.DialogListener.DismissReason;
|
||||||
import com.android.systemui.animation.ListenableDialog;
|
import com.android.systemui.animation.ListenableDialog;
|
||||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||||
@@ -62,6 +63,10 @@ public class SystemUIDialog extends AlertDialog implements ListenableDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public SystemUIDialog(Context context, int theme) {
|
public SystemUIDialog(Context context, int theme) {
|
||||||
|
this(context, theme, true /* dismissOnDeviceLock */);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SystemUIDialog(Context context, int theme, boolean dismissOnDeviceLock) {
|
||||||
super(context, theme);
|
super(context, theme);
|
||||||
mContext = context;
|
mContext = context;
|
||||||
|
|
||||||
@@ -70,7 +75,7 @@ public class SystemUIDialog extends AlertDialog implements ListenableDialog {
|
|||||||
attrs.setTitle(getClass().getSimpleName());
|
attrs.setTitle(getClass().getSimpleName());
|
||||||
getWindow().setAttributes(attrs);
|
getWindow().setAttributes(attrs);
|
||||||
|
|
||||||
mDismissReceiver = new DismissReceiver(this);
|
mDismissReceiver = dismissOnDeviceLock ? new DismissReceiver(this) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -111,13 +116,19 @@ public class SystemUIDialog extends AlertDialog implements ListenableDialog {
|
|||||||
@Override
|
@Override
|
||||||
protected void onStart() {
|
protected void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
mDismissReceiver.register();
|
|
||||||
|
if (mDismissReceiver != null) {
|
||||||
|
mDismissReceiver.register();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStop() {
|
protected void onStop() {
|
||||||
super.onStop();
|
super.onStop();
|
||||||
mDismissReceiver.unregister();
|
|
||||||
|
if (mDismissReceiver != null) {
|
||||||
|
mDismissReceiver.unregister();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -132,10 +143,14 @@ public class SystemUIDialog extends AlertDialog implements ListenableDialog {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dismiss() {
|
public void dismiss() {
|
||||||
|
dismiss(DismissReason.UNKNOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void dismiss(DismissReason reason) {
|
||||||
super.dismiss();
|
super.dismiss();
|
||||||
|
|
||||||
for (DialogListener listener : new LinkedHashSet<>(mDialogListeners)) {
|
for (DialogListener listener : new LinkedHashSet<>(mDialogListeners)) {
|
||||||
listener.onDismiss();
|
listener.onDismiss(reason);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,7 +266,11 @@ public class SystemUIDialog extends AlertDialog implements ListenableDialog {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
mDialog.dismiss();
|
if (mDialog instanceof SystemUIDialog) {
|
||||||
|
((SystemUIDialog) mDialog).dismiss(DismissReason.DEVICE_LOCKED);
|
||||||
|
} else {
|
||||||
|
mDialog.dismiss();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,12 +16,18 @@ class SystemUIHostDialogProvider : HostDialogProvider {
|
|||||||
return SystemUIHostDialog(context, theme, onCreateCallback, dismissOverride)
|
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(
|
private class SystemUIHostDialog(
|
||||||
context: Context,
|
context: Context,
|
||||||
theme: Int,
|
theme: Int,
|
||||||
private val onCreateCallback: () -> Unit,
|
private val onCreateCallback: () -> Unit,
|
||||||
private val dismissOverride: (() -> Unit) -> Unit
|
private val dismissOverride: (() -> Unit) -> Unit
|
||||||
) : SystemUIDialog(context, theme) {
|
) : SystemUIDialog(context, theme, false /* dismissOnDeviceLock */) {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
onCreateCallback()
|
onCreateCallback()
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import com.android.keyguard.KeyguardUpdateMonitor;
|
|||||||
import com.android.keyguard.ViewMediatorCallback;
|
import com.android.keyguard.ViewMediatorCallback;
|
||||||
import com.android.systemui.InitController;
|
import com.android.systemui.InitController;
|
||||||
import com.android.systemui.animation.ActivityLaunchAnimator;
|
import com.android.systemui.animation.ActivityLaunchAnimator;
|
||||||
import com.android.systemui.animation.DialogLaunchAnimator;
|
|
||||||
import com.android.systemui.assist.AssistManager;
|
import com.android.systemui.assist.AssistManager;
|
||||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||||
import com.android.systemui.classifier.FalsingCollector;
|
import com.android.systemui.classifier.FalsingCollector;
|
||||||
@@ -246,8 +245,7 @@ public interface StatusBarPhoneModule {
|
|||||||
Optional<StartingSurface> startingSurfaceOptional,
|
Optional<StartingSurface> startingSurfaceOptional,
|
||||||
TunerService tunerService,
|
TunerService tunerService,
|
||||||
DumpManager dumpManager,
|
DumpManager dumpManager,
|
||||||
ActivityLaunchAnimator activityLaunchAnimator,
|
ActivityLaunchAnimator activityLaunchAnimator) {
|
||||||
DialogLaunchAnimator dialogLaunchAnimator) {
|
|
||||||
return new StatusBar(
|
return new StatusBar(
|
||||||
context,
|
context,
|
||||||
notificationsController,
|
notificationsController,
|
||||||
@@ -349,7 +347,7 @@ public interface StatusBarPhoneModule {
|
|||||||
startingSurfaceOptional,
|
startingSurfaceOptional,
|
||||||
tunerService,
|
tunerService,
|
||||||
dumpManager,
|
dumpManager,
|
||||||
activityLaunchAnimator,
|
activityLaunchAnimator
|
||||||
dialogLaunchAnimator);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import android.view.WindowManager
|
|||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.animation.DialogListener.DismissReason
|
||||||
import junit.framework.Assert.assertEquals
|
import junit.framework.Assert.assertEquals
|
||||||
import junit.framework.Assert.assertFalse
|
import junit.framework.Assert.assertFalse
|
||||||
import junit.framework.Assert.assertTrue
|
import junit.framework.Assert.assertTrue
|
||||||
@@ -63,10 +64,6 @@ class DialogLaunchAnimatorTest : SysuiTestCase() {
|
|||||||
assertEquals(1, hostDialogRoot.childCount)
|
assertEquals(1, hostDialogRoot.childCount)
|
||||||
assertEquals(dialog.contentView, hostDialogRoot.getChildAt(0))
|
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
|
// Hiding/showing/dismissing the dialog should hide/show/dismiss the host dialog given that
|
||||||
// it's a ListenableDialog.
|
// it's a ListenableDialog.
|
||||||
runOnMainThreadAndWaitForIdleSync { dialog.hide() }
|
runOnMainThreadAndWaitForIdleSync { dialog.hide() }
|
||||||
@@ -164,7 +161,7 @@ class DialogLaunchAnimatorTest : SysuiTestCase() {
|
|||||||
|
|
||||||
override fun dismiss() {
|
override fun dismiss() {
|
||||||
super.dismiss()
|
super.dismiss()
|
||||||
notifyListeners { onDismiss() }
|
notifyListeners { onDismiss(DismissReason.UNKNOWN) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hide() {
|
override fun hide() {
|
||||||
|
|||||||
@@ -78,7 +78,6 @@ import com.android.systemui.InitController;
|
|||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
import com.android.systemui.SysuiTestCase;
|
import com.android.systemui.SysuiTestCase;
|
||||||
import com.android.systemui.animation.ActivityLaunchAnimator;
|
import com.android.systemui.animation.ActivityLaunchAnimator;
|
||||||
import com.android.systemui.animation.DialogLaunchAnimator;
|
|
||||||
import com.android.systemui.assist.AssistManager;
|
import com.android.systemui.assist.AssistManager;
|
||||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||||
import com.android.systemui.classifier.FalsingCollectorFake;
|
import com.android.systemui.classifier.FalsingCollectorFake;
|
||||||
@@ -282,7 +281,6 @@ public class StatusBarTest extends SysuiTestCase {
|
|||||||
@Mock private OperatorNameViewController.Factory mOperatorNameViewControllerFactory;
|
@Mock private OperatorNameViewController.Factory mOperatorNameViewControllerFactory;
|
||||||
@Mock private PhoneStatusBarViewController.Factory mPhoneStatusBarViewControllerFactory;
|
@Mock private PhoneStatusBarViewController.Factory mPhoneStatusBarViewControllerFactory;
|
||||||
@Mock private ActivityLaunchAnimator mActivityLaunchAnimator;
|
@Mock private ActivityLaunchAnimator mActivityLaunchAnimator;
|
||||||
@Mock private DialogLaunchAnimator mDialogLaunchAnimator;
|
|
||||||
private ShadeController mShadeController;
|
private ShadeController mShadeController;
|
||||||
private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
|
private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
|
||||||
private FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock);
|
private FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock);
|
||||||
@@ -464,8 +462,7 @@ public class StatusBarTest extends SysuiTestCase {
|
|||||||
Optional.of(mStartingSurface),
|
Optional.of(mStartingSurface),
|
||||||
mTunerService,
|
mTunerService,
|
||||||
mock(DumpManager.class),
|
mock(DumpManager.class),
|
||||||
mActivityLaunchAnimator,
|
mActivityLaunchAnimator);
|
||||||
mDialogLaunchAnimator);
|
|
||||||
when(mKeyguardViewMediator.registerStatusBar(
|
when(mKeyguardViewMediator.registerStatusBar(
|
||||||
any(StatusBar.class),
|
any(StatusBar.class),
|
||||||
any(NotificationPanelViewController.class),
|
any(NotificationPanelViewController.class),
|
||||||
|
|||||||
Reference in New Issue
Block a user