diff options
| author | 2021-11-04 13:04:31 +0000 | |
|---|---|---|
| committer | 2021-11-04 13:04:31 +0000 | |
| commit | 94204aa4745b8bb66c7813da126e34a31e2f75b6 (patch) | |
| tree | b6108207fe836693d8f15c494b8b5644a9afcc23 | |
| parent | c5a945385b62f7ad1861489cb99f85771a6b1edf (diff) | |
| parent | 2642eed1f194e71a59fbe9ae58357830ecb9b5ab (diff) | |
Merge changes from topic "dialog-aod" into sc-v2-dev
* changes:
Resize dialogs when the configuration changes
Disable dialog exit animation when locking (1/2)
8 files changed, 162 insertions, 57 deletions
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 3e30c3c9a0cf..65d0e497a5b1 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -879,6 +879,13 @@ public final class ViewRootImpl implements ViewParent, } } + /** Remove a static config callback. */ + public static void removeConfigCallback(ConfigChangedCallback callback) { + synchronized (sConfigCallbacks) { + sConfigCallbacks.remove(callback); + } + } + /** Add activity config callback to be notified about override config changes. */ public void setActivityConfigCallback(ActivityConfigCallback callback) { mActivityConfigCallback = callback; 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 669a054eaa2a..865f96be1775 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() } @@ -110,6 +116,10 @@ class DialogLaunchAnimator( launchAnimation.ignoreNextCallToHide = true dialog.hide() } + + override fun onSizeChanged() { + launchAnimation.onOriginalDialogSizeChanged() + } }) } @@ -117,13 +127,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. @@ -147,6 +150,7 @@ interface HostDialogProvider { * 2. call [dismissOverride] instead of doing any dismissing logic. The actual dismissing * logic should instead be done inside the lambda passed to [dismissOverride], which will * be called after the exit animation. + * 3. Be full screen, i.e. have a window matching its parent size. * * See SystemUIHostDialogProvider for an example of implementation. */ @@ -168,14 +172,25 @@ 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() /** Called when this dialog show() is called. */ fun onShow() + + /** Called when this dialog size might have changed, e.g. because of configuration changes. */ + fun onSizeChanged() } private class DialogLaunchAnimation( @@ -254,10 +269,6 @@ private class DialogLaunchAnimation( val window = hostDialog.window ?: throw IllegalStateException("There is no window associated to the host dialog") window.setBackgroundDrawableResource(android.R.color.transparent) - window.setLayout( - WindowManager.LayoutParams.MATCH_PARENT, - WindowManager.LayoutParams.MATCH_PARENT - ) // If we are using gesture navigation, then we can overlay the navigation/task bars with // the host dialog. @@ -425,6 +436,19 @@ private class DialogLaunchAnimation( }) } + fun onOriginalDialogSizeChanged() { + // The dialog is the single child of the root. + if (hostDialogRoot.childCount != 1) { + return + } + + val dialogView = hostDialogRoot.getChildAt(0) + val layoutParams = dialogView.layoutParams as? FrameLayout.LayoutParams ?: return + layoutParams.width = originalDialog.window.attributes.width + layoutParams.height = originalDialog.window.attributes.height + dialogView.layoutParams = layoutParams + } + private fun maybeStartLaunchAnimation() { if (!isTouchSurfaceGhostDrawn || !isOriginalDialogViewLaidOut) { return @@ -638,14 +662,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 491e5647c222..76790cfd4d68 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; @@ -680,7 +679,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; @@ -806,8 +804,7 @@ public class StatusBar extends SystemUI implements Optional<StartingSurface> startingSurfaceOptional, TunerService tunerService, DumpManager dumpManager, - ActivityLaunchAnimator activityLaunchAnimator, - DialogLaunchAnimator dialogLaunchAnimator) { + ActivityLaunchAnimator activityLaunchAnimator) { super(context); mNotificationsController = notificationsController; mLightBarController = lightBarController; @@ -919,7 +916,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()); @@ -4480,8 +4476,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 18aa6893e7bc..cf4aaba107cf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java @@ -22,11 +22,15 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.res.Configuration; import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; import android.os.SystemProperties; import android.os.UserHandle; import android.util.TypedValue; import android.view.ViewGroup; +import android.view.ViewRootImpl; import android.view.Window; import android.view.WindowInsets.Type; import android.view.WindowManager; @@ -35,6 +39,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; @@ -48,7 +53,8 @@ import java.util.Set; * The SystemUIDialog registers a listener for the screen off / close system dialogs broadcast, * and dismisses itself when it receives the broadcast. */ -public class SystemUIDialog extends AlertDialog implements ListenableDialog { +public class SystemUIDialog extends AlertDialog implements ListenableDialog, + ViewRootImpl.ConfigChangedCallback { // TODO(b/203389579): Remove this once the dialog width on large screens has been agreed on. private static final String FLAG_TABLET_DIALOG_WIDTH = "persist.systemui.flag_tablet_dialog_width"; @@ -56,12 +62,22 @@ public class SystemUIDialog extends AlertDialog implements ListenableDialog { private final Context mContext; private final DismissReceiver mDismissReceiver; private final Set<DialogListener> mDialogListeners = new LinkedHashSet<>(); + private final Handler mHandler = new Handler(); + + private int mLastWidth = Integer.MIN_VALUE; + private int mLastHeight = Integer.MIN_VALUE; + private int mLastConfigurationWidthDp = -1; + private int mLastConfigurationHeightDp = -1; public SystemUIDialog(Context context) { this(context, R.style.Theme_SystemUI_Dialog); } 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,18 +86,57 @@ 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 protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - // Set the dialog window size. - getWindow().setLayout(getDialogWidth(), ViewGroup.LayoutParams.WRAP_CONTENT); + Configuration config = getContext().getResources().getConfiguration(); + mLastConfigurationWidthDp = config.screenWidthDp; + mLastConfigurationHeightDp = config.screenHeightDp; + updateWindowSize(); + } + + private void updateWindowSize() { + // Only the thread that created this dialog can update its window size. + if (Looper.myLooper() != mHandler.getLooper()) { + mHandler.post(this::updateWindowSize); + return; + } + + int width = getWidth(); + int height = getHeight(); + if (width == mLastWidth && height == mLastHeight) { + return; + } + + mLastWidth = width; + mLastHeight = height; + getWindow().setLayout(width, height); + + for (DialogListener listener : new LinkedHashSet<>(mDialogListeners)) { + listener.onSizeChanged(); + } + } + + @Override + public void onConfigurationChanged(Configuration configuration) { + if (mLastConfigurationWidthDp != configuration.screenWidthDp + || mLastConfigurationHeightDp != configuration.screenHeightDp) { + mLastConfigurationWidthDp = configuration.screenWidthDp; + mLastConfigurationHeightDp = configuration.compatScreenWidthDp; + + updateWindowSize(); + } } - private int getDialogWidth() { + /** + * Return this dialog width. This method will be invoked when this dialog is created and when + * the device configuration changes, and the result will be used to resize this dialog window. + */ + protected int getWidth() { boolean isOnTablet = mContext.getResources().getConfiguration().smallestScreenWidthDp >= 600; if (!isOnTablet) { @@ -108,16 +163,36 @@ public class SystemUIDialog extends AlertDialog implements ListenableDialog { } } + /** + * Return this dialog height. This method will be invoked when this dialog is created and when + * the device configuration changes, and the result will be used to resize this dialog window. + */ + protected int getHeight() { + return ViewGroup.LayoutParams.WRAP_CONTENT; + } + @Override protected void onStart() { super.onStart(); - mDismissReceiver.register(); + + if (mDismissReceiver != null) { + mDismissReceiver.register(); + } + + // Listen for configuration changes to resize this dialog window. This is mostly necessary + // for foldables that often go from large <=> small screen when folding/unfolding. + ViewRootImpl.addConfigCallback(this); } @Override protected void onStop() { super.onStop(); - mDismissReceiver.unregister(); + + if (mDismissReceiver != null) { + mDismissReceiver.unregister(); + } + + ViewRootImpl.removeConfigCallback(this); } @Override @@ -132,10 +207,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 +330,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 6a49a6da0d62..4f18f8c597b2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIHostDialogProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIHostDialogProvider.kt @@ -3,6 +3,7 @@ package com.android.systemui.statusbar.phone import android.app.Dialog import android.content.Context import android.os.Bundle +import android.view.ViewGroup import com.android.systemui.animation.HostDialogProvider /** An implementation of [HostDialogProvider] to be used when animating SysUI dialogs. */ @@ -16,12 +17,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() @@ -32,5 +39,13 @@ class SystemUIHostDialogProvider : HostDialogProvider { super.dismiss() } } + + override fun getWidth(): Int { + return ViewGroup.LayoutParams.MATCH_PARENT + } + + override fun getHeight(): Int { + return ViewGroup.LayoutParams.MATCH_PARENT + } } }
\ No newline at end of file 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 adff2fd43425..4f4342606194 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; @@ -244,8 +243,7 @@ public interface StatusBarPhoneModule { Optional<StartingSurface> startingSurfaceOptional, TunerService tunerService, DumpManager dumpManager, - ActivityLaunchAnimator activityLaunchAnimator, - DialogLaunchAnimator dialogLaunchAnimator) { + ActivityLaunchAnimator activityLaunchAnimator) { return new StatusBar( context, notificationsController, @@ -346,7 +344,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 5bcf828afe9f..54278066b5d3 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 9fe142337bbe..9202cecf63db 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; @@ -281,7 +280,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); @@ -462,8 +460,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), |