Merge "Wire up flyout to new bubble animation" into main

This commit is contained in:
Liran Binyamin
2024-10-21 12:20:23 +00:00
committed by Android (Google) Code Review
9 changed files with 248 additions and 51 deletions

View File

@@ -19,6 +19,7 @@ package com.android.launcher3.taskbar.bubbles.animation
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.BubbleBarBubble
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 @@ class BubbleBarViewAnimatorTest {
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 @@ class BubbleBarViewAnimatorTest {
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
flyoutController,
onExpandedNoOp,
animatorScheduler,
)
@@ -106,10 +118,14 @@ class BubbleBarViewAnimatorTest {
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 @@ class BubbleBarViewAnimatorTest {
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
flyoutController,
onExpandedNoOp,
animatorScheduler,
)
@@ -157,10 +174,16 @@ class BubbleBarViewAnimatorTest {
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 @@ class BubbleBarViewAnimatorTest {
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
flyoutController,
onExpandedNoOp,
animatorScheduler,
)
@@ -227,6 +251,7 @@ class BubbleBarViewAnimatorTest {
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
flyoutController,
onExpandedNoOp,
animatorScheduler,
)
@@ -239,10 +264,14 @@ class BubbleBarViewAnimatorTest {
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 @@ class BubbleBarViewAnimatorTest {
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
flyoutController,
onExpandedNoOp,
animatorScheduler,
)
@@ -310,6 +340,7 @@ class BubbleBarViewAnimatorTest {
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
flyoutController,
onExpanded,
animatorScheduler,
)
@@ -354,6 +385,7 @@ class BubbleBarViewAnimatorTest {
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
flyoutController,
onExpanded,
animatorScheduler,
)
@@ -404,6 +436,7 @@ class BubbleBarViewAnimatorTest {
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
flyoutController,
onExpanded,
animatorScheduler,
)
@@ -418,6 +451,9 @@ class BubbleBarViewAnimatorTest {
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 @@ class BubbleBarViewAnimatorTest {
// 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 @@ class BubbleBarViewAnimatorTest {
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
flyoutController,
onExpandedNoOp,
animatorScheduler,
)
@@ -469,9 +508,13 @@ class BubbleBarViewAnimatorTest {
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 @@ class BubbleBarViewAnimatorTest {
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
flyoutController,
onExpanded,
animatorScheduler,
)
@@ -537,6 +581,7 @@ class BubbleBarViewAnimatorTest {
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
flyoutController,
onExpandedNoOp,
animatorScheduler,
)
@@ -553,9 +598,13 @@ class BubbleBarViewAnimatorTest {
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 @@ class BubbleBarViewAnimatorTest {
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
flyoutController,
onExpanded,
animatorScheduler,
)
@@ -624,6 +674,7 @@ class BubbleBarViewAnimatorTest {
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
flyoutController,
onExpanded,
animatorScheduler,
)
@@ -636,6 +687,8 @@ class BubbleBarViewAnimatorTest {
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 @@ class BubbleBarViewAnimatorTest {
animator.expandedWhileAnimating()
}
waitForFlyoutToHide()
// verify that the hide animation was canceled
assertThat(animatorScheduler.delayedBlock).isNull()
@@ -665,6 +720,7 @@ class BubbleBarViewAnimatorTest {
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
flyoutController,
onExpandedNoOp,
animatorScheduler,
)
@@ -687,9 +743,13 @@ class BubbleBarViewAnimatorTest {
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 @@ class BubbleBarViewAnimatorTest {
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
flyoutController,
onExpanded,
animatorScheduler,
)
@@ -759,6 +820,7 @@ class BubbleBarViewAnimatorTest {
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
flyoutController,
onExpanded,
animatorScheduler,
)
@@ -817,6 +879,7 @@ class BubbleBarViewAnimatorTest {
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
flyoutController,
onExpanded,
animatorScheduler,
)
@@ -843,6 +906,8 @@ class BubbleBarViewAnimatorTest {
assertThat(animatorScheduler.delayedBlock).isNotNull()
assertThat(animator.isAnimating).isTrue()
waitForFlyoutToShow()
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.expandedWhileAnimating()
}
@@ -850,6 +915,8 @@ class BubbleBarViewAnimatorTest {
// 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 @@ class BubbleBarViewAnimatorTest {
Color.WHITE,
Path(),
"",
null,
BubbleBarFlyoutMessage(icon = null, title = "title", message = "message"),
)
bubbleView.setBubble(bubble)
bubbleBarView.addView(bubbleView)
@@ -913,6 +980,34 @@ class BubbleBarViewAnimatorTest {
.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 @@ class BubbleBarViewAnimatorTest {
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()

View File

@@ -20,6 +20,7 @@ import android.content.Context
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 @@ class BubbleBarFlyoutControllerTest {
@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 @@ class BubbleBarFlyoutControllerTest {
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 @@ class BubbleBarFlyoutControllerTest {
@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 @@ class BubbleBarFlyoutControllerTest {
@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 @@ class BubbleBarFlyoutControllerTest {
// boundary
flyoutTy = -50f
InstrumentationRegistry.getInstrumentation().runOnMainSync {
flyoutController.setUpFlyout(flyoutMessage)
flyoutController.setUpAndShowFlyout(flyoutMessage) {}
assertThat(flyoutContainer.childCount).isEqualTo(1)
}
InstrumentationRegistry.getInstrumentation().waitForIdleSync()
@@ -145,7 +146,7 @@ class BubbleBarFlyoutControllerTest {
@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 @@ class BubbleBarFlyoutControllerTest {
}
@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