summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jordan Demeulenaere <jdemeulenaere@google.com> 2021-12-01 13:14:47 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2021-12-01 13:14:47 +0000
commit9f02d2fd201831f0d24f7e0756dbe784a11027a7 (patch)
tree8b579d502bca45fc225bfb08bfa545c1889d0e1a
parentf5fe79dedc4742e60a6727fefb7280cfeb5d1238 (diff)
parent4538223f856fc1d5ee6d246c47110cf8487b9454 (diff)
Merge changes from topic "dialog-refactor" into sc-v2-dev
* changes: Animate the cast dialog Refactor DialogLaunchAnimator and remove host dialog (2/2) Refactor DialogLaunchAnimator and remove host dialog (1/2)
-rw-r--r--core/java/android/app/Dialog.java23
-rw-r--r--packages/SystemUI/animation/res/anim/launch_dialog_enter.xml (renamed from packages/SystemUI/animation/res/anim/launch_host_dialog_enter.xml)0
-rw-r--r--packages/SystemUI/animation/res/anim/launch_dialog_exit.xml (renamed from packages/SystemUI/animation/res/anim/launch_host_dialog_exit.xml)0
-rw-r--r--packages/SystemUI/animation/res/values/ids.xml1
-rw-r--r--packages/SystemUI/animation/res/values/styles.xml15
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt595
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java75
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIHostDialogProvider.kt51
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt218
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt19
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt5
19 files changed, 389 insertions, 714 deletions
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 9833ed60fe46..306035341ea3 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -151,6 +151,9 @@ public class Dialog implements DialogInterface, Window.Callback,
private final Runnable mDismissAction = this::dismissDialog;
+ /** A {@link Runnable} to run instead of dismissing when {@link #dismiss()} is called. */
+ private Runnable mDismissOverride;
+
/**
* Creates a dialog window that uses the default dialog theme.
* <p>
@@ -370,6 +373,11 @@ public class Dialog implements DialogInterface, Window.Callback,
*/
@Override
public void dismiss() {
+ if (mDismissOverride != null) {
+ mDismissOverride.run();
+ return;
+ }
+
if (Looper.myLooper() == mHandler.getLooper()) {
dismissDialog();
} else {
@@ -1354,6 +1362,21 @@ public class Dialog implements DialogInterface, Window.Callback,
mDismissMessage = msg;
}
+ /**
+ * Set a {@link Runnable} to run when this dialog is dismissed instead of directly dismissing
+ * it. This allows to animate the dialog in its window before dismissing it.
+ *
+ * Note that {@code override} should always end up calling this method with {@code null}
+ * followed by a call to {@link #dismiss() dismiss} to actually dismiss the dialog.
+ *
+ * @see #dismiss()
+ *
+ * @hide
+ */
+ public void setDismissOverride(@Nullable Runnable override) {
+ mDismissOverride = override;
+ }
+
/** @hide */
public boolean takeCancelAndDismissListeners(@Nullable String msg,
@Nullable OnCancelListener cancel, @Nullable OnDismissListener dismiss) {
diff --git a/packages/SystemUI/animation/res/anim/launch_host_dialog_enter.xml b/packages/SystemUI/animation/res/anim/launch_dialog_enter.xml
index c6b87d38f7da..c6b87d38f7da 100644
--- a/packages/SystemUI/animation/res/anim/launch_host_dialog_enter.xml
+++ b/packages/SystemUI/animation/res/anim/launch_dialog_enter.xml
diff --git a/packages/SystemUI/animation/res/anim/launch_host_dialog_exit.xml b/packages/SystemUI/animation/res/anim/launch_dialog_exit.xml
index a0f441eaeed4..a0f441eaeed4 100644
--- a/packages/SystemUI/animation/res/anim/launch_host_dialog_exit.xml
+++ b/packages/SystemUI/animation/res/anim/launch_dialog_exit.xml
diff --git a/packages/SystemUI/animation/res/values/ids.xml b/packages/SystemUI/animation/res/values/ids.xml
index c4cb89fecccb..ef60a248f79a 100644
--- a/packages/SystemUI/animation/res/values/ids.xml
+++ b/packages/SystemUI/animation/res/values/ids.xml
@@ -16,5 +16,4 @@
-->
<resources>
<item type="id" name="launch_animation_running"/>
- <item type="id" name="dialog_content_parent" />
</resources> \ No newline at end of file
diff --git a/packages/SystemUI/animation/res/values/styles.xml b/packages/SystemUI/animation/res/values/styles.xml
index ad06c9192bc3..3b3f7f6128fa 100644
--- a/packages/SystemUI/animation/res/values/styles.xml
+++ b/packages/SystemUI/animation/res/values/styles.xml
@@ -15,15 +15,10 @@
limitations under the License.
-->
<resources>
- <style name="HostDialogTheme">
- <item name="android:windowAnimationStyle">@style/Animation.HostDialog</item>
- <item name="android:windowIsFloating">false</item>
- <item name="android:backgroundDimEnabled">true</item>
- <item name="android:navigationBarColor">@android:color/transparent</item>
- </style>
-
- <style name="Animation.HostDialog" parent="@android:style/Animation">
- <item name="android:windowEnterAnimation">@anim/launch_host_dialog_enter</item>
- <item name="android:windowExitAnimation">@anim/launch_host_dialog_exit</item>
+ <!-- An animation used by DialogLaunchAnimator to make a dialog appear instantly (to animate -->
+ <!-- in-window) and disappear by fading out (when the exit into view is disabled). -->
+ <style name="Animation.LaunchAnimation" parent="@android:style/Animation">
+ <item name="android:windowEnterAnimation">@anim/launch_dialog_enter</item>
+ <item name="android:windowExitAnimation">@anim/launch_dialog_exit</item>
</style>
</resources> \ No newline at end of file
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 e5726b08aff4..de82ebdc6b1c 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
@@ -24,22 +24,19 @@ import android.content.Context
import android.graphics.Color
import android.graphics.Rect
import android.os.Looper
+import android.service.dreams.IDreamManager
import android.util.Log
import android.util.MathUtils
import android.view.GhostView
import android.view.View
import android.view.ViewGroup
+import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.ViewTreeObserver.OnPreDrawListener
-import android.view.WindowInsets
import android.view.WindowManager
-import android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
-import android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-import android.view.WindowManagerPolicyConstants
import android.widget.FrameLayout
import kotlin.math.roundToInt
private const val TAG = "DialogLaunchAnimator"
-private val DIALOG_CONTENT_PARENT_ID = R.id.dialog_content_parent
/**
* A class that allows dialogs to be started in a seamless way from a view that is transforming
@@ -48,7 +45,7 @@ private val DIALOG_CONTENT_PARENT_ID = R.id.dialog_content_parent
class DialogLaunchAnimator(
private val context: Context,
private val launchAnimator: LaunchAnimator,
- private val hostDialogProvider: HostDialogProvider
+ private val dreamManager: IDreamManager
) {
private companion object {
private val TAG_LAUNCH_ANIMATION_RUNNING = R.id.launch_animation_running
@@ -62,41 +59,38 @@ class DialogLaunchAnimator(
private val openedDialogs = hashSetOf<AnimatedDialog>()
/**
- * Show [dialog] by expanding it from [view]. If [animateBackgroundBoundsChange] is true, then
- * the background of the dialog will be animated when the dialog bounds change.
+ * Show [dialog] by expanding it from [view]. If [view] is a view inside another dialog that was
+ * shown using this method, then we will animate from that dialog instead.
*
- * Caveats: When calling this function, the dialog content view will actually be stolen and
- * attached to a different dialog (and thus a different window) which means that the actual
- * dialog window will never be drawn. Moreover, unless [dialog] is a [ListenableDialog], you
- * must call dismiss(), hide() and show() on the [Dialog] returned by this function to actually
- * dismiss, hide or show the dialog.
+ * If [animateBackgroundBoundsChange] is true, then the background of the dialog will be
+ * animated when the dialog bounds change.
+ *
+ * Caveats: When calling this function and [dialog] is not a fullscreen dialog, then it will be
+ * made fullscreen and 2 views will be inserted between the dialog DecorView and its children.
*/
@JvmOverloads
fun showFromView(
dialog: Dialog,
view: View,
animateBackgroundBoundsChange: Boolean = false
- ): Dialog {
+ ) {
if (Looper.myLooper() != Looper.getMainLooper()) {
throw IllegalStateException(
"showFromView must be called from the main thread and dialog must be created in " +
"the main thread")
}
- // If the parent of the view we are launching from is the background of some other animated
- // dialog, then this means the caller intent is to launch a dialog from another dialog. In
- // this case, we also animate the parent (which is the dialog background).
- val animatedParent = openedDialogs.firstOrNull {
- it.dialogContentWithBackground == view || it.dialogContentWithBackground == view.parent
- }
- val dialogContentWithBackground = animatedParent?.dialogContentWithBackground
- val animateFrom = dialogContentWithBackground ?: view
+ // If the view we are launching from belongs to another dialog, then this means the caller
+ // intent is to launch a dialog from another dialog.
+ val animatedParent = openedDialogs
+ .firstOrNull { it.dialog.window.decorView.viewRootImpl == view.viewRootImpl }
+ val animateFrom = animatedParent?.dialogContentWithBackground ?: view
// Make sure we don't run the launch animation from the same view twice at the same time.
if (animateFrom.getTag(TAG_LAUNCH_ANIMATION_RUNNING) != null) {
Log.e(TAG, "Not running dialog launch animation as there is already one running")
dialog.show()
- return dialog
+ return
}
animateFrom.setTag(TAG_LAUNCH_ANIMATION_RUNNING, true)
@@ -104,82 +98,36 @@ class DialogLaunchAnimator(
val animatedDialog = AnimatedDialog(
context,
launchAnimator,
- hostDialogProvider,
+ dreamManager,
animateFrom,
onDialogDismissed = { openedDialogs.remove(it) },
- originalDialog = dialog,
+ dialog = dialog,
animateBackgroundBoundsChange,
animatedParent
)
- val hostDialog = animatedDialog.hostDialog
- openedDialogs.add(animatedDialog)
-
- // If the dialog is dismissed/hidden/shown, then we should actually dismiss/hide/show the
- // host dialog.
- if (dialog is ListenableDialog) {
- dialog.addListener(object : DialogListener {
- 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) {
- animatedDialog.exitAnimationDisabled = true
- }
-
- hostDialog.dismiss()
- }
-
- override fun onHide() {
- if (animatedDialog.ignoreNextCallToHide) {
- animatedDialog.ignoreNextCallToHide = false
- return
- }
-
- hostDialog.hide()
- }
-
- override fun onShow() {
- hostDialog.show()
-
- // We don't actually want to show the original dialog, so hide it.
- animatedDialog.ignoreNextCallToHide = true
- dialog.hide()
- }
-
- override fun onSizeChanged() {
- animatedDialog.onOriginalDialogSizeChanged()
- }
-
- override fun prepareForStackDismiss() {
- animatedDialog.touchSurface = animatedDialog.prepareForStackDismiss()
- }
- })
- }
+ openedDialogs.add(animatedDialog)
animatedDialog.start()
- return hostDialog
}
/**
- * Launch [dialog] from a [parentHostDialog] as returned by [showFromView]. This will allow
- * for dismissing the whole stack.
- *
- * This will return a new host dialog, with the same caveat as [showFromView].
+ * Launch [dialog] from [another dialog][animateFrom] that was shown using [showFromView]. This
+ * will allow for dismissing the whole stack.
*
- * @see DialogListener.prepareForStackDismiss
+ * @see dismissStack
*/
fun showFromDialog(
dialog: Dialog,
- parentHostDialog: Dialog,
+ animateFrom: Dialog,
animateBackgroundBoundsChange: Boolean = false
- ): Dialog {
- val view = parentHostDialog.findViewById<ViewGroup>(DIALOG_CONTENT_PARENT_ID)
- ?.getChildAt(0)
- ?: throw IllegalStateException("No dialog content parent found in host dialog")
- return showFromView(dialog, view, animateBackgroundBoundsChange)
+ ) {
+ val view = openedDialogs
+ .firstOrNull { it.dialog == animateFrom }
+ ?.dialogContentWithBackground
+ ?: throw IllegalStateException(
+ "The animateFrom dialog was not animated using " +
+ "DialogLaunchAnimator.showFrom(View|Dialog)")
+ showFromView(dialog, view, animateBackgroundBoundsChange)
}
/**
@@ -195,69 +143,23 @@ class DialogLaunchAnimator(
fun disableAllCurrentDialogsExitAnimations() {
openedDialogs.forEach { it.exitAnimationDisabled = true }
}
-}
-interface HostDialogProvider {
/**
- * Create a host dialog that will be used to host a launch animation. This host dialog must:
- * 1. call [onCreateCallback] in its onCreate() method, e.g. right after calling
- * super.onCreate().
- * 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.
+ * Dismiss [dialog]. If it was launched from another dialog using [showFromView], also dismiss
+ * the stack of dialogs, animating back to the original touchSurface.
*/
- fun createHostDialog(
- context: Context,
- theme: Int,
- onCreateCallback: () -> Unit,
- dismissOverride: (() -> Unit) -> Unit
- ): Dialog
-}
-
-/** A dialog to/from which we can add/remove listeners. */
-interface ListenableDialog {
- /** Add [listener] to the listeners. */
- fun addListener(listener: DialogListener)
-
- /** Remove [listener] from the listeners. */
- fun removeListener(listener: DialogListener)
-}
-
-interface DialogListener {
- /** The reason why a dialog was dismissed. */
- enum class DismissReason {
- UNKNOWN,
-
- /** The device was locked, which dismissed this dialog. */
- DEVICE_LOCKED,
+ fun dismissStack(dialog: Dialog) {
+ openedDialogs
+ .firstOrNull { it.dialog == dialog }
+ ?.let { it.touchSurface = it.prepareForStackDismiss() }
+ dialog.dismiss()
}
-
- /** Called when this dialog dismiss() is called. */
- fun onDismiss(reason: DismissReason)
-
- /** Called when this dialog hide() is called. */
- fun onHide()
-
- /** Called when this dialog show() is called. */
- fun onShow()
-
- /**
- * Call before dismissing a stack of dialogs (dialogs launched from dialogs), so the topmost
- * can animate directly into the original `touchSurface`.
- */
- fun prepareForStackDismiss()
-
- /** Called when this dialog size might have changed, e.g. because of configuration changes. */
- fun onSizeChanged()
}
private class AnimatedDialog(
private val context: Context,
private val launchAnimator: LaunchAnimator,
- hostDialogProvider: HostDialogProvider,
+ private val dreamManager: IDreamManager,
/** The view that triggered the dialog after being tapped. */
var touchSurface: View,
@@ -268,36 +170,33 @@ private class AnimatedDialog(
*/
private val onDialogDismissed: (AnimatedDialog) -> Unit,
- /** The original dialog whose content will be shown and animate in/out in [hostDialog]. */
- private val originalDialog: Dialog,
+ /** The dialog to show and animate. */
+ val dialog: Dialog,
/** Whether we should animate the dialog background when its bounds change. */
private val animateBackgroundBoundsChange: Boolean,
- /** Launch animation corresponding to the parent [hostDialog]. */
+ /** Launch animation corresponding to the parent [AnimatedDialog]. */
private val parentAnimatedDialog: AnimatedDialog? = null
) {
/**
- * The fullscreen dialog to which we will add the content view [originalDialogView] of
- * [originalDialog].
- */
- val hostDialog = hostDialogProvider.createHostDialog(
- context, R.style.HostDialogTheme, this::onHostDialogCreated, this::onHostDialogDismissed)
-
- /** The root content view of [hostDialog]. */
- private val hostDialogRoot = FrameLayout(context)
+ * The DecorView of this dialog window.
+ *
+ * Note that we access this DecorView lazily to avoid accessing it before the dialog is created,
+ * which can sometimes cause crashes (e.g. with the Cast dialog).
+ */
+ private val decorView by lazy { dialog.window!!.decorView as ViewGroup }
/**
* The dialog content with its background. When animating a fullscreen dialog, this is just the
* first ViewGroup of the dialog that has a background. When animating a normal (not fullscreen)
* dialog, this is an additional view that serves as a fake window that will have the same size
- * as the original dialog window and to which we will set the original dialog window background.
+ * as the dialog window initially had and to which we will set the dialog window background.
*/
var dialogContentWithBackground: ViewGroup? = null
/**
- * The background color of [originalDialogView], taking into consideration the [originalDialog]
- * window background color.
+ * The background color of [dialog], taking into consideration its window background color.
*/
private var originalDialogBackgroundColor = Color.BLACK
@@ -310,75 +209,182 @@ private class AnimatedDialog(
private var isDismissing = false
private var dismissRequested = false
- var ignoreNextCallToHide = false
var exitAnimationDisabled = false
private var isTouchSurfaceGhostDrawn = false
private var isOriginalDialogViewLaidOut = false
- private var backgroundLayoutListener = if (animateBackgroundBoundsChange) {
+
+ /** A layout listener to animate the dialog height change. */
+ private val backgroundLayoutListener = if (animateBackgroundBoundsChange) {
AnimatedBoundsLayoutListener()
} else {
null
}
+ /*
+ * A layout listener in case the dialog (window) size changes (for instance because of a
+ * configuration change) to ensure that the dialog stays full width.
+ */
+ private var decorViewLayoutListener: View.OnLayoutChangeListener? = null
+
fun start() {
- // Show the host (fullscreen) dialog, to which we will add the stolen dialog view.
- hostDialog.show()
+ // Create the dialog so that its onCreate() method is called, which usually sets the dialog
+ // content.
+ dialog.create()
+
+ val window = dialog.window!!
+ val isWindowFullScreen =
+ window.attributes.width == MATCH_PARENT && window.attributes.height == MATCH_PARENT
+ val dialogContentWithBackground = if (isWindowFullScreen) {
+ // If the dialog window is already fullscreen, then we look for the first ViewGroup that
+ // has a background (and is not the DecorView, which always has a background) and
+ // animate towards that ViewGroup given that this is probably what represents the actual
+ // dialog view.
+ var viewGroupWithBackground: ViewGroup? = null
+ for (i in 0 until decorView.childCount) {
+ viewGroupWithBackground = findFirstViewGroupWithBackground(decorView.getChildAt(i))
+ if (viewGroupWithBackground != null) {
+ break
+ }
+ }
- // Steal the dialog view. We do that by showing it but preventing it from drawing, then
- // hiding it as soon as its content is available.
- stealOriginalDialogContentView(then = this::showDialogFromView)
- }
+ // Animate that view with the background. Throw if we didn't find one, because otherwise
+ // it's not clear what we should animate.
+ viewGroupWithBackground
+ ?: throw IllegalStateException("Unable to find ViewGroup with background")
+ } else {
+ // We will make the dialog window (and therefore its DecorView) fullscreen to make it
+ // possible to animate outside its bounds.
+ //
+ // Before that, we add a new View as a child of the DecorView with the same size and
+ // gravity as that DecorView, then we add all original children of the DecorView to that
+ // new View. Finally we remove the background of the DecorView and add it to the new
+ // View, then we make the DecorView fullscreen. This new View now acts as a fake (non
+ // fullscreen) window.
+ //
+ // On top of that, we also add a fullscreen transparent background between the DecorView
+ // and the view that we added so that we can dismiss the dialog when this view is
+ // clicked. This is necessary because DecorView overrides onTouchEvent and therefore we
+ // can't set the click listener directly on the (now fullscreen) DecorView.
+ val fullscreenTransparentBackground = FrameLayout(context)
+ decorView.addView(
+ fullscreenTransparentBackground,
+ 0 /* index */,
+ FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
+ )
+
+ val dialogContentWithBackground = FrameLayout(context)
+ dialogContentWithBackground.background = decorView.background
+
+ // Make the window background transparent. Note that setting the window (or DecorView)
+ // background drawable to null leads to issues with background color (not being
+ // transparent) or with insets that are not refreshed. Therefore we need to set it to
+ // something not null, hence we are using android.R.color.transparent here.
+ window.setBackgroundDrawableResource(android.R.color.transparent)
+
+ // Close the dialog when clicking outside of it.
+ fullscreenTransparentBackground.setOnClickListener { dialog.dismiss() }
+ dialogContentWithBackground.isClickable = true
- private fun onHostDialogCreated() {
- // Make the dialog fullscreen with a transparent background.
- hostDialog.setContentView(
- hostDialogRoot,
- ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT
+ fullscreenTransparentBackground.addView(
+ dialogContentWithBackground,
+ FrameLayout.LayoutParams(
+ window.attributes.width,
+ window.attributes.height,
+ window.attributes.gravity
+ )
)
- )
- val window = hostDialog.window
- ?: throw IllegalStateException("There is no window associated to the host dialog")
- window.setBackgroundDrawableResource(android.R.color.transparent)
-
- // If we are using gesture navigation, then we can overlay the navigation/task bars with
- // the host dialog.
- val navigationMode = context.resources.getInteger(
- com.android.internal.R.integer.config_navBarInteractionMode)
- if (navigationMode == WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL) {
- window.attributes.fitInsetsTypes = window.attributes.fitInsetsTypes and
- WindowInsets.Type.navigationBars().inv()
- window.addFlags(FLAG_LAYOUT_IN_SCREEN or FLAG_LAYOUT_INSET_DECOR)
- window.setDecorFitsSystemWindows(false)
+ // Move all original children of the DecorView to the new View we just added.
+ for (i in 1 until decorView.childCount) {
+ val view = decorView.getChildAt(1)
+ decorView.removeViewAt(1)
+ dialogContentWithBackground.addView(view)
+ }
+
+ // Make the window fullscreen and add a layout listener to ensure it stays fullscreen.
+ window.setLayout(MATCH_PARENT, MATCH_PARENT)
+ decorViewLayoutListener = View.OnLayoutChangeListener {
+ v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom ->
+ if (window.attributes.width != MATCH_PARENT ||
+ window.attributes.height != MATCH_PARENT) {
+ // The dialog size changed, copy its size to dialogContentWithBackground and
+ // make the dialog window full screen again.
+ val layoutParams = dialogContentWithBackground.layoutParams
+ layoutParams.width = window.attributes.width
+ layoutParams.height = window.attributes.height
+ dialogContentWithBackground.layoutParams = layoutParams
+ window.setLayout(MATCH_PARENT, MATCH_PARENT)
+ }
+ }
+ decorView.addOnLayoutChangeListener(decorViewLayoutListener)
+
+ dialogContentWithBackground
}
+ this.dialogContentWithBackground = dialogContentWithBackground
+
+ val background = dialogContentWithBackground.background
+ originalDialogBackgroundColor =
+ GhostedViewLaunchAnimatorController.findGradientDrawable(background)
+ ?.color
+ ?.defaultColor ?: Color.BLACK
+
+ // Make the background view invisible until we start the animation.
+ dialogContentWithBackground.visibility = View.INVISIBLE
+
+ // Make sure the dialog is visible instantly and does not do any window animation.
+ window.attributes.windowAnimations = R.style.Animation_LaunchAnimation
+
+ // Start the animation once the background view is properly laid out.
+ dialogContentWithBackground.addOnLayoutChangeListener(object : View.OnLayoutChangeListener {
+ override fun onLayoutChange(
+ v: View,
+ left: Int,
+ top: Int,
+ right: Int,
+ bottom: Int,
+ oldLeft: Int,
+ oldTop: Int,
+ oldRight: Int,
+ oldBottom: Int
+ ) {
+ dialogContentWithBackground.removeOnLayoutChangeListener(this)
+
+ isOriginalDialogViewLaidOut = true
+ maybeStartLaunchAnimation()
+ }
+ })
// Disable the dim. We will enable it once we start the animation.
window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
+ // Override the dialog dismiss() so that we can animate the exit before actually dismissing
+ // the dialog.
+ dialog.setDismissOverride(this::onDialogDismissed)
+
+ // Show the dialog.
+ dialog.show()
+
// Add a temporary touch surface ghost as soon as the window is ready to draw. This
- // temporary ghost will be drawn together with the touch surface, but in the host dialog
+ // temporary ghost will be drawn together with the touch surface, but in the dialog
// window. Once it is drawn, we will make the touch surface invisible, and then start the
// animation. We do all this synchronization to avoid flicker that would occur if we made
// the touch surface invisible too early (before its ghost is drawn), leading to one or more
// frames with a hole instead of the touch surface (or its ghost).
- hostDialogRoot.viewTreeObserver.addOnPreDrawListener(object : OnPreDrawListener {
+ decorView.viewTreeObserver.addOnPreDrawListener(object : OnPreDrawListener {
override fun onPreDraw(): Boolean {
- hostDialogRoot.viewTreeObserver.removeOnPreDrawListener(this)
+ decorView.viewTreeObserver.removeOnPreDrawListener(this)
addTemporaryTouchSurfaceGhost()
return true
}
})
- hostDialogRoot.invalidate()
+ decorView.invalidate()
}
private fun addTemporaryTouchSurfaceGhost() {
// Create a ghost of the touch surface (which will make the touch surface invisible) and add
- // it to the host dialog. We will wait for this ghost to be drawn before starting the
- // animation.
- val ghost = GhostView.addGhost(touchSurface, hostDialogRoot)
+ // it to the dialog. We will wait for this ghost to be drawn before starting the animation.
+ val ghost = GhostView.addGhost(touchSurface, decorView)
// The ghost of the touch surface was just created, so the touch surface was made invisible.
// We make it visible again until the ghost is actually drawn.
@@ -414,142 +420,6 @@ private class AnimatedDialog(
touchSurface.invalidate()
}
- /** Get the content view of [originalDialog] and pass it to [then]. */
- private fun stealOriginalDialogContentView(then: (View) -> Unit) {
- // The original dialog content view will be attached to android.R.id.content when the dialog
- // is shown, so we show the dialog and add an observer to get the view but also prevents the
- // original dialog from being drawn.
- val androidContent = originalDialog.findViewById<ViewGroup>(android.R.id.content)
- ?: throw IllegalStateException("Dialog does not have any android.R.id.content view")
-
- androidContent.viewTreeObserver.addOnPreDrawListener(
- object : OnPreDrawListener {
- override fun onPreDraw(): Boolean {
- if (androidContent.childCount == 1) {
- androidContent.viewTreeObserver.removeOnPreDrawListener(this)
-
- // Hide the animated dialog. Because of the dialog listener set up
- // earlier, this would also hide the host dialog, but in this case we
- // need to keep the host dialog visible.
- ignoreNextCallToHide = true
- originalDialog.hide()
-
- then(androidContent.getChildAt(0))
- return false
- }
-
- // Never draw the original dialog content.
- return false
- }
- })
- originalDialog.show()
- }
-
- private fun showDialogFromView(dialogView: View) {
- // Close the dialog when clicking outside of it.
- hostDialogRoot.setOnClickListener { hostDialog.dismiss() }
- dialogView.isClickable = true
-
- // Remove the original dialog view from its parent.
- (dialogView.parent as? ViewGroup)?.removeView(dialogView)
-
- val originalDialogWindow = originalDialog.window!!
- val isOriginalWindowFullScreen =
- originalDialogWindow.attributes.width == ViewGroup.LayoutParams.MATCH_PARENT &&
- originalDialogWindow.attributes.height == ViewGroup.LayoutParams.MATCH_PARENT
- if (isOriginalWindowFullScreen) {
- // If the original dialog window is fullscreen, then we look for the first ViewGroup
- // that has a background and animate towards that ViewGroup given that this is probably
- // what represents the actual dialog view.
- dialogContentWithBackground = findFirstViewGroupWithBackground(dialogView)
- ?: throw IllegalStateException("Unable to find ViewGroup with background")
-
- hostDialogRoot.addView(
- dialogView,
-
- FrameLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT
- )
- )
- } else {
- // Add a parent view to the original dialog view to which we will set the original
- // dialog window background. This View serves as a fake window with background, so that
- // we are sure that we don't override the original dialog content view paddings with the
- // window background that usually has insets.
- dialogContentWithBackground = FrameLayout(context).apply {
- id = DIALOG_CONTENT_PARENT_ID
-
- // TODO(b/193634619): Support dialog windows without background.
- background = originalDialogWindow.decorView?.background
- ?: throw IllegalStateException(
- "Dialogs with no backgrounds on window are not supported")
-
- addView(
- dialogView,
-
- // It should match its parent size, which is sized the same as the original
- // dialog window.
- FrameLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT
- )
- )
- }
-
- // Add the parent (that has the background) to the host window.
- hostDialogRoot.addView(
- dialogContentWithBackground,
-
- // We give it the size and gravity of its original dialog window.
- FrameLayout.LayoutParams(
- originalDialogWindow.attributes.width,
- originalDialogWindow.attributes.height,
- originalDialogWindow.attributes.gravity
- )
- )
- }
-
- val dialogContentWithBackground = this.dialogContentWithBackground!!
-
- // Make the dialog and its background invisible for now, to make sure it's not drawn yet.
- dialogContentWithBackground.visibility = View.INVISIBLE
-
- val background = dialogContentWithBackground.background!!
- originalDialogBackgroundColor =
- GhostedViewLaunchAnimatorController.findGradientDrawable(background)
- ?.color
- ?.defaultColor ?: Color.BLACK
-
- if (isOriginalWindowFullScreen) {
- // If the original window is full screen, the ViewGroup with background might already be
- // correctly laid out. Make sure we relayout and that the layout listener below is still
- // called.
- dialogContentWithBackground.layout(0, 0, 0, 0)
- dialogContentWithBackground.requestLayout()
- }
-
- // Start the animation when the dialog is laid out in the center of the host dialog.
- dialogContentWithBackground.addOnLayoutChangeListener(object : View.OnLayoutChangeListener {
- override fun onLayoutChange(
- view: View,
- left: Int,
- top: Int,
- right: Int,
- bottom: Int,
- oldLeft: Int,
- oldTop: Int,
- oldRight: Int,
- oldBottom: Int
- ) {
- dialogContentWithBackground.removeOnLayoutChangeListener(this)
-
- isOriginalDialogViewLaidOut = true
- maybeStartLaunchAnimation()
- }
- })
- }
-
private fun findFirstViewGroupWithBackground(view: View): ViewGroup? {
if (view !is ViewGroup) {
return null
@@ -569,26 +439,13 @@ private class AnimatedDialog(
return null
}
- 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
}
// Show the background dim.
- hostDialog.window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
+ dialog.window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
startAnimation(
isLaunching = true,
@@ -610,7 +467,7 @@ private class AnimatedDialog(
// dismiss was called during the animation, dismiss again now to actually
// dismiss.
if (dismissRequested) {
- hostDialog.dismiss()
+ dialog.dismiss()
}
// If necessary, we animate the dialog background when its bounds change. We do it
@@ -624,9 +481,9 @@ private class AnimatedDialog(
)
}
- private fun onHostDialogDismissed(actualDismiss: () -> Unit) {
+ private fun onDialogDismissed() {
if (Looper.myLooper() != Looper.getMainLooper()) {
- context.mainExecutor.execute { onHostDialogDismissed(actualDismiss) }
+ context.mainExecutor.execute { onDialogDismissed() }
return
}
@@ -641,23 +498,29 @@ private class AnimatedDialog(
}
isDismissing = true
- hideDialogIntoView { instantDismiss: Boolean ->
- if (instantDismiss) {
- originalDialog.hide()
- hostDialog.hide()
+ hideDialogIntoView { animationRan: Boolean ->
+ if (animationRan) {
+ // Instantly dismiss the dialog if we ran the animation into view. If it was
+ // skipped, dismiss() will run the window animation (which fades out the dialog).
+ dialog.hide()
}
- originalDialog.dismiss()
- actualDismiss()
+ dialog.setDismissOverride(null)
+ dialog.dismiss()
}
}
/**
- * Hide the dialog into the touch surface and call [dismissDialogs] when the animation is done
- * (passing instantDismiss=true) or if it's skipped (passing instantDismiss=false) to actually
- * dismiss the dialogs.
+ * Hide the dialog into the touch surface and call [onAnimationFinished] when the animation is
+ * done (passing animationRan=true) or if it's skipped (passing animationRan=false) to actually
+ * dismiss the dialog.
*/
- private fun hideDialogIntoView(dismissDialogs: (Boolean) -> Unit) {
+ private fun hideDialogIntoView(onAnimationFinished: (Boolean) -> Unit) {
+ // Remove the layout change listener we have added to the DecorView earlier.
+ if (decorViewLayoutListener != null) {
+ decorView.removeOnLayoutChangeListener(decorViewLayoutListener)
+ }
+
if (!shouldAnimateDialogIntoView()) {
Log.i(TAG, "Skipping animation of dialog into the touch surface")
@@ -669,7 +532,7 @@ private class AnimatedDialog(
touchSurface.visibility = View.VISIBLE
}
- dismissDialogs(false /* instantDismiss */)
+ onAnimationFinished(false /* instantDismiss */)
onDialogDismissed(this@AnimatedDialog)
return
}
@@ -678,7 +541,7 @@ private class AnimatedDialog(
isLaunching = false,
onLaunchAnimationStart = {
// Remove the dim background as soon as we start the animation.
- hostDialog.window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
+ dialog.window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
},
onLaunchAnimationEnd = {
// Make sure we allow the touch surface to change its visibility again.
@@ -696,7 +559,7 @@ private class AnimatedDialog(
// The animated ghost was just removed. We create a temporary ghost that will be
// removed only once we draw the touch surface, to avoid flickering that would
// happen when removing the ghost too early (before the touch surface is drawn).
- GhostView.addGhost(touchSurface, hostDialogRoot)
+ GhostView.addGhost(touchSurface, decorView)
touchSurface.viewTreeObserver.addOnPreDrawListener(object : OnPreDrawListener {
override fun onPreDraw(): Boolean {
@@ -705,7 +568,7 @@ private class AnimatedDialog(
// Now that the touch surface was drawn, we can remove the temporary ghost
// and instantly dismiss the dialog.
GhostView.removeGhost(touchSurface)
- dismissDialogs(true /* instantDismiss */)
+ onAnimationFinished(true /* instantDismiss */)
onDialogDismissed(this@AnimatedDialog)
return true
@@ -721,14 +584,14 @@ private class AnimatedDialog(
onLaunchAnimationStart: () -> Unit = {},
onLaunchAnimationEnd: () -> Unit = {}
) {
- // Create 2 ghost controllers to animate both the dialog and the touch surface in the host
+ // Create 2 ghost controllers to animate both the dialog and the touch surface in the
// dialog.
val startView = if (isLaunching) touchSurface else dialogContentWithBackground!!
val endView = if (isLaunching) dialogContentWithBackground!! else touchSurface
val startViewController = GhostedViewLaunchAnimatorController(startView)
val endViewController = GhostedViewLaunchAnimatorController(endView)
- startViewController.launchContainer = hostDialogRoot
- endViewController.launchContainer = hostDialogRoot
+ startViewController.launchContainer = decorView
+ endViewController.launchContainer = decorView
val endState = endViewController.createAnimatorState()
val controller = object : LaunchAnimator.Controller {
@@ -785,9 +648,15 @@ private class AnimatedDialog(
}
private fun shouldAnimateDialogIntoView(): Boolean {
- // Don't animate if the dialog was previously hidden using hide() (either on the host dialog
- // or on the original dialog) or if we disabled the exit animation.
- if (exitAnimationDisabled || !hostDialog.isShowing) {
+ // Don't animate if the dialog was previously hidden using hide() or if we disabled the exit
+ // animation.
+ if (exitAnimationDisabled || !dialog.isShowing) {
+ return false
+ }
+
+ // If we are dreaming, the dialog was probably closed because of that so we don't animate
+ // into the touchSurface.
+ if (dreamManager.isDreaming) {
return false
}
@@ -888,9 +757,9 @@ private class AnimatedDialog(
return touchSurface
}
parentAnimatedDialog.exitAnimationDisabled = true
- parentAnimatedDialog.originalDialog.hide()
+ parentAnimatedDialog.dialog.hide()
val view = parentAnimatedDialog.prepareForStackDismiss()
- parentAnimatedDialog.originalDialog.dismiss()
+ parentAnimatedDialog.dialog.dismiss()
// Make the touch surface invisible, so we end up animating to it when we actually
// dismiss the stack
view.visibility = View.INVISIBLE
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index 26ce645eefc5..03a097746ba9 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -217,14 +217,6 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
dismiss();
}
- @Override
- public void onWindowFocusChanged(boolean hasFocus) {
- super.onWindowFocusChanged(hasFocus);
- if (!hasFocus && isShowing()) {
- dismiss();
- }
- }
-
void onHeaderIconClick() {
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 0427e38aa811..b83dc52240b3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -31,7 +31,6 @@ import android.util.Log;
import android.view.View;
import android.view.View.OnAttachStateChangeListener;
import android.view.ViewGroup;
-import android.view.WindowManager.LayoutParams;
import android.widget.Button;
import androidx.annotation.Nullable;
@@ -40,6 +39,7 @@ import com.android.internal.app.MediaRouteDialogPresenter;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.R;
+import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
@@ -76,6 +76,7 @@ public class CastTile extends QSTileImpl<BooleanState> {
private final CastDetailAdapter mDetailAdapter;
private final KeyguardStateController mKeyguard;
private final NetworkController mNetworkController;
+ private final DialogLaunchAnimator mDialogLaunchAnimator;
private final Callback mCallback = new Callback();
private Dialog mDialog;
private boolean mWifiConnected;
@@ -94,7 +95,8 @@ public class CastTile extends QSTileImpl<BooleanState> {
CastController castController,
KeyguardStateController keyguardStateController,
NetworkController networkController,
- HotspotController hotspotController
+ HotspotController hotspotController,
+ DialogLaunchAnimator dialogLaunchAnimator
) {
super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
statusBarStateController, activityStarter, qsLogger);
@@ -102,6 +104,7 @@ public class CastTile extends QSTileImpl<BooleanState> {
mDetailAdapter = new CastDetailAdapter();
mKeyguard = keyguardStateController;
mNetworkController = networkController;
+ mDialogLaunchAnimator = dialogLaunchAnimator;
mController.observe(this, mCallback);
mKeyguard.observe(this, mCallback);
mNetworkController.observe(this, mSignalCallback);
@@ -153,9 +156,15 @@ public class CastTile extends QSTileImpl<BooleanState> {
List<CastDevice> activeDevices = getActiveDevices();
if (willPopDetail()) {
- mActivityStarter.postQSRunnableDismissingKeyguard(() -> {
- showDetail(true);
- });
+ if (!mKeyguard.isShowing()) {
+ showDetail(view);
+ } else {
+ mActivityStarter.postQSRunnableDismissingKeyguard(() -> {
+ // Dismissing the keyguard will collapse the shade, so we don't animate from the
+ // view here as it would not look good.
+ showDetail(null /* view */);
+ });
+ }
} else {
mController.stopCasting(activeDevices.get(0));
}
@@ -184,19 +193,29 @@ public class CastTile extends QSTileImpl<BooleanState> {
@Override
public void showDetail(boolean show) {
+ showDetail(null /* view */);
+ }
+
+ private void showDetail(@Nullable View view) {
mUiHandler.post(() -> {
mDialog = MediaRouteDialogPresenter.createDialog(mContext, ROUTE_TYPE_REMOTE_DISPLAY,
v -> {
+ mDialogLaunchAnimator.disableAllCurrentDialogsExitAnimations();
mDialog.dismiss();
mActivityStarter
.postStartActivityDismissingKeyguard(getLongClickIntent(), 0);
});
- mDialog.getWindow().setType(LayoutParams.TYPE_KEYGUARD_DIALOG);
SystemUIDialog.setShowForAllUsers(mDialog, true);
SystemUIDialog.registerDismissListener(mDialog);
SystemUIDialog.setWindowOnTop(mDialog);
- mUiHandler.post(() -> mDialog.show());
- mHost.collapsePanels();
+
+ mUiHandler.post(() -> {
+ if (view != null) {
+ mDialogLaunchAnimator.showFromView(mDialog, view);
+ } else {
+ mDialog.show();
+ }
+ });
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 3163c5f5a3c9..20805a141312 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -190,14 +190,10 @@ public class DndTile extends QSTileImpl<BooleanState> {
case Settings.Secure.ZEN_DURATION_PROMPT:
mUiHandler.post(() -> {
Dialog dialog = makeZenModeDialog();
+ SystemUIDialog.registerDismissListener(dialog);
if (view != null) {
- final Dialog hostDialog =
- mDialogLaunchAnimator.showFromView(dialog, view, false);
- setDialogListeners(dialog, hostDialog);
+ mDialogLaunchAnimator.showFromView(dialog, view, false);
} else {
- // If we are not launching with animator, register default
- // dismiss listener
- SystemUIDialog.registerDismissListener(dialog);
dialog.show();
}
});
@@ -222,12 +218,6 @@ public class DndTile extends QSTileImpl<BooleanState> {
return dialog;
}
- private void setDialogListeners(Dialog zenModeDialog, Dialog hostDialog) {
- // Zen mode dialog is never hidden.
- SystemUIDialog.registerDismissListener(zenModeDialog, hostDialog::dismiss);
- zenModeDialog.setOnCancelListener(dialog -> hostDialog.cancel());
- }
-
@Override
protected void handleSecondaryClick(@Nullable View view) {
if (mController.isVolumeRestricted()) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt b/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt
index 00e04540fd94..7c8f4b15d3a3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt
@@ -94,24 +94,24 @@ class UserSwitchDialogController @VisibleForTesting constructor(
adapter.linkToViewGroup(gridFrame.findViewById(R.id.grid))
- val hostDialog = dialogLaunchAnimator.showFromView(this, view)
- adapter.injectDialogShower(DialogShowerImpl(hostDialog, dialogLaunchAnimator))
+ dialogLaunchAnimator.showFromView(this, view)
+ adapter.injectDialogShower(DialogShowerImpl(this, dialogLaunchAnimator))
}
}
private class DialogShowerImpl(
- private val hostDialog: Dialog,
+ private val animateFrom: Dialog,
private val dialogLaunchAnimator: DialogLaunchAnimator
- ) : DialogInterface by hostDialog, DialogShower {
- override fun showDialog(dialog: Dialog): Dialog {
- return dialogLaunchAnimator.showFromDialog(
+ ) : DialogInterface by animateFrom, DialogShower {
+ override fun showDialog(dialog: Dialog) {
+ dialogLaunchAnimator.showFromDialog(
dialog,
- parentHostDialog = hostDialog
+ animateFrom = animateFrom
)
}
}
interface DialogShower : DialogInterface {
- fun showDialog(dialog: Dialog): Dialog
+ fun showDialog(dialog: Dialog)
}
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
index 74ea19f4ca22..1d921702e632 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
@@ -20,6 +20,7 @@ import android.app.IActivityManager;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Handler;
+import android.service.dreams.IDreamManager;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.animation.ActivityLaunchAnimator;
@@ -67,13 +68,10 @@ import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl;
import com.android.systemui.statusbar.phone.StatusBarRemoteInputCallback;
-import com.android.systemui.statusbar.phone.SystemUIHostDialogProvider;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallLogger;
import com.android.systemui.statusbar.policy.RemoteInputUriController;
import com.android.systemui.statusbar.window.StatusBarWindowController;
-import com.android.systemui.statusbar.window.StatusBarWindowModule;
-import com.android.systemui.statusbar.window.StatusBarWindowView;
import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.time.SystemClock;
@@ -320,7 +318,7 @@ public interface StatusBarDependenciesModule {
@Provides
@SysUISingleton
static DialogLaunchAnimator provideDialogLaunchAnimator(Context context,
- LaunchAnimator launchAnimator) {
- return new DialogLaunchAnimator(context, launchAnimator, new SystemUIHostDialogProvider());
+ LaunchAnimator launchAnimator, IDreamManager dreamManager) {
+ return new DialogLaunchAnimator(context, launchAnimator, dreamManager);
}
}
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 ed52a81751dd..43264b600a0e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
@@ -40,30 +40,21 @@ import androidx.annotation.Nullable;
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;
-import java.util.LinkedHashSet;
-import java.util.Set;
-
-
/**
* Base class for dialogs that should appear over panels and keyguard.
* 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,
- ViewRootImpl.ConfigChangedCallback {
+public class SystemUIDialog extends AlertDialog implements 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";
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;
@@ -117,10 +108,6 @@ public class SystemUIDialog extends AlertDialog implements ListenableDialog,
mLastWidth = width;
mLastHeight = height;
getWindow().setLayout(width, height);
-
- for (DialogListener listener : new LinkedHashSet<>(mDialogListeners)) {
- listener.onSizeChanged();
- }
}
@Override
@@ -197,60 +184,6 @@ public class SystemUIDialog extends AlertDialog implements ListenableDialog,
ViewRootImpl.removeConfigCallback(this);
}
- @Override
- public void addListener(DialogListener listener) {
- mDialogListeners.add(listener);
- }
-
- @Override
- public void removeListener(DialogListener listener) {
- mDialogListeners.remove(listener);
- }
-
- @Override
- public void dismiss() {
- dismiss(DismissReason.UNKNOWN);
- }
-
- private void dismiss(DismissReason reason) {
- super.dismiss();
-
- for (DialogListener listener : new LinkedHashSet<>(mDialogListeners)) {
- listener.onDismiss(reason);
- }
- }
-
- /**
- * Dismiss this dialog. If it was launched from another dialog using
- * {@link com.android.systemui.animation.DialogLaunchAnimator#showFromView} with a
- * non-{@code null} {@code parentHostDialog} parameter, also dismisses the stack of dialogs,
- * animating back to the original touchSurface.
- */
- public void dismissStack() {
- for (DialogListener listener : new LinkedHashSet<>(mDialogListeners)) {
- listener.prepareForStackDismiss();
- }
- dismiss();
- }
-
- @Override
- public void hide() {
- super.hide();
-
- for (DialogListener listener : new LinkedHashSet<>(mDialogListeners)) {
- listener.onHide();
- }
- }
-
- @Override
- public void show() {
- super.show();
-
- for (DialogListener listener : new LinkedHashSet<>(mDialogListeners)) {
- listener.onShow();
- }
- }
-
public void setShowForAllUsers(boolean show) {
setShowForAllUsers(this, show);
}
@@ -364,11 +297,7 @@ public class SystemUIDialog extends AlertDialog implements ListenableDialog,
@Override
public void onReceive(Context context, Intent intent) {
- if (mDialog instanceof SystemUIDialog) {
- ((SystemUIDialog) mDialog).dismiss(DismissReason.DEVICE_LOCKED);
- } else {
- mDialog.dismiss();
- }
+ 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
deleted file mode 100644
index 4f18f8c597b2..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIHostDialogProvider.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-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. */
-class SystemUIHostDialogProvider : HostDialogProvider {
- override fun createHostDialog(
- context: Context,
- theme: Int,
- onCreateCallback: () -> Unit,
- dismissOverride: (() -> Unit) -> Unit
- ): Dialog {
- 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, false /* dismissOnDeviceLock */) {
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- onCreateCallback()
- }
-
- override fun dismiss() {
- dismissOverride {
- 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/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index fd387ae0a82e..36e56f967424 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -69,6 +69,7 @@ import com.android.systemui.Prefs;
import com.android.systemui.Prefs.Key;
import com.android.systemui.R;
import com.android.systemui.SystemUISecondaryUserService;
+import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
@@ -133,6 +134,7 @@ public class UserSwitcherController implements Dumpable {
private final IActivityTaskManager mActivityTaskManager;
private final InteractionJankMonitor mInteractionJankMonitor;
private final LatencyTracker mLatencyTracker;
+ private final DialogLaunchAnimator mDialogLaunchAnimator;
private ArrayList<UserRecord> mUsers = new ArrayList<>();
@VisibleForTesting
@@ -180,7 +182,8 @@ public class UserSwitcherController implements Dumpable {
@Background Executor bgExecutor,
InteractionJankMonitor interactionJankMonitor,
LatencyTracker latencyTracker,
- DumpManager dumpManager) {
+ DumpManager dumpManager,
+ DialogLaunchAnimator dialogLaunchAnimator) {
mContext = context;
mActivityManager = activityManager;
mUserTracker = userTracker;
@@ -208,6 +211,8 @@ public class UserSwitcherController implements Dumpable {
mHandler = handler;
mActivityStarter = activityStarter;
mUserManager = userManager;
+ mDialogLaunchAnimator = dialogLaunchAnimator;
+
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_ADDED);
filter.addAction(Intent.ACTION_USER_REMOVED);
@@ -1179,7 +1184,7 @@ public class UserSwitcherController implements Dumpable {
cancel();
} else {
mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_REMOVE);
- dismissStack();
+ mDialogLaunchAnimator.dismissStack(this);
removeGuestUser(mGuestId, mTargetId);
}
}
@@ -1210,7 +1215,7 @@ public class UserSwitcherController implements Dumpable {
if (which == BUTTON_NEGATIVE) {
cancel();
} else {
- dismissStack();
+ mDialogLaunchAnimator.dismissStack(this);
if (ActivityManager.isUserAMonkey()) {
return;
}
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 9bd33eb8db6b..f9ad740f86df 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt
@@ -2,35 +2,49 @@ package com.android.systemui.animation
import android.app.Dialog
import android.content.Context
+import android.graphics.Color
+import android.graphics.drawable.ColorDrawable
import android.os.Bundle
+import android.service.dreams.IDreamManager
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.testing.ViewUtils
import android.view.View
import android.view.ViewGroup
+import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.WindowManager
import android.widget.LinearLayout
import androidx.test.filters.SmallTest
+import com.android.internal.policy.DecorView
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.assertNotNull
import junit.framework.Assert.assertTrue
import org.junit.After
+import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.junit.MockitoJUnit
@SmallTest
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper
class DialogLaunchAnimatorTest : SysuiTestCase() {
private val launchAnimator = LaunchAnimator(context, isForTesting = true)
- private val hostDialogprovider = TestHostDialogProvider()
- private val dialogLaunchAnimator =
- DialogLaunchAnimator(context, launchAnimator, hostDialogprovider)
-
+ private lateinit var dialogLaunchAnimator: DialogLaunchAnimator
private val attachedViews = mutableSetOf<View>()
+ @Mock lateinit var dreamManager: IDreamManager
+ @get:Rule val rule = MockitoJUnit.rule()
+
+ @Before
+ fun setUp() {
+ dialogLaunchAnimator = DialogLaunchAnimator(context, launchAnimator, dreamManager)
+ }
+
@After
fun tearDown() {
runOnMainThreadAndWaitForIdleSync {
@@ -44,76 +58,66 @@ class DialogLaunchAnimatorTest : SysuiTestCase() {
fun testShowDialogFromView() {
// Show the dialog. showFromView() must be called on the main thread with a dialog created
// on the main thread too.
- val (dialog, hostDialog) = createDialogAndHostDialog()
-
- // Only the host dialog is actually showing.
- assertTrue(hostDialog.isShowing)
- assertFalse(dialog.isShowing)
-
- // The dialog onStart() method was called but not onStop().
- assertTrue(dialog.onStartCalled)
- assertFalse(dialog.onStopCalled)
-
- // The dialog content has been stolen and is shown inside the host dialog.
- val hostDialogContent = hostDialog.findViewById<ViewGroup>(android.R.id.content)
- assertEquals(0, dialog.findViewById<ViewGroup>(android.R.id.content).childCount)
- assertEquals(1, hostDialogContent.childCount)
-
- // The original dialog content is added to another view that is the same size as the
- // original dialog window.
- val hostDialogRoot = hostDialogContent.getChildAt(0) as ViewGroup
- assertEquals(1, hostDialogRoot.childCount)
-
- val dialogContentParent = hostDialogRoot.getChildAt(0) as ViewGroup
- assertEquals(1, dialogContentParent.childCount)
- assertEquals(TestDialog.DIALOG_WIDTH, dialogContentParent.layoutParams.width)
- assertEquals(TestDialog.DIALOG_HEIGHT, dialogContentParent.layoutParams.height)
-
- val dialogContent = dialogContentParent.getChildAt(0)
- assertEquals(dialog.contentView, dialogContent)
- assertEquals(ViewGroup.LayoutParams.MATCH_PARENT, dialogContent.layoutParams.width)
- assertEquals(ViewGroup.LayoutParams.MATCH_PARENT, dialogContent.layoutParams.height)
-
- // Hiding/showing/dismissing the dialog should hide/show/dismiss the host dialog given that
- // it's a ListenableDialog.
- runOnMainThreadAndWaitForIdleSync { dialog.hide() }
- assertFalse(hostDialog.isShowing)
- assertFalse(dialog.isShowing)
-
- runOnMainThreadAndWaitForIdleSync { dialog.show() }
- assertTrue(hostDialog.isShowing)
- assertFalse(dialog.isShowing)
-
- assertFalse(dialog.onStopCalled)
+ val dialog = createAndShowDialog()
+
+ assertTrue(dialog.isShowing)
+
+ // The dialog is now fullscreen.
+ val window = dialog.window
+ val decorView = window.decorView as DecorView
+ assertEquals(MATCH_PARENT, window.attributes.width)
+ assertEquals(MATCH_PARENT, window.attributes.height)
+ assertEquals(MATCH_PARENT, decorView.layoutParams.width)
+ assertEquals(MATCH_PARENT, decorView.layoutParams.height)
+
+ // The single DecorView child is a transparent fullscreen view that will dismiss the dialog
+ // when clicked.
+ assertEquals(1, decorView.childCount)
+ val transparentBackground = decorView.getChildAt(0) as ViewGroup
+ assertEquals(MATCH_PARENT, transparentBackground.layoutParams.width)
+ assertEquals(MATCH_PARENT, transparentBackground.layoutParams.height)
+
+ // The single transparent background child is a fake window with the same size and
+ // background as the dialog initially had.
+ assertEquals(1, transparentBackground.childCount)
+ val dialogContentWithBackground = transparentBackground.getChildAt(0) as ViewGroup
+ assertEquals(TestDialog.DIALOG_WIDTH, dialogContentWithBackground.layoutParams.width)
+ assertEquals(TestDialog.DIALOG_HEIGHT, dialogContentWithBackground.layoutParams.height)
+ assertEquals(dialog.windowBackground, dialogContentWithBackground.background)
+
+ // The dialog content is inside this fake window view.
+ assertNotNull(
+ dialogContentWithBackground.findViewByPredicate { it === dialog.contentView })
+
+ // Clicking the transparent background should dismiss the dialog.
runOnMainThreadAndWaitForIdleSync {
// TODO(b/204561691): Remove this call to disableAllCurrentDialogsExitAnimations() and
// make sure that the test still pass on git_master/cf_x86_64_phone-userdebug in
// Forrest.
dialogLaunchAnimator.disableAllCurrentDialogsExitAnimations()
- dialog.dismiss()
+ transparentBackground.performClick()
}
- assertFalse(hostDialog.isShowing)
assertFalse(dialog.isShowing)
- assertTrue(hostDialog.wasDismissed)
- assertTrue(dialog.onStopCalled)
}
@Test
fun testStackedDialogsDismissesAll() {
- val (_, hostDialogFirst) = createDialogAndHostDialog()
- val (dialogSecond, hostDialogSecond) = createDialogAndHostDialogFromDialog(hostDialogFirst)
+ val firstDialog = createAndShowDialog()
+ val secondDialog = createDialogAndShowFromDialog(firstDialog)
+ assertTrue(firstDialog.isShowing)
+ assertTrue(secondDialog.isShowing)
runOnMainThreadAndWaitForIdleSync {
dialogLaunchAnimator.disableAllCurrentDialogsExitAnimations()
- dialogSecond.dismissStack()
+ dialogLaunchAnimator.dismissStack(secondDialog)
}
- assertTrue(hostDialogSecond.wasDismissed)
- assertTrue(hostDialogFirst.wasDismissed)
+ assertFalse(firstDialog.isShowing)
+ assertFalse(secondDialog.isShowing)
}
- private fun createDialogAndHostDialog(): Pair<TestDialog, TestHostDialog> {
+ private fun createAndShowDialog(): TestDialog {
return runOnMainThreadAndWaitForIdleSync {
val touchSurfaceRoot = LinearLayout(context)
val touchSurface = View(context)
@@ -125,22 +129,16 @@ class DialogLaunchAnimatorTest : SysuiTestCase() {
attachedViews.add(touchSurfaceRoot)
val dialog = TestDialog(context)
- val hostDialog =
- dialogLaunchAnimator.showFromView(dialog, touchSurface) as TestHostDialog
- dialog to hostDialog
+ dialogLaunchAnimator.showFromView(dialog, touchSurface)
+ dialog
}
}
- private fun createDialogAndHostDialogFromDialog(
- hostParent: Dialog
- ): Pair<TestDialog, TestHostDialog> {
+ private fun createDialogAndShowFromDialog(animateFrom: Dialog): TestDialog {
return runOnMainThreadAndWaitForIdleSync {
val dialog = TestDialog(context)
- val hostDialog = dialogLaunchAnimator.showFromDialog(
- dialog,
- hostParent
- ) as TestHostDialog
- dialog to hostDialog
+ dialogLaunchAnimator.showFromDialog(dialog, animateFrom)
+ dialog
}
}
@@ -153,50 +151,14 @@ class DialogLaunchAnimatorTest : SysuiTestCase() {
return result
}
- private class TestHostDialogProvider : HostDialogProvider {
- override fun createHostDialog(
- context: Context,
- theme: Int,
- onCreateCallback: () -> Unit,
- dismissOverride: (() -> Unit) -> Unit
- ): Dialog = TestHostDialog(context, onCreateCallback, dismissOverride)
- }
-
- private class TestHostDialog(
- context: Context,
- private val onCreateCallback: () -> Unit,
- private val dismissOverride: (() -> Unit) -> Unit
- ) : Dialog(context) {
- var wasDismissed = false
-
- init {
- // We need to set the window type for dialogs shown by SysUI, otherwise WM will throw.
- window.setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL)
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- onCreateCallback()
- }
-
- override fun dismiss() {
- dismissOverride {
- super.dismiss()
- wasDismissed = true
- }
- }
- }
-
- private class TestDialog(context: Context) : Dialog(context), ListenableDialog {
+ private class TestDialog(context: Context) : Dialog(context) {
companion object {
const val DIALOG_WIDTH = 100
const val DIALOG_HEIGHT = 200
}
- private val listeners = hashSetOf<DialogListener>()
val contentView = View(context)
- var onStartCalled = false
- var onStopCalled = false
+ val windowBackground = ColorDrawable(Color.RED)
init {
// We need to set the window type for dialogs shown by SysUI, otherwise WM will throw.
@@ -205,52 +167,10 @@ class DialogLaunchAnimatorTest : SysuiTestCase() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- window.setLayout(DIALOG_WIDTH, DIALOG_HEIGHT)
setContentView(contentView)
- }
-
- override fun onStart() {
- super.onStart()
- onStartCalled = true
- }
-
- override fun onStop() {
- super.onStart()
- onStopCalled = true
- }
-
- override fun addListener(listener: DialogListener) {
- listeners.add(listener)
- }
-
- override fun removeListener(listener: DialogListener) {
- listeners.remove(listener)
- }
-
- override fun dismiss() {
- super.dismiss()
- notifyListeners { onDismiss(DismissReason.UNKNOWN) }
- }
-
- override fun hide() {
- super.hide()
- notifyListeners { onHide() }
- }
- override fun show() {
- super.show()
- notifyListeners { onShow() }
- }
-
- fun dismissStack() {
- notifyListeners { prepareForStackDismiss() }
- dismiss()
- }
-
- private fun notifyListeners(notify: DialogListener.() -> Unit) {
- for (listener in HashSet(listeners)) {
- listener.notify()
- }
+ window.setLayout(DIALOG_WIDTH, DIALOG_HEIGHT)
+ window.setBackgroundDrawable(windowBackground)
}
}
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
index 5a49337fe640..b40a20c27820 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
@@ -38,6 +38,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -90,6 +91,8 @@ public class CastTileTest extends SysuiTestCase {
private HotspotController.Callback mHotspotCallback;
@Mock
private QSLogger mQSLogger;
+ @Mock
+ private DialogLaunchAnimator mDialogLaunchAnimator;
private TestableLooper mTestableLooper;
private CastTile mCastTile;
@@ -113,7 +116,8 @@ public class CastTileTest extends SysuiTestCase {
mController,
mKeyguard,
mNetworkController,
- mHotspotController
+ mHotspotController,
+ mDialogLaunchAnimator
);
mCastTile.initialize();
@@ -241,6 +245,7 @@ public class CastTileTest extends SysuiTestCase {
List<CastDevice> devices = new ArrayList<>();
devices.add(device);
when(mController.getCastDevices()).thenReturn(devices);
+ when(mKeyguard.isShowing()).thenReturn(true);
enableWifiAndProcessMessages();
mCastTile.handleClick(null /* view */);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt
index 13df04ccef6f..9936d4951d00 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt
@@ -96,8 +96,6 @@ class DndTileTest : SysuiTestCase() {
whenever(qsHost.userId).thenReturn(DEFAULT_USER)
whenever(qsHost.uiEventLogger).thenReturn(uiEventLogger)
- whenever(dialogLaunchAnimator.showFromView(any(), any(), anyBoolean()))
- .thenReturn(hostDialog)
val wrappedContext = object : ContextWrapper(context) {
override fun getSharedPreferences(file: File?, mode: Int): SharedPreferences {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt
index 3c4a557eac10..b7fdc1a6cb0d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt
@@ -16,7 +16,6 @@
package com.android.systemui.qs.user
-import android.app.Dialog
import android.content.DialogInterface
import android.content.Intent
import android.provider.Settings
@@ -31,7 +30,6 @@ import com.android.systemui.qs.PseudoGridView
import com.android.systemui.qs.tiles.UserDetailView
import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
import org.junit.Before
@@ -42,7 +40,6 @@ import org.mockito.ArgumentMatcher
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.`when`
-import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.anyInt
import org.mockito.Mockito.argThat
import org.mockito.Mockito.never
@@ -65,8 +62,6 @@ class UserSwitchDialogControllerTest : SysuiTestCase() {
private lateinit var launchView: View
@Mock
private lateinit var dialogLaunchAnimator: DialogLaunchAnimator
- @Mock
- private lateinit var hostDialog: Dialog
@Captor
private lateinit var clickCaptor: ArgumentCaptor<DialogInterface.OnClickListener>
@@ -78,8 +73,6 @@ class UserSwitchDialogControllerTest : SysuiTestCase() {
`when`(launchView.context).thenReturn(mContext)
`when`(dialog.context).thenReturn(mContext)
- `when`(dialogLaunchAnimator.showFromView(any(), any(), anyBoolean()))
- .thenReturn(hostDialog)
controller = UserSwitchDialogController(
{ userDetailViewAdapter },
@@ -151,18 +144,6 @@ class UserSwitchDialogControllerTest : SysuiTestCase() {
verify(activityStarter, never()).postStartActivityDismissingKeyguard(any(), anyInt())
}
- @Test
- fun callbackFromDialogShower_dismissesDialog() {
- val captor = argumentCaptor<UserSwitchDialogController.DialogShower>()
-
- controller.showDialog(launchView)
- verify(userDetailViewAdapter).injectDialogShower(capture(captor))
-
- captor.value.dismiss()
-
- verify(hostDialog).dismiss()
- }
-
private class IntentMatcher(private val action: String) : ArgumentMatcher<Intent> {
override fun matches(argument: Intent?): Boolean {
return argument?.action == action
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
index 724f841922ff..a4bf14254e2c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
@@ -40,6 +40,7 @@ import com.android.internal.util.UserIcons
import com.android.systemui.GuestResumeSessionReceiver
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.ActivityStarter
@@ -94,6 +95,7 @@ class UserSwitcherControllerTest : SysuiTestCase() {
@Mock private lateinit var dialogShower: UserSwitchDialogController.DialogShower
@Mock private lateinit var notificationShadeWindowView: NotificationShadeWindowView
@Mock private lateinit var threadedRenderer: ThreadedRenderer
+ @Mock private lateinit var dialogLaunchAnimator: DialogLaunchAnimator
private lateinit var testableLooper: TestableLooper
private lateinit var uiBgExecutor: FakeExecutor
private lateinit var uiEventLogger: UiEventLoggerFake
@@ -147,7 +149,8 @@ class UserSwitcherControllerTest : SysuiTestCase() {
uiBgExecutor,
interactionJankMonitor,
latencyTracker,
- dumpManager)
+ dumpManager,
+ dialogLaunchAnimator)
userSwitcherController.mPauseRefreshUsers = true
// Since userSwitcherController involves InteractionJankMonitor.