Merge "Update removeTaskInternal Desktop case" into main
diff --git a/quickstep/res/values/ids.xml b/quickstep/res/values/ids.xml
index 3091d9e..c71bb76 100644
--- a/quickstep/res/values/ids.xml
+++ b/quickstep/res/values/ids.xml
@@ -19,4 +19,6 @@
<item type="id" name="action_move_left" />
<item type="id" name="action_move_right" />
<item type="id" name="action_dismiss_all" />
+
+ <item type="id" name="bubble_bar_flyout_view" />
</resources>
\ No newline at end of file
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
index 51e09ab..b22fd6f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
@@ -377,8 +377,6 @@
// Updates mean the dot state may have changed; any other changes were updated in
// the populateBubble step.
BubbleBarBubble bb = mBubbles.get(update.updatedBubble.getKey());
- // If we're not stashed, we're visible so animate
- bb.getView().updateDotVisibility(!mBubbleStashController.isStashed() /* animate */);
mBubbleBarViewController.animateBubbleNotification(
bb, /* isExpanding= */ false, /* isUpdate= */ true);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index 63f101f..76d3606 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -148,7 +148,8 @@
mBubbleBarFlyoutController = new BubbleBarFlyoutController(
mBubbleBarContainer, createFlyoutPositioner(), createFlyoutTopBoundaryListener());
mBubbleBarViewAnimator = new BubbleBarViewAnimator(
- mBarView, mBubbleStashController, mBubbleBarController::showExpandedView);
+ mBarView, mBubbleStashController, mBubbleBarFlyoutController,
+ mBubbleBarController::showExpandedView);
mTaskbarViewPropertiesProvider = taskbarViewPropertiesProvider;
onBubbleBarConfigurationChanged(/* animate= */ false);
mActivity.addOnDeviceProfileChangeListener(
@@ -781,6 +782,11 @@
/** Animates the bubble bar to notify the user about a bubble change. */
public void animateBubbleNotification(BubbleBarBubble bubble, boolean isExpanding,
boolean isUpdate) {
+ // if we're expanded, don't animate the bubble bar. just show the notification dot.
+ if (isExpanded()) {
+ bubble.getView().updateDotVisibility(/* animate= */ true);
+ return;
+ }
boolean isInApp = mTaskbarStashController.isInApp();
// if this is the first bubble, animate to the initial state.
if (mBarView.getBubbleChildCount() == 1 && !isUpdate) {
@@ -789,13 +795,12 @@
}
boolean persistentTaskbarOrOnHome = mBubbleStashController.isBubblesShowingOnHome()
|| !mBubbleStashController.isTransientTaskBar();
- if (persistentTaskbarOrOnHome && !isExpanded()) {
+ if (persistentTaskbarOrOnHome) {
mBubbleBarViewAnimator.animateBubbleBarForCollapsed(bubble, isExpanding);
return;
}
- // only animate the new bubble if we're in an app, have handle view and not auto expanding
- if (isInApp && mBubbleStashController.getHasHandleView() && !isExpanded()) {
+ if (isInApp && mBubbleStashController.getHasHandleView()) {
mBubbleBarViewAnimator.animateBubbleInForStashed(bubble, isExpanding);
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
index 707655c..4f3e1ae 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
@@ -301,7 +301,7 @@
void updateDotVisibility(boolean animate) {
if (mDotSuppressedForBubbleUpdate) {
- // if the dot is suppressed for
+ // if the dot is suppressed for an update, there's nothing to do
return;
}
final float targetScale = hasUnseenContent() ? 1f : 0f;
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
index 6a955d9..8a52ca9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
@@ -27,6 +27,8 @@
import com.android.launcher3.taskbar.bubbles.BubbleBarBubble
import com.android.launcher3.taskbar.bubbles.BubbleBarView
import com.android.launcher3.taskbar.bubbles.BubbleView
+import com.android.launcher3.taskbar.bubbles.flyout.BubbleBarFlyoutController
+import com.android.launcher3.taskbar.bubbles.flyout.BubbleBarFlyoutMessage
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController
import com.android.wm.shell.shared.animation.PhysicsAnimator
@@ -36,8 +38,9 @@
constructor(
private val bubbleBarView: BubbleBarView,
private val bubbleStashController: BubbleStashController,
+ private val bubbleBarFlyoutController: BubbleBarFlyoutController,
private val onExpanded: Runnable,
- private val scheduler: Scheduler = HandlerScheduler(bubbleBarView)
+ private val scheduler: Scheduler = HandlerScheduler(bubbleBarView),
) {
private var animatingBubble: AnimatingBubble? = null
@@ -54,7 +57,7 @@
private companion object {
/** The time to show the flyout. */
- const val FLYOUT_DELAY_MS: Long = 2500
+ const val FLYOUT_DELAY_MS: Long = 3000
/** The initial scale Y value that the new bubble is set to before the animation starts. */
const val BUBBLE_ANIMATION_INITIAL_SCALE_Y = 0.3f
/** The minimum alpha value to make the bubble bar touchable. */
@@ -69,7 +72,7 @@
val showAnimation: Runnable,
val hideAnimation: Runnable,
val expand: Boolean,
- val state: State = State.CREATED
+ val state: State = State.CREATED,
) {
/**
@@ -91,7 +94,7 @@
/** The bubble notification is now fully showing and waiting to be hidden. */
IN,
/** The bubble notification is animating out. */
- ANIMATING_OUT
+ ANIMATING_OUT,
}
}
@@ -127,7 +130,7 @@
private val springConfig =
PhysicsAnimator.SpringConfig(
stiffness = SpringForce.STIFFNESS_LOW,
- dampingRatio = SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY
+ dampingRatio = SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY,
)
/** Animates a bubble for the state where the bubble bar is stashed. */
@@ -137,8 +140,9 @@
val bubbleView = b.view
val animator = PhysicsAnimator.getInstance(bubbleView)
if (animator.isRunning()) animator.cancel()
- // the animation of a new bubble is divided into 2 parts. The first part shows the bubble
- // and the second part hides it after a delay.
+ // the animation of a new bubble is divided into 2 parts. The first part transforms the
+ // handle to the bubble bar and then shows the flyout. The second part hides the flyout and
+ // transforms the bubble bar back to the handle.
val showAnimation = buildHandleToBubbleBarAnimation()
val hideAnimation = if (isExpanding) Runnable {} else buildBubbleBarToHandleAnimation()
animatingBubble =
@@ -243,7 +247,8 @@
cancelHideAnimation()
return@addEndListener
}
- moveToState(AnimatingBubble.State.IN)
+ setupAndShowFlyout()
+
// the bubble bar is now fully settled in. update taskbar touch region so it's touchable
bubbleStashController.updateTaskbarTouchRegion()
}
@@ -316,7 +321,17 @@
bubbleBarView.scaleY = 1f
bubbleStashController.updateTaskbarTouchRegion()
}
- animator.start()
+
+ val bubble = animatingBubble?.bubbleView?.bubble as? BubbleBarBubble
+ val flyout = bubble?.flyoutMessage
+ if (flyout != null) {
+ bubbleBarFlyoutController.collapseFlyout {
+ onFlyoutRemoved(bubble.view)
+ animator.start()
+ }
+ } else {
+ animator.start()
+ }
}
/** Animates to the initial state of the bubble bar, when there are no previous bubbles. */
@@ -326,16 +341,16 @@
val bubbleView = b.view
val animator = PhysicsAnimator.getInstance(bubbleView)
if (animator.isRunning()) animator.cancel()
- // the animation of a new bubble is divided into 2 parts. The first part shows the bubble
- // and the second part hides it after a delay if we are in an app.
+ // the animation of a new bubble is divided into 2 parts. The first part slides in the
+ // bubble bar and shows the flyout. The second part hides the flyout and transforms the
+ // bubble bar to the handle if we're in an app.
val showAnimation = buildBubbleBarSpringInAnimation()
val hideAnimation =
if (isInApp && !isExpanding) {
buildBubbleBarToHandleAnimation()
} else {
- // in this case the bubble bar remains visible so not much to do. once we implement
- // the flyout we'll update this runnable to hide it.
Runnable {
+ bubbleBarFlyoutController.collapseFlyout { onFlyoutRemoved(bubbleView) }
animatingBubble = null
bubbleStashController.showBubbleBarImmediate()
bubbleStashController.updateTaskbarTouchRegion()
@@ -370,7 +385,7 @@
if (animatingBubble?.expand == true) {
cancelHideAnimation()
} else {
- moveToState(AnimatingBubble.State.IN)
+ setupAndShowFlyout()
}
// the bubble bar is now fully settled in. update taskbar touch region so it's touchable
bubbleStashController.updateTaskbarTouchRegion()
@@ -384,8 +399,10 @@
val bubbleView = b.view
val animator = PhysicsAnimator.getInstance(bubbleView)
if (animator.isRunning()) animator.cancel()
+ // first bounce the bubble bar and show the flyout. Then hide the flyout.
val showAnimation = buildBubbleBarBounceAnimation()
val hideAnimation = Runnable {
+ bubbleBarFlyoutController.collapseFlyout { onFlyoutRemoved(bubbleView) }
animatingBubble = null
bubbleStashController.showBubbleBarImmediate()
bubbleStashController.updateTaskbarTouchRegion()
@@ -413,7 +430,7 @@
expandBubbleBar()
cancelHideAnimation()
} else {
- moveToState(AnimatingBubble.State.IN)
+ setupAndShowFlyout()
}
}
@@ -427,10 +444,38 @@
.start()
}
+ private fun setupAndShowFlyout() {
+ val bubbleView = animatingBubble?.bubbleView
+ val bubble = bubbleView?.bubble as? BubbleBarBubble
+ val flyout = bubble?.flyoutMessage
+ if (flyout != null) {
+ bubbleView.suppressDotForBubbleUpdate(true)
+ bubbleBarFlyoutController.setUpAndShowFlyout(
+ BubbleBarFlyoutMessage(flyout.icon, flyout.title, flyout.message)
+ ) {
+ moveToState(AnimatingBubble.State.IN)
+ bubbleStashController.updateTaskbarTouchRegion()
+ }
+ } else {
+ moveToState(AnimatingBubble.State.IN)
+ }
+ }
+
+ private fun cancelFlyout() {
+ val bubbleView = animatingBubble?.bubbleView
+ bubbleBarFlyoutController.cancelFlyout { onFlyoutRemoved(bubbleView) }
+ }
+
+ private fun onFlyoutRemoved(bubbleView: BubbleView?) {
+ bubbleView?.suppressDotForBubbleUpdate(false)
+ bubbleStashController.updateTaskbarTouchRegion()
+ }
+
/** Handles touching the animating bubble bar. */
fun onBubbleBarTouchedWhileAnimating() {
PhysicsAnimator.getInstance(bubbleBarView).cancelIfRunning()
bubbleStashController.getStashedHandlePhysicsAnimator().cancelIfRunning()
+ cancelFlyout()
val hideAnimation = animatingBubble?.hideAnimation ?: return
scheduler.cancel(hideAnimation)
bubbleBarView.relativePivotY = 1f
@@ -439,6 +484,7 @@
/** Notifies the animator that the taskbar area was touched during an animation. */
fun onStashStateChangingWhileAnimating() {
+ cancelFlyout()
val hideAnimation = animatingBubble?.hideAnimation ?: return
scheduler.cancel(hideAnimation)
animatingBubble = null
@@ -446,7 +492,7 @@
bubbleBarView.relativePivotY = 1f
bubbleStashController.onNewBubbleAnimationInterrupted(
/* isStashed= */ bubbleBarView.alpha == 0f,
- bubbleBarView.translationY
+ bubbleBarView.translationY,
)
}
@@ -455,6 +501,7 @@
this.animatingBubble = animatingBubble.copy(expand = true)
// if we're fully in and waiting to hide, cancel the hide animation and clean up
if (animatingBubble.state == AnimatingBubble.State.IN) {
+ cancelFlyout()
expandBubbleBar()
cancelHideAnimation()
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt
index c431deb..d6400bb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt
@@ -21,8 +21,8 @@
import android.widget.FrameLayout
import androidx.core.animation.ValueAnimator
import com.android.launcher3.R
+import com.android.systemui.util.addListener
import com.android.systemui.util.doOnEnd
-import com.android.systemui.util.doOnStart
/** Creates and manages the visibility of the [BubbleBarFlyoutView]. */
class BubbleBarFlyoutController
@@ -35,14 +35,19 @@
) {
private companion object {
- const val EXPAND_COLLAPSE_ANIMATION_DURATION_MS = 250L
+ const val ANIMATION_DURATION_MS = 250L
}
private var flyout: BubbleBarFlyoutView? = null
private val horizontalMargin =
container.context.resources.getDimensionPixelSize(R.dimen.transient_taskbar_bottom_margin)
- fun setUpFlyout(message: BubbleBarFlyoutMessage) {
+ private enum class AnimationType {
+ COLLAPSE,
+ FADE,
+ }
+
+ fun setUpAndShowFlyout(message: BubbleBarFlyoutMessage, onEnd: () -> Unit) {
flyout?.let(container::removeView)
val flyout = BubbleBarFlyoutView(container.context, positioner, flyoutScheduler)
@@ -58,27 +63,42 @@
lp.marginEnd = horizontalMargin
container.addView(flyout, lp)
- val animator =
- ValueAnimator.ofFloat(0f, 1f).setDuration(EXPAND_COLLAPSE_ANIMATION_DURATION_MS)
+ val animator = ValueAnimator.ofFloat(0f, 1f).setDuration(ANIMATION_DURATION_MS)
animator.addUpdateListener { _ ->
flyout.updateExpansionProgress(animator.animatedValue as Float)
}
- animator.doOnStart {
- val flyoutTop = flyout.top + flyout.translationY
- // If the top position of the flyout is negative, then it's bleeding over the
- // top boundary of its parent view
- if (flyoutTop < 0) topBoundaryListener.extendTopBoundary(space = -flyoutTop.toInt())
- }
+ animator.addListener(
+ onStart = {
+ val flyoutTop = flyout.top + flyout.translationY
+ // If the top position of the flyout is negative, then it's bleeding over the
+ // top boundary of its parent view
+ if (flyoutTop < 0) topBoundaryListener.extendTopBoundary(space = -flyoutTop.toInt())
+ },
+ onEnd = { onEnd() },
+ )
flyout.showFromCollapsed(message) { animator.start() }
this.flyout = flyout
}
- fun hideFlyout(endAction: () -> Unit) {
+ fun cancelFlyout(endAction: () -> Unit) {
+ hideFlyout(AnimationType.FADE, endAction)
+ }
+
+ fun collapseFlyout(endAction: () -> Unit) {
+ hideFlyout(AnimationType.COLLAPSE, endAction)
+ }
+
+ private fun hideFlyout(animationType: AnimationType, endAction: () -> Unit) {
+ // TODO: b/277815200 - stop the current animation if it's running
val flyout = this.flyout ?: return
- val animator =
- ValueAnimator.ofFloat(1f, 0f).setDuration(EXPAND_COLLAPSE_ANIMATION_DURATION_MS)
- animator.addUpdateListener { _ ->
- flyout.updateExpansionProgress(animator.animatedValue as Float)
+ val animator = ValueAnimator.ofFloat(1f, 0f).setDuration(ANIMATION_DURATION_MS)
+ when (animationType) {
+ AnimationType.FADE ->
+ animator.addUpdateListener { _ -> flyout.alpha = animator.animatedValue as Float }
+ AnimationType.COLLAPSE ->
+ animator.addUpdateListener { _ ->
+ flyout.updateExpansionProgress(animator.animatedValue as Float)
+ }
}
animator.doOnEnd {
container.removeView(flyout)
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt
index c60fba2..6903c87 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt
@@ -140,6 +140,7 @@
init {
LayoutInflater.from(context).inflate(R.layout.bubblebar_flyout, this, true)
+ id = R.id.bubble_bar_flyout_view
val ta = context.obtainStyledAttributes(intArrayOf(android.R.attr.dialogCornerRadius))
cornerRadius = ta.getDimensionPixelSize(0, 0).toFloat()
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
index e23947b..461f963 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
@@ -53,7 +53,6 @@
import com.android.systemui.shared.system.InteractionJankMonitorWrapper
import java.io.PrintWriter
import java.util.concurrent.ConcurrentLinkedDeque
-import java.util.concurrent.Executor
import kotlin.coroutines.resume
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
@@ -70,7 +69,6 @@
private val overviewComponentObserver: OverviewComponentObserver,
private val taskAnimationManager: TaskAnimationManager,
private val dispatcherProvider: DispatcherProvider = ProductionDispatchers,
- private val uiExecutor: Executor = Executors.MAIN_EXECUTOR,
) {
private val coroutineScope = CoroutineScope(SupervisorJob() + dispatcherProvider.default)
@@ -87,7 +85,7 @@
get() = overviewComponentObserver.containerInterface
private val visibleRecentsView: RecentsView<*, *>?
- get() = containerInterface.getVisibleRecentsView()
+ get() = containerInterface.getVisibleRecentsView<RecentsView<*, *>>()
/**
* Adds a command to be executed next, after all pending tasks are completed. Max commands that
@@ -107,7 +105,11 @@
if (commandQueue.size == 1) {
Log.d(TAG, "execute: $command - queue size: ${commandQueue.size}")
- uiExecutor.execute { processNextCommand() }
+ if (enableOverviewCommandHelperTimeout()) {
+ coroutineScope.launch(dispatcherProvider.main) { processNextCommand() }
+ } else {
+ Executors.MAIN_EXECUTOR.execute { processNextCommand() }
+ }
} else {
Log.d(TAG, "not executed: $command - queue size: ${commandQueue.size}")
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 27f5248..0c7c176 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -5045,7 +5045,8 @@
mSplitHiddenTaskView = getTaskViewByTaskId(splitSelectSource.alreadyRunningTaskId);
mSplitHiddenTaskViewIndex = indexOfChild(mSplitHiddenTaskView);
mSplitSelectStateController
- .setAnimateCurrentTaskDismissal(splitSelectSource.animateCurrentTaskDismissal);
+ .setAnimateCurrentTaskDismissal(splitSelectSource.animateCurrentTaskDismissal
+ && mSplitHiddenTaskView != null);
// Prevent dismissing whole task if we're only initiating from one of 2 tasks in split pair
mSplitSelectStateController.setDismissingFromSplitPair(mSplitHiddenTaskView != null
@@ -5430,7 +5431,6 @@
int taskIndex = indexOfChild(taskView);
int centerTaskIndex = getCurrentPage();
- boolean isRunningTask = taskView.isRunningTask();
float toScale = getMaxScaleForFullScreen();
boolean showAsGrid = showAsGrid();
@@ -5450,7 +5450,9 @@
setPivotX(mTempPointF.x);
setPivotY(mTempPointF.y);
- if (!isRunningTask) {
+ // If live tile is not launching, apply pivot to live tile as well and bring it
+ // above RecentsView to avoid wallpaper blur from being applied to it.
+ if (!taskView.isRunningTask()) {
runActionOnRemoteHandles(
remoteTargetHandle -> {
remoteTargetHandle.getTaskViewSimulator().setPivotOverride(
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
index 7eee4de..b37048a 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
@@ -19,6 +19,7 @@
import android.content.Context
import android.graphics.Color
import android.graphics.Path
+import android.graphics.PointF
import android.graphics.drawable.ColorDrawable
import android.view.LayoutInflater
import android.view.View
@@ -36,6 +37,10 @@
import com.android.launcher3.taskbar.bubbles.BubbleBarOverflow
import com.android.launcher3.taskbar.bubbles.BubbleBarView
import com.android.launcher3.taskbar.bubbles.BubbleView
+import com.android.launcher3.taskbar.bubbles.flyout.BubbleBarFlyoutController
+import com.android.launcher3.taskbar.bubbles.flyout.BubbleBarFlyoutMessage
+import com.android.launcher3.taskbar.bubbles.flyout.BubbleBarFlyoutPositioner
+import com.android.launcher3.taskbar.bubbles.flyout.FlyoutScheduler
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController
import com.android.wm.shell.shared.animation.PhysicsAnimator
import com.android.wm.shell.shared.animation.PhysicsAnimatorTestUtils
@@ -63,13 +68,19 @@
private lateinit var bubbleView: BubbleView
private lateinit var bubble: BubbleBarBubble
private lateinit var bubbleBarView: BubbleBarView
+ private lateinit var flyoutContainer: FrameLayout
private lateinit var bubbleStashController: BubbleStashController
+ private lateinit var flyoutController: BubbleBarFlyoutController
private val onExpandedNoOp = Runnable {}
+ private val flyoutView: View?
+ get() = flyoutContainer.findViewById(R.id.bubble_bar_flyout_view)
+
@Before
fun setUp() {
animatorScheduler = TestBubbleBarViewAnimatorScheduler()
PhysicsAnimatorTestUtils.prepareForTest()
+ setupFlyoutController()
}
@Test
@@ -85,6 +96,7 @@
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
+ flyoutController,
onExpandedNoOp,
animatorScheduler,
)
@@ -106,10 +118,14 @@
assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
assertThat(animator.isAnimating).isTrue()
+ waitForFlyoutToShow()
+
// execute the hide bubble animation
assertThat(animatorScheduler.delayedBlock).isNotNull()
InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!)
+ waitForFlyoutToHide()
+
// let the animation start and wait for it to complete
InstrumentationRegistry.getInstrumentation().runOnMainSync {}
PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
@@ -134,6 +150,7 @@
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
+ flyoutController,
onExpandedNoOp,
animatorScheduler,
)
@@ -157,10 +174,16 @@
verify(bubbleStashController, atLeastOnce()).updateTaskbarTouchRegion()
+ waitForFlyoutToShow()
+
// verify the hide bubble animation is pending
assertThat(animatorScheduler.delayedBlock).isNotNull()
- animator.onBubbleBarTouchedWhileAnimating()
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animator.onBubbleBarTouchedWhileAnimating()
+ }
+
+ waitForFlyoutToHide()
assertThat(animatorScheduler.delayedBlock).isNull()
assertThat(bubbleBarView.alpha).isEqualTo(1)
@@ -182,6 +205,7 @@
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
+ flyoutController,
onExpandedNoOp,
animatorScheduler,
)
@@ -227,6 +251,7 @@
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
+ flyoutController,
onExpandedNoOp,
animatorScheduler,
)
@@ -239,10 +264,14 @@
InstrumentationRegistry.getInstrumentation().runOnMainSync {}
PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+ waitForFlyoutToShow()
+
// execute the hide bubble animation
assertThat(animatorScheduler.delayedBlock).isNotNull()
InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!)
+ waitForFlyoutToHide()
+
// wait for the hide animation to start
InstrumentationRegistry.getInstrumentation().runOnMainSync {}
handleAnimator.assertIsRunning()
@@ -273,6 +302,7 @@
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
+ flyoutController,
onExpandedNoOp,
animatorScheduler,
)
@@ -310,6 +340,7 @@
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
+ flyoutController,
onExpanded,
animatorScheduler,
)
@@ -354,6 +385,7 @@
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
+ flyoutController,
onExpanded,
animatorScheduler,
)
@@ -404,6 +436,7 @@
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
+ flyoutController,
onExpanded,
animatorScheduler,
)
@@ -418,6 +451,9 @@
PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
assertThat(animator.isAnimating).isTrue()
+
+ waitForFlyoutToShow()
+
// verify the hide bubble animation is pending
assertThat(animatorScheduler.delayedBlock).isNotNull()
@@ -428,6 +464,8 @@
// verify that the hide animation was canceled
assertThat(animatorScheduler.delayedBlock).isNull()
+ waitForFlyoutToHide()
+
assertThat(handle.alpha).isEqualTo(0)
assertThat(handle.translationY)
.isEqualTo(DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS + BAR_TRANSLATION_Y_FOR_TASKBAR)
@@ -453,6 +491,7 @@
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
+ flyoutController,
onExpandedNoOp,
animatorScheduler,
)
@@ -469,9 +508,13 @@
assertThat(bubbleBarView.alpha).isEqualTo(1)
assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
+ waitForFlyoutToShow()
+
assertThat(animatorScheduler.delayedBlock).isNotNull()
InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!)
+ waitForFlyoutToHide()
+
InstrumentationRegistry.getInstrumentation().runOnMainSync {}
PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
@@ -503,6 +546,7 @@
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
+ flyoutController,
onExpanded,
animatorScheduler,
)
@@ -537,6 +581,7 @@
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
+ flyoutController,
onExpandedNoOp,
animatorScheduler,
)
@@ -553,9 +598,13 @@
assertThat(bubbleBarView.alpha).isEqualTo(1)
assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+ waitForFlyoutToShow()
+
assertThat(animatorScheduler.delayedBlock).isNotNull()
InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!)
+ waitForFlyoutToHide()
+
assertThat(animator.isAnimating).isFalse()
assertThat(bubbleBarView.alpha).isEqualTo(1)
assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
@@ -576,6 +625,7 @@
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
+ flyoutController,
onExpanded,
animatorScheduler,
)
@@ -624,6 +674,7 @@
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
+ flyoutController,
onExpanded,
animatorScheduler,
)
@@ -636,6 +687,8 @@
InstrumentationRegistry.getInstrumentation().runOnMainSync {}
PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+ waitForFlyoutToShow()
+
assertThat(animator.isAnimating).isTrue()
// verify the hide bubble animation is pending
assertThat(animatorScheduler.delayedBlock).isNotNull()
@@ -644,6 +697,8 @@
animator.expandedWhileAnimating()
}
+ waitForFlyoutToHide()
+
// verify that the hide animation was canceled
assertThat(animatorScheduler.delayedBlock).isNull()
@@ -665,6 +720,7 @@
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
+ flyoutController,
onExpandedNoOp,
animatorScheduler,
)
@@ -687,9 +743,13 @@
barAnimator.assertIsRunning()
PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+ waitForFlyoutToShow()
+
assertThat(animatorScheduler.delayedBlock).isNotNull()
InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!)
+ waitForFlyoutToHide()
+
assertThat(animator.isAnimating).isFalse()
// the bubble bar translation y should be back to its initial value
assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
@@ -712,6 +772,7 @@
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
+ flyoutController,
onExpanded,
animatorScheduler,
)
@@ -759,6 +820,7 @@
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
+ flyoutController,
onExpanded,
animatorScheduler,
)
@@ -817,6 +879,7 @@
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
+ flyoutController,
onExpanded,
animatorScheduler,
)
@@ -843,6 +906,8 @@
assertThat(animatorScheduler.delayedBlock).isNotNull()
assertThat(animator.isAnimating).isTrue()
+ waitForFlyoutToShow()
+
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.expandedWhileAnimating()
}
@@ -850,6 +915,8 @@
// verify that the hide animation was canceled
assertThat(animatorScheduler.delayedBlock).isNull()
+ waitForFlyoutToHide()
+
assertThat(animator.isAnimating).isFalse()
assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
assertThat(bubbleBarView.isExpanded).isTrue()
@@ -894,7 +961,7 @@
Color.WHITE,
Path(),
"",
- null,
+ BubbleBarFlyoutMessage(icon = null, title = "title", message = "message"),
)
bubbleView.setBubble(bubble)
bubbleBarView.addView(bubbleView)
@@ -913,6 +980,34 @@
.thenReturn(BAR_TRANSLATION_Y_FOR_TASKBAR)
}
+ private fun setupFlyoutController() {
+ flyoutContainer = FrameLayout(context)
+ val flyoutPositioner =
+ object : BubbleBarFlyoutPositioner {
+ override val isOnLeft = true
+ override val targetTy = 100f
+ override val distanceToCollapsedPosition = PointF(0f, 0f)
+ override val collapsedSize = 30f
+ override val collapsedColor = Color.BLUE
+ override val collapsedElevation = 1f
+ override val distanceToRevealTriangle = 10f
+ }
+ val topBoundaryListener =
+ object : BubbleBarFlyoutController.TopBoundaryListener {
+ override fun extendTopBoundary(space: Int) {}
+
+ override fun resetTopBoundary() {}
+ }
+ val flyoutScheduler = FlyoutScheduler { block -> block.invoke() }
+ flyoutController =
+ BubbleBarFlyoutController(
+ flyoutContainer,
+ flyoutPositioner,
+ topBoundaryListener,
+ flyoutScheduler,
+ )
+ }
+
private fun verifyBubbleBarIsExpandedWithTranslation(ty: Float) {
assertThat(bubbleBarView.visibility).isEqualTo(VISIBLE)
assertThat(bubbleBarView.scaleX).isEqualTo(1)
@@ -921,6 +1016,20 @@
assertThat(bubbleBarView.isExpanded).isTrue()
}
+ private fun waitForFlyoutToShow() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animatorTestRule.advanceTimeBy(300)
+ }
+ assertThat(flyoutView).isNotNull()
+ }
+
+ private fun waitForFlyoutToHide() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animatorTestRule.advanceTimeBy(300)
+ }
+ assertThat(flyoutView).isNull()
+ }
+
private fun <T> PhysicsAnimator<T>.assertIsRunning() {
InstrumentationRegistry.getInstrumentation().runOnMainSync {
assertThat(isRunning()).isTrue()
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt
index 3dd7689..527bdaa 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt
@@ -20,6 +20,7 @@
import android.graphics.Color
import android.graphics.PointF
import android.view.Gravity
+import android.view.View
import android.widget.FrameLayout
import android.widget.TextView
import androidx.core.animation.AnimatorTestRule
@@ -80,7 +81,7 @@
@Test
fun flyoutPosition_left() {
InstrumentationRegistry.getInstrumentation().runOnMainSync {
- flyoutController.setUpFlyout(flyoutMessage)
+ flyoutController.setUpAndShowFlyout(flyoutMessage) {}
assertThat(flyoutContainer.childCount).isEqualTo(1)
val flyout = flyoutContainer.getChildAt(0)
val lp = flyout.layoutParams as FrameLayout.LayoutParams
@@ -93,7 +94,7 @@
fun flyoutPosition_right() {
onLeft = false
InstrumentationRegistry.getInstrumentation().runOnMainSync {
- flyoutController.setUpFlyout(flyoutMessage)
+ flyoutController.setUpAndShowFlyout(flyoutMessage) {}
assertThat(flyoutContainer.childCount).isEqualTo(1)
val flyout = flyoutContainer.getChildAt(0)
val lp = flyout.layoutParams as FrameLayout.LayoutParams
@@ -105,7 +106,7 @@
@Test
fun flyoutMessage() {
InstrumentationRegistry.getInstrumentation().runOnMainSync {
- flyoutController.setUpFlyout(flyoutMessage)
+ flyoutController.setUpAndShowFlyout(flyoutMessage) {}
assertThat(flyoutContainer.childCount).isEqualTo(1)
val flyout = flyoutContainer.getChildAt(0)
val sender = flyout.findViewById<TextView>(R.id.bubble_flyout_title)
@@ -118,9 +119,9 @@
@Test
fun hideFlyout_removedFromContainer() {
InstrumentationRegistry.getInstrumentation().runOnMainSync {
- flyoutController.setUpFlyout(flyoutMessage)
+ flyoutController.setUpAndShowFlyout(flyoutMessage) {}
assertThat(flyoutContainer.childCount).isEqualTo(1)
- flyoutController.hideFlyout {}
+ flyoutController.collapseFlyout {}
animatorTestRule.advanceTimeBy(300)
}
assertThat(flyoutContainer.childCount).isEqualTo(0)
@@ -132,7 +133,7 @@
// boundary
flyoutTy = -50f
InstrumentationRegistry.getInstrumentation().runOnMainSync {
- flyoutController.setUpFlyout(flyoutMessage)
+ flyoutController.setUpAndShowFlyout(flyoutMessage) {}
assertThat(flyoutContainer.childCount).isEqualTo(1)
}
InstrumentationRegistry.getInstrumentation().waitForIdleSync()
@@ -145,7 +146,7 @@
@Test
fun showFlyout_withinBoundary() {
InstrumentationRegistry.getInstrumentation().runOnMainSync {
- flyoutController.setUpFlyout(flyoutMessage)
+ flyoutController.setUpAndShowFlyout(flyoutMessage) {}
assertThat(flyoutContainer.childCount).isEqualTo(1)
}
InstrumentationRegistry.getInstrumentation().waitForIdleSync()
@@ -156,16 +157,30 @@
}
@Test
- fun hideFlyout_resetsTopBoundary() {
+ fun collapseFlyout_resetsTopBoundary() {
InstrumentationRegistry.getInstrumentation().runOnMainSync {
- flyoutController.setUpFlyout(flyoutMessage)
+ flyoutController.setUpAndShowFlyout(flyoutMessage) {}
assertThat(flyoutContainer.childCount).isEqualTo(1)
- flyoutController.hideFlyout {}
+ flyoutController.collapseFlyout {}
animatorTestRule.advanceTimeBy(300)
}
assertThat(topBoundaryListener.topBoundaryReset).isTrue()
}
+ @Test
+ fun cancelFlyout_fadesOutFlyout() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ flyoutController.setUpAndShowFlyout(flyoutMessage) {}
+ assertThat(flyoutContainer.childCount).isEqualTo(1)
+ val flyoutView = flyoutContainer.findViewById<View>(R.id.bubble_bar_flyout_view)
+ assertThat(flyoutView.alpha).isEqualTo(1f)
+ flyoutController.cancelFlyout {}
+ animatorTestRule.advanceTimeBy(300)
+ assertThat(flyoutView.alpha).isEqualTo(0f)
+ }
+ assertThat(topBoundaryListener.topBoundaryReset).isTrue()
+ }
+
class FakeTopBoundaryListener : BubbleBarFlyoutController.TopBoundaryListener {
var topBoundaryExtendedSpace = 0
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/OverviewCommandHelperTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/OverviewCommandHelperTest.kt
index b0db737..0ae710f 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/OverviewCommandHelperTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/OverviewCommandHelperTest.kt
@@ -41,6 +41,7 @@
import org.junit.runner.RunWith
import org.mockito.Mockito.doAnswer
import org.mockito.Mockito.spy
+import org.mockito.Mockito.`when`
import org.mockito.kotlin.any
import org.mockito.kotlin.mock
@@ -55,12 +56,10 @@
private val testScope = TestScope(dispatcher)
private var pendingCallbacksWithDelays = mutableListOf<Long>()
- private lateinit var pendingCommandsToExecute: MutableList<Runnable>
@Suppress("UNCHECKED_CAST")
@Before
fun setup() {
- pendingCommandsToExecute = mutableListOf()
setFlagsRule.setFlags(true, Flags.FLAG_ENABLE_OVERVIEW_COMMAND_HELPER_TIMEOUT)
sut =
@@ -69,8 +68,7 @@
touchInteractionService = mock(),
overviewComponentObserver = mock(),
taskAnimationManager = mock(),
- dispatcherProvider = TestDispatcherProvider(dispatcher),
- uiExecutor = { runnable -> pendingCommandsToExecute += runnable },
+ dispatcherProvider = TestDispatcherProvider(dispatcher)
)
)
@@ -96,21 +94,12 @@
pendingCallbacksWithDelays.add(delayInMillis)
}
- /**
- * This function runs all the pending commands from the Executor for testing purposes. Replacing
- * the uiExecutor allows the test to execute the command queue manually, making it possible to
- * assert each state of the commands in the queue individually.
- */
- private fun executePendingCommands() = pendingCommandsToExecute.forEach { it.run() }
-
@Test
fun whenFirstCommandIsAdded_executeCommandImmediately() =
testScope.runTest {
// Add command to queue
val commandInfo: CommandInfo = sut.addCommand(CommandType.HOME)!!
assertThat(commandInfo.status).isEqualTo(CommandStatus.IDLE)
- executePendingCommands()
- assertThat(commandInfo.status).isEqualTo(CommandStatus.PROCESSING)
runCurrent()
assertThat(commandInfo.status).isEqualTo(CommandStatus.COMPLETED)
}
@@ -125,7 +114,7 @@
val commandInfo: CommandInfo = sut.addCommand(commandType)!!
assertThat(commandInfo.status).isEqualTo(CommandStatus.IDLE)
- executePendingCommands()
+ runCurrent()
assertThat(commandInfo.status).isEqualTo(CommandStatus.PROCESSING)
advanceTimeBy(200L)
@@ -146,14 +135,12 @@
val commandInfo2: CommandInfo = sut.addCommand(commandType2)!!
assertThat(commandInfo2.status).isEqualTo(CommandStatus.IDLE)
- executePendingCommands()
+ runCurrent()
assertThat(commandInfo1.status).isEqualTo(CommandStatus.PROCESSING)
assertThat(commandInfo2.status).isEqualTo(CommandStatus.IDLE)
advanceTimeBy(101L)
assertThat(commandInfo1.status).isEqualTo(CommandStatus.COMPLETED)
-
- executePendingCommands()
assertThat(commandInfo2.status).isEqualTo(CommandStatus.PROCESSING)
advanceTimeBy(101L)
@@ -174,14 +161,12 @@
val commandInfo2: CommandInfo = sut.addCommand(commandType2)!!
assertThat(commandInfo2.status).isEqualTo(CommandStatus.IDLE)
- executePendingCommands()
+ runCurrent()
assertThat(commandInfo1.status).isEqualTo(CommandStatus.PROCESSING)
assertThat(commandInfo2.status).isEqualTo(CommandStatus.IDLE)
advanceTimeBy(QUEUE_TIMEOUT)
assertThat(commandInfo1.status).isEqualTo(CommandStatus.CANCELED)
-
- executePendingCommands()
assertThat(commandInfo2.status).isEqualTo(CommandStatus.PROCESSING)
advanceTimeBy(101)