Loading quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java +7 −0 Original line number Diff line number Diff line Loading @@ -173,6 +173,13 @@ public class BubbleBarViewController { } } /** Notifies that the stash state is changing. */ public void onStashStateChanging() { if (isAnimatingNewBubble()) { mBubbleBarViewAnimator.onStashStateChangingWhileAnimating(); } } // // The below animators are exposed to BubbleStashController so it can manage the stashing // animation. Loading quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java +30 −0 Original line number Diff line number Diff line Loading @@ -250,6 +250,11 @@ public class BubbleStashController { && !mBubblesShowingOnHome && !mBubblesShowingOnOverview; if (mIsStashed != isStashed) { // notify the view controller that the stash state is about to change so that it can // cancel an ongoing animation if there is one. // note that this has to be called before updating mIsStashed with the new value, // otherwise interrupting an ongoing animation may update it again with the wrong state mBarViewController.onStashStateChanging(); mIsStashed = isStashed; if (mAnimator != null) { mAnimator.cancel(); Loading Loading @@ -423,4 +428,29 @@ public class BubbleStashController { mIsStashed = true; onIsStashedChanged(); } /** * Updates the values of the internal animators after the new bubble animation was interrupted * * @param isStashed whether the current state should be stashed * @param bubbleBarTranslationY the current bubble bar translation. this is only used if the * bubble bar is showing to ensure that the stash animator runs * smoothly. */ public void onNewBubbleAnimationInterrupted(boolean isStashed, float bubbleBarTranslationY) { if (isStashed) { mBubbleStashedHandleAlpha.setValue(1); mIconAlphaForStash.setValue(0); mIconScaleForStash.updateValue(STASHED_BAR_SCALE); mIconTranslationYForStash.updateValue(getStashTranslation()); } else { mBubbleStashedHandleAlpha.setValue(0); mHandleViewController.setTranslationYForSwipe(0); mIconAlphaForStash.setValue(1); mIconScaleForStash.updateValue(1); mIconTranslationYForStash.updateValue(bubbleBarTranslationY); } mIsStashed = isStashed; onIsStashedChanged(); } } quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt +28 −3 Original line number Diff line number Diff line Loading @@ -179,7 +179,17 @@ constructor( } } } animator.addEndListener { _, _, _, _, _, _, _ -> animator.addEndListener { _, _, _, canceled, _, _, _ -> // if the show animation was canceled, also cancel the hide animation. this is typically // canceled in this class, but could potentially be canceled elsewhere. if (canceled) { val hideAnimation = animatingBubble?.hideAnimation ?: return@addEndListener scheduler.cancel(hideAnimation) animatingBubble = null bubbleBarView.onAnimatingBubbleCompleted() bubbleBarView.relativePivotY = 1f return@addEndListener } // the bubble bar is now fully settled in. update taskbar touch region so it's touchable bubbleStashController.updateTaskbarTouchRegion() } Loading @@ -200,6 +210,7 @@ constructor( * 3. The third part is the overshoot. The handle is made fully visible. */ private fun buildHideAnimation() = Runnable { if (animatingBubble == null) return@Runnable val offset = bubbleStashController.diffBetweenHandleAndBarCenters val stashedHandleTranslationY = bubbleStashController.stashedHandleTranslationForNewBubbleAnimation Loading Loading @@ -238,9 +249,9 @@ constructor( } } } animator.addEndListener { _, _, _, _, _, _, _ -> animator.addEndListener { _, _, _, canceled, _, _, _ -> animatingBubble = null bubbleStashController.stashBubbleBarImmediate() if (!canceled) bubbleStashController.stashBubbleBarImmediate() bubbleBarView.onAnimatingBubbleCompleted() bubbleBarView.relativePivotY = 1f bubbleStashController.updateTaskbarTouchRegion() Loading @@ -256,4 +267,18 @@ constructor( bubbleBarView.relativePivotY = 1f animatingBubble = null } /** Notifies the animator that the taskbar area was touched during an animation. */ fun onStashStateChangingWhileAnimating() { val hideAnimation = animatingBubble?.hideAnimation ?: return scheduler.cancel(hideAnimation) animatingBubble = null bubbleStashController.stashedHandlePhysicsAnimator.cancel() bubbleBarView.onAnimatingBubbleCompleted() bubbleBarView.relativePivotY = 1f bubbleStashController.onNewBubbleAnimationInterrupted( /* isStashed= */ bubbleBarView.alpha == 0f, bubbleBarView.translationY ) } } quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt +160 −68 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.any import org.mockito.kotlin.mock import org.mockito.kotlin.verify import org.mockito.kotlin.whenever Loading @@ -52,47 +53,23 @@ import org.mockito.kotlin.whenever class BubbleBarViewAnimatorTest { private val context = ApplicationProvider.getApplicationContext<Context>() private val animatorScheduler = TestBubbleBarViewAnimatorScheduler() private lateinit var animatorScheduler: TestBubbleBarViewAnimatorScheduler private lateinit var overflowView: BubbleView private lateinit var bubbleView: BubbleView private lateinit var bubble: BubbleBarBubble private lateinit var bubbleBarView: BubbleBarView private lateinit var bubbleStashController: BubbleStashController @Before fun setUp() { animatorScheduler = TestBubbleBarViewAnimatorScheduler() PhysicsAnimatorTestUtils.prepareForTest() } @Test fun animateBubbleInForStashed() { lateinit var overflowView: BubbleView lateinit var bubbleView: BubbleView lateinit var bubble: BubbleBarBubble val bubbleBarView = BubbleBarView(context) InstrumentationRegistry.getInstrumentation().runOnMainSync { bubbleBarView.layoutParams = FrameLayout.LayoutParams(0, 0) val inflater = LayoutInflater.from(context) val bitmap = ColorDrawable(Color.WHITE).toBitmap(width = 20, height = 20) overflowView = inflater.inflate(R.layout.bubblebar_item_view, bubbleBarView, false) as BubbleView overflowView.setOverflow(BubbleBarOverflow(overflowView), bitmap) bubbleBarView.addView(overflowView) val bubbleInfo = BubbleInfo("key", 0, null, null, 0, context.packageName, null, false) bubbleView = inflater.inflate(R.layout.bubblebar_item_view, bubbleBarView, false) as BubbleView bubble = BubbleBarBubble(bubbleInfo, bubbleView, bitmap, bitmap, Color.WHITE, Path(), "") bubbleView.setBubble(bubble) bubbleBarView.addView(bubbleView) } InstrumentationRegistry.getInstrumentation().waitForIdleSync() val bubbleStashController = mock<BubbleStashController>() whenever(bubbleStashController.isStashed).thenReturn(true) whenever(bubbleStashController.diffBetweenHandleAndBarCenters) .thenReturn(DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS) whenever(bubbleStashController.stashedHandleTranslationForNewBubbleAnimation) .thenReturn(HANDLE_TRANSLATION) whenever(bubbleStashController.bubbleBarTranslationYForTaskbar) .thenReturn(BAR_TRANSLATION_Y_FOR_TASKBAR) setUpBubbleBar() setUpBubbleStashController() val handle = View(context) val handleAnimator = PhysicsAnimator.getInstance(handle) Loading @@ -106,7 +83,7 @@ class BubbleBarViewAnimatorTest { } // let the animation start and wait for it to complete InstrumentationRegistry.getInstrumentation().waitForIdleSync() InstrumentationRegistry.getInstrumentation().runOnMainSync {} PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y) assertThat(handle.alpha).isEqualTo(0) Loading @@ -123,7 +100,7 @@ class BubbleBarViewAnimatorTest { InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!) // let the animation start and wait for it to complete InstrumentationRegistry.getInstrumentation().waitForIdleSync() InstrumentationRegistry.getInstrumentation().runOnMainSync {} PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y) assertThat(handle.alpha).isEqualTo(1) Loading @@ -135,38 +112,8 @@ class BubbleBarViewAnimatorTest { @Test fun animateBubbleInForStashed_tapAnimatingBubble() { lateinit var overflowView: BubbleView lateinit var bubbleView: BubbleView lateinit var bubble: BubbleBarBubble val bubbleBarView = BubbleBarView(context) InstrumentationRegistry.getInstrumentation().runOnMainSync { bubbleBarView.layoutParams = FrameLayout.LayoutParams(0, 0) val inflater = LayoutInflater.from(context) val bitmap = ColorDrawable(Color.WHITE).toBitmap(width = 20, height = 20) overflowView = inflater.inflate(R.layout.bubblebar_item_view, bubbleBarView, false) as BubbleView overflowView.setOverflow(BubbleBarOverflow(overflowView), bitmap) bubbleBarView.addView(overflowView) val bubbleInfo = BubbleInfo("key", 0, null, null, 0, context.packageName, null, false) bubbleView = inflater.inflate(R.layout.bubblebar_item_view, bubbleBarView, false) as BubbleView bubble = BubbleBarBubble(bubbleInfo, bubbleView, bitmap, bitmap, Color.WHITE, Path(), "") bubbleView.setBubble(bubble) bubbleBarView.addView(bubbleView) } InstrumentationRegistry.getInstrumentation().waitForIdleSync() val bubbleStashController = mock<BubbleStashController>() whenever(bubbleStashController.isStashed).thenReturn(true) whenever(bubbleStashController.diffBetweenHandleAndBarCenters) .thenReturn(DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS) whenever(bubbleStashController.stashedHandleTranslationForNewBubbleAnimation) .thenReturn(HANDLE_TRANSLATION) whenever(bubbleStashController.bubbleBarTranslationYForTaskbar) .thenReturn(BAR_TRANSLATION_Y_FOR_TASKBAR) setUpBubbleBar() setUpBubbleStashController() val handle = View(context) val handleAnimator = PhysicsAnimator.getInstance(handle) Loading @@ -180,7 +127,7 @@ class BubbleBarViewAnimatorTest { } // let the animation start and wait for it to complete InstrumentationRegistry.getInstrumentation().waitForIdleSync() InstrumentationRegistry.getInstrumentation().runOnMainSync {} PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y) assertThat(handle.alpha).isEqualTo(0) Loading @@ -206,6 +153,151 @@ class BubbleBarViewAnimatorTest { assertThat(bubbleBarView.isAnimatingNewBubble).isFalse() } @Test fun animateBubbleInForStashed_touchTaskbarArea_whileShowing() { setUpBubbleBar() setUpBubbleStashController() val handle = View(context) val handleAnimator = PhysicsAnimator.getInstance(handle) whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator) val animator = BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler) InstrumentationRegistry.getInstrumentation().runOnMainSync { animator.animateBubbleInForStashed(bubble) } // wait for the animation to start InstrumentationRegistry.getInstrumentation().runOnMainSync {} PhysicsAnimatorTestUtils.blockUntilFirstAnimationFrameWhereTrue(handleAnimator) { true } assertThat(handleAnimator.isRunning()).isTrue() assertThat(bubbleBarView.isAnimatingNewBubble).isTrue() // verify the hide bubble animation is pending assertThat(animatorScheduler.delayedBlock).isNotNull() InstrumentationRegistry.getInstrumentation().runOnMainSync { animator.onStashStateChangingWhileAnimating() } // verify that the hide animation was canceled assertThat(animatorScheduler.delayedBlock).isNull() assertThat(bubbleBarView.isAnimatingNewBubble).isFalse() verify(bubbleStashController).onNewBubbleAnimationInterrupted(any(), any()) // PhysicsAnimatorTestUtils posts the cancellation to the main thread so we need to wait // again InstrumentationRegistry.getInstrumentation().waitForIdleSync() assertThat(handleAnimator.isRunning()).isFalse() } @Test fun animateBubbleInForStashed_touchTaskbarArea_whileHiding() { setUpBubbleBar() setUpBubbleStashController() val handle = View(context) val handleAnimator = PhysicsAnimator.getInstance(handle) whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator) val animator = BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler) InstrumentationRegistry.getInstrumentation().runOnMainSync { animator.animateBubbleInForStashed(bubble) } // let the animation start and wait for it to complete InstrumentationRegistry.getInstrumentation().runOnMainSync {} PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y) // execute the hide bubble animation assertThat(animatorScheduler.delayedBlock).isNotNull() InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!) // wait for the hide animation to start InstrumentationRegistry.getInstrumentation().runOnMainSync {} assertThat(handleAnimator.isRunning()).isTrue() InstrumentationRegistry.getInstrumentation().runOnMainSync { animator.onStashStateChangingWhileAnimating() } assertThat(bubbleBarView.isAnimatingNewBubble).isFalse() verify(bubbleStashController).onNewBubbleAnimationInterrupted(any(), any()) // PhysicsAnimatorTestUtils posts the cancellation to the main thread so we need to wait // again InstrumentationRegistry.getInstrumentation().waitForIdleSync() assertThat(handleAnimator.isRunning()).isFalse() } @Test fun animateBubbleInForStashed_showAnimationCanceled() { setUpBubbleBar() setUpBubbleStashController() val handle = View(context) val handleAnimator = PhysicsAnimator.getInstance(handle) whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator) val animator = BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler) InstrumentationRegistry.getInstrumentation().runOnMainSync { animator.animateBubbleInForStashed(bubble) } // wait for the animation to start InstrumentationRegistry.getInstrumentation().runOnMainSync {} PhysicsAnimatorTestUtils.blockUntilFirstAnimationFrameWhereTrue(handleAnimator) { true } assertThat(handleAnimator.isRunning()).isTrue() assertThat(bubbleBarView.isAnimatingNewBubble).isTrue() assertThat(animatorScheduler.delayedBlock).isNotNull() handleAnimator.cancel() assertThat(handleAnimator.isRunning()).isFalse() assertThat(bubbleBarView.isAnimatingNewBubble).isFalse() assertThat(animatorScheduler.delayedBlock).isNull() } private fun setUpBubbleBar() { bubbleBarView = BubbleBarView(context) InstrumentationRegistry.getInstrumentation().runOnMainSync { bubbleBarView.layoutParams = FrameLayout.LayoutParams(0, 0) val inflater = LayoutInflater.from(context) val bitmap = ColorDrawable(Color.WHITE).toBitmap(width = 20, height = 20) overflowView = inflater.inflate(R.layout.bubblebar_item_view, bubbleBarView, false) as BubbleView overflowView.setOverflow(BubbleBarOverflow(overflowView), bitmap) bubbleBarView.addView(overflowView) val bubbleInfo = BubbleInfo("key", 0, null, null, 0, context.packageName, null, false) bubbleView = inflater.inflate(R.layout.bubblebar_item_view, bubbleBarView, false) as BubbleView bubble = BubbleBarBubble(bubbleInfo, bubbleView, bitmap, bitmap, Color.WHITE, Path(), "") bubbleView.setBubble(bubble) bubbleBarView.addView(bubbleView) } InstrumentationRegistry.getInstrumentation().waitForIdleSync() } private fun setUpBubbleStashController() { bubbleStashController = mock<BubbleStashController>() whenever(bubbleStashController.isStashed).thenReturn(true) whenever(bubbleStashController.diffBetweenHandleAndBarCenters) .thenReturn(DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS) whenever(bubbleStashController.stashedHandleTranslationForNewBubbleAnimation) .thenReturn(HANDLE_TRANSLATION) whenever(bubbleStashController.bubbleBarTranslationYForTaskbar) .thenReturn(BAR_TRANSLATION_Y_FOR_TASKBAR) } private class TestBubbleBarViewAnimatorScheduler : BubbleBarViewAnimator.Scheduler { var delayedBlock: Runnable? = null Loading Loading
quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java +7 −0 Original line number Diff line number Diff line Loading @@ -173,6 +173,13 @@ public class BubbleBarViewController { } } /** Notifies that the stash state is changing. */ public void onStashStateChanging() { if (isAnimatingNewBubble()) { mBubbleBarViewAnimator.onStashStateChangingWhileAnimating(); } } // // The below animators are exposed to BubbleStashController so it can manage the stashing // animation. Loading
quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java +30 −0 Original line number Diff line number Diff line Loading @@ -250,6 +250,11 @@ public class BubbleStashController { && !mBubblesShowingOnHome && !mBubblesShowingOnOverview; if (mIsStashed != isStashed) { // notify the view controller that the stash state is about to change so that it can // cancel an ongoing animation if there is one. // note that this has to be called before updating mIsStashed with the new value, // otherwise interrupting an ongoing animation may update it again with the wrong state mBarViewController.onStashStateChanging(); mIsStashed = isStashed; if (mAnimator != null) { mAnimator.cancel(); Loading Loading @@ -423,4 +428,29 @@ public class BubbleStashController { mIsStashed = true; onIsStashedChanged(); } /** * Updates the values of the internal animators after the new bubble animation was interrupted * * @param isStashed whether the current state should be stashed * @param bubbleBarTranslationY the current bubble bar translation. this is only used if the * bubble bar is showing to ensure that the stash animator runs * smoothly. */ public void onNewBubbleAnimationInterrupted(boolean isStashed, float bubbleBarTranslationY) { if (isStashed) { mBubbleStashedHandleAlpha.setValue(1); mIconAlphaForStash.setValue(0); mIconScaleForStash.updateValue(STASHED_BAR_SCALE); mIconTranslationYForStash.updateValue(getStashTranslation()); } else { mBubbleStashedHandleAlpha.setValue(0); mHandleViewController.setTranslationYForSwipe(0); mIconAlphaForStash.setValue(1); mIconScaleForStash.updateValue(1); mIconTranslationYForStash.updateValue(bubbleBarTranslationY); } mIsStashed = isStashed; onIsStashedChanged(); } }
quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt +28 −3 Original line number Diff line number Diff line Loading @@ -179,7 +179,17 @@ constructor( } } } animator.addEndListener { _, _, _, _, _, _, _ -> animator.addEndListener { _, _, _, canceled, _, _, _ -> // if the show animation was canceled, also cancel the hide animation. this is typically // canceled in this class, but could potentially be canceled elsewhere. if (canceled) { val hideAnimation = animatingBubble?.hideAnimation ?: return@addEndListener scheduler.cancel(hideAnimation) animatingBubble = null bubbleBarView.onAnimatingBubbleCompleted() bubbleBarView.relativePivotY = 1f return@addEndListener } // the bubble bar is now fully settled in. update taskbar touch region so it's touchable bubbleStashController.updateTaskbarTouchRegion() } Loading @@ -200,6 +210,7 @@ constructor( * 3. The third part is the overshoot. The handle is made fully visible. */ private fun buildHideAnimation() = Runnable { if (animatingBubble == null) return@Runnable val offset = bubbleStashController.diffBetweenHandleAndBarCenters val stashedHandleTranslationY = bubbleStashController.stashedHandleTranslationForNewBubbleAnimation Loading Loading @@ -238,9 +249,9 @@ constructor( } } } animator.addEndListener { _, _, _, _, _, _, _ -> animator.addEndListener { _, _, _, canceled, _, _, _ -> animatingBubble = null bubbleStashController.stashBubbleBarImmediate() if (!canceled) bubbleStashController.stashBubbleBarImmediate() bubbleBarView.onAnimatingBubbleCompleted() bubbleBarView.relativePivotY = 1f bubbleStashController.updateTaskbarTouchRegion() Loading @@ -256,4 +267,18 @@ constructor( bubbleBarView.relativePivotY = 1f animatingBubble = null } /** Notifies the animator that the taskbar area was touched during an animation. */ fun onStashStateChangingWhileAnimating() { val hideAnimation = animatingBubble?.hideAnimation ?: return scheduler.cancel(hideAnimation) animatingBubble = null bubbleStashController.stashedHandlePhysicsAnimator.cancel() bubbleBarView.onAnimatingBubbleCompleted() bubbleBarView.relativePivotY = 1f bubbleStashController.onNewBubbleAnimationInterrupted( /* isStashed= */ bubbleBarView.alpha == 0f, bubbleBarView.translationY ) } }
quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt +160 −68 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.any import org.mockito.kotlin.mock import org.mockito.kotlin.verify import org.mockito.kotlin.whenever Loading @@ -52,47 +53,23 @@ import org.mockito.kotlin.whenever class BubbleBarViewAnimatorTest { private val context = ApplicationProvider.getApplicationContext<Context>() private val animatorScheduler = TestBubbleBarViewAnimatorScheduler() private lateinit var animatorScheduler: TestBubbleBarViewAnimatorScheduler private lateinit var overflowView: BubbleView private lateinit var bubbleView: BubbleView private lateinit var bubble: BubbleBarBubble private lateinit var bubbleBarView: BubbleBarView private lateinit var bubbleStashController: BubbleStashController @Before fun setUp() { animatorScheduler = TestBubbleBarViewAnimatorScheduler() PhysicsAnimatorTestUtils.prepareForTest() } @Test fun animateBubbleInForStashed() { lateinit var overflowView: BubbleView lateinit var bubbleView: BubbleView lateinit var bubble: BubbleBarBubble val bubbleBarView = BubbleBarView(context) InstrumentationRegistry.getInstrumentation().runOnMainSync { bubbleBarView.layoutParams = FrameLayout.LayoutParams(0, 0) val inflater = LayoutInflater.from(context) val bitmap = ColorDrawable(Color.WHITE).toBitmap(width = 20, height = 20) overflowView = inflater.inflate(R.layout.bubblebar_item_view, bubbleBarView, false) as BubbleView overflowView.setOverflow(BubbleBarOverflow(overflowView), bitmap) bubbleBarView.addView(overflowView) val bubbleInfo = BubbleInfo("key", 0, null, null, 0, context.packageName, null, false) bubbleView = inflater.inflate(R.layout.bubblebar_item_view, bubbleBarView, false) as BubbleView bubble = BubbleBarBubble(bubbleInfo, bubbleView, bitmap, bitmap, Color.WHITE, Path(), "") bubbleView.setBubble(bubble) bubbleBarView.addView(bubbleView) } InstrumentationRegistry.getInstrumentation().waitForIdleSync() val bubbleStashController = mock<BubbleStashController>() whenever(bubbleStashController.isStashed).thenReturn(true) whenever(bubbleStashController.diffBetweenHandleAndBarCenters) .thenReturn(DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS) whenever(bubbleStashController.stashedHandleTranslationForNewBubbleAnimation) .thenReturn(HANDLE_TRANSLATION) whenever(bubbleStashController.bubbleBarTranslationYForTaskbar) .thenReturn(BAR_TRANSLATION_Y_FOR_TASKBAR) setUpBubbleBar() setUpBubbleStashController() val handle = View(context) val handleAnimator = PhysicsAnimator.getInstance(handle) Loading @@ -106,7 +83,7 @@ class BubbleBarViewAnimatorTest { } // let the animation start and wait for it to complete InstrumentationRegistry.getInstrumentation().waitForIdleSync() InstrumentationRegistry.getInstrumentation().runOnMainSync {} PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y) assertThat(handle.alpha).isEqualTo(0) Loading @@ -123,7 +100,7 @@ class BubbleBarViewAnimatorTest { InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!) // let the animation start and wait for it to complete InstrumentationRegistry.getInstrumentation().waitForIdleSync() InstrumentationRegistry.getInstrumentation().runOnMainSync {} PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y) assertThat(handle.alpha).isEqualTo(1) Loading @@ -135,38 +112,8 @@ class BubbleBarViewAnimatorTest { @Test fun animateBubbleInForStashed_tapAnimatingBubble() { lateinit var overflowView: BubbleView lateinit var bubbleView: BubbleView lateinit var bubble: BubbleBarBubble val bubbleBarView = BubbleBarView(context) InstrumentationRegistry.getInstrumentation().runOnMainSync { bubbleBarView.layoutParams = FrameLayout.LayoutParams(0, 0) val inflater = LayoutInflater.from(context) val bitmap = ColorDrawable(Color.WHITE).toBitmap(width = 20, height = 20) overflowView = inflater.inflate(R.layout.bubblebar_item_view, bubbleBarView, false) as BubbleView overflowView.setOverflow(BubbleBarOverflow(overflowView), bitmap) bubbleBarView.addView(overflowView) val bubbleInfo = BubbleInfo("key", 0, null, null, 0, context.packageName, null, false) bubbleView = inflater.inflate(R.layout.bubblebar_item_view, bubbleBarView, false) as BubbleView bubble = BubbleBarBubble(bubbleInfo, bubbleView, bitmap, bitmap, Color.WHITE, Path(), "") bubbleView.setBubble(bubble) bubbleBarView.addView(bubbleView) } InstrumentationRegistry.getInstrumentation().waitForIdleSync() val bubbleStashController = mock<BubbleStashController>() whenever(bubbleStashController.isStashed).thenReturn(true) whenever(bubbleStashController.diffBetweenHandleAndBarCenters) .thenReturn(DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS) whenever(bubbleStashController.stashedHandleTranslationForNewBubbleAnimation) .thenReturn(HANDLE_TRANSLATION) whenever(bubbleStashController.bubbleBarTranslationYForTaskbar) .thenReturn(BAR_TRANSLATION_Y_FOR_TASKBAR) setUpBubbleBar() setUpBubbleStashController() val handle = View(context) val handleAnimator = PhysicsAnimator.getInstance(handle) Loading @@ -180,7 +127,7 @@ class BubbleBarViewAnimatorTest { } // let the animation start and wait for it to complete InstrumentationRegistry.getInstrumentation().waitForIdleSync() InstrumentationRegistry.getInstrumentation().runOnMainSync {} PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y) assertThat(handle.alpha).isEqualTo(0) Loading @@ -206,6 +153,151 @@ class BubbleBarViewAnimatorTest { assertThat(bubbleBarView.isAnimatingNewBubble).isFalse() } @Test fun animateBubbleInForStashed_touchTaskbarArea_whileShowing() { setUpBubbleBar() setUpBubbleStashController() val handle = View(context) val handleAnimator = PhysicsAnimator.getInstance(handle) whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator) val animator = BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler) InstrumentationRegistry.getInstrumentation().runOnMainSync { animator.animateBubbleInForStashed(bubble) } // wait for the animation to start InstrumentationRegistry.getInstrumentation().runOnMainSync {} PhysicsAnimatorTestUtils.blockUntilFirstAnimationFrameWhereTrue(handleAnimator) { true } assertThat(handleAnimator.isRunning()).isTrue() assertThat(bubbleBarView.isAnimatingNewBubble).isTrue() // verify the hide bubble animation is pending assertThat(animatorScheduler.delayedBlock).isNotNull() InstrumentationRegistry.getInstrumentation().runOnMainSync { animator.onStashStateChangingWhileAnimating() } // verify that the hide animation was canceled assertThat(animatorScheduler.delayedBlock).isNull() assertThat(bubbleBarView.isAnimatingNewBubble).isFalse() verify(bubbleStashController).onNewBubbleAnimationInterrupted(any(), any()) // PhysicsAnimatorTestUtils posts the cancellation to the main thread so we need to wait // again InstrumentationRegistry.getInstrumentation().waitForIdleSync() assertThat(handleAnimator.isRunning()).isFalse() } @Test fun animateBubbleInForStashed_touchTaskbarArea_whileHiding() { setUpBubbleBar() setUpBubbleStashController() val handle = View(context) val handleAnimator = PhysicsAnimator.getInstance(handle) whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator) val animator = BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler) InstrumentationRegistry.getInstrumentation().runOnMainSync { animator.animateBubbleInForStashed(bubble) } // let the animation start and wait for it to complete InstrumentationRegistry.getInstrumentation().runOnMainSync {} PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y) // execute the hide bubble animation assertThat(animatorScheduler.delayedBlock).isNotNull() InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!) // wait for the hide animation to start InstrumentationRegistry.getInstrumentation().runOnMainSync {} assertThat(handleAnimator.isRunning()).isTrue() InstrumentationRegistry.getInstrumentation().runOnMainSync { animator.onStashStateChangingWhileAnimating() } assertThat(bubbleBarView.isAnimatingNewBubble).isFalse() verify(bubbleStashController).onNewBubbleAnimationInterrupted(any(), any()) // PhysicsAnimatorTestUtils posts the cancellation to the main thread so we need to wait // again InstrumentationRegistry.getInstrumentation().waitForIdleSync() assertThat(handleAnimator.isRunning()).isFalse() } @Test fun animateBubbleInForStashed_showAnimationCanceled() { setUpBubbleBar() setUpBubbleStashController() val handle = View(context) val handleAnimator = PhysicsAnimator.getInstance(handle) whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator) val animator = BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler) InstrumentationRegistry.getInstrumentation().runOnMainSync { animator.animateBubbleInForStashed(bubble) } // wait for the animation to start InstrumentationRegistry.getInstrumentation().runOnMainSync {} PhysicsAnimatorTestUtils.blockUntilFirstAnimationFrameWhereTrue(handleAnimator) { true } assertThat(handleAnimator.isRunning()).isTrue() assertThat(bubbleBarView.isAnimatingNewBubble).isTrue() assertThat(animatorScheduler.delayedBlock).isNotNull() handleAnimator.cancel() assertThat(handleAnimator.isRunning()).isFalse() assertThat(bubbleBarView.isAnimatingNewBubble).isFalse() assertThat(animatorScheduler.delayedBlock).isNull() } private fun setUpBubbleBar() { bubbleBarView = BubbleBarView(context) InstrumentationRegistry.getInstrumentation().runOnMainSync { bubbleBarView.layoutParams = FrameLayout.LayoutParams(0, 0) val inflater = LayoutInflater.from(context) val bitmap = ColorDrawable(Color.WHITE).toBitmap(width = 20, height = 20) overflowView = inflater.inflate(R.layout.bubblebar_item_view, bubbleBarView, false) as BubbleView overflowView.setOverflow(BubbleBarOverflow(overflowView), bitmap) bubbleBarView.addView(overflowView) val bubbleInfo = BubbleInfo("key", 0, null, null, 0, context.packageName, null, false) bubbleView = inflater.inflate(R.layout.bubblebar_item_view, bubbleBarView, false) as BubbleView bubble = BubbleBarBubble(bubbleInfo, bubbleView, bitmap, bitmap, Color.WHITE, Path(), "") bubbleView.setBubble(bubble) bubbleBarView.addView(bubbleView) } InstrumentationRegistry.getInstrumentation().waitForIdleSync() } private fun setUpBubbleStashController() { bubbleStashController = mock<BubbleStashController>() whenever(bubbleStashController.isStashed).thenReturn(true) whenever(bubbleStashController.diffBetweenHandleAndBarCenters) .thenReturn(DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS) whenever(bubbleStashController.stashedHandleTranslationForNewBubbleAnimation) .thenReturn(HANDLE_TRANSLATION) whenever(bubbleStashController.bubbleBarTranslationYForTaskbar) .thenReturn(BAR_TRANSLATION_Y_FOR_TASKBAR) } private class TestBubbleBarViewAnimatorScheduler : BubbleBarViewAnimator.Scheduler { var delayedBlock: Runnable? = null Loading