See go/bubble-stack-design for a high level overview of these changes. This is a large CL, but required in order to allow continued development and team testing without breaking functionality over the course of multiple CL submissions. To integrate the new animations, the following changes have been made to existing code: * (BubbleStackView) The bubble container (and thus, the stack view) are MATCH_PARENT to allow the bubbles to independently translate anywhere on the screen. * (BubbleStackView) Start position is set by the stack controller, not BubbleStackView. * (BubbleStackView) Expand positon is set by the expansion controller, not BubbleStackView. * (BubbleStackView/BubbleTouchHandler) Added the methods onDragStart/onDragged/onDragFinish, and onBubbleDragStart/onBubbleDragged/onBubbleDragFinish, for cleaner dispatch of touch events to the appropriate animation controller. * (BubbleStackView/BubbleController) The stack view's getBoundsOnScreen returns the first bubble's bounds, if the stack is not expanded. * (BubbleStackView) applyCurrentState no longer manages translation of bubbles, or the expanded view, these are controlled by animation. * (BubbleMovementHelper) Deleted, no longer needed. * (Everywhere) Changed uses of Point to PointF, since translation values are floats anyway. Known issues to be fixed in subsequent, far smaller CLs: * (b/123022862) Bubble dragging out/dismissing is not animated, and the bubbles can be deposited anywhere. Tap outside the stack to collapse them back to normal. * (b/123023502) New bubbles added while the stack is expanded are not positioned properly. * (b/123022982) Expanded view arrow is sometimes in the wrong position. * (b/123023410) If the stack is expanded while animating, it collapses to its original position even if not along the edge of the screen. * (b/123023904) The expanded view doesn't animate out, it disappears instantly. * (b/123026584) Bounds in landscape are a bit wonky. Bug: 111236845 Test: atest SystemUITests Test: physics-animation-testing.md Change-Id: Icaca09e5db89c635c9bb7ca82d7d2714362e344e
2.4 KiB
Physics Animation Testing
Physics animations are notoriously difficult to test, since they’re essentially small simulations. They have no set duration, and they’re considered ‘finished’ only when the movements imparted by the animation are too small to be user-visible. Mid-states are not deterministic.
For this reason, we only test the end state of animations. Manual testing should be sufficient to reveal flaws in the en-route animation visuals. In a worst-case failure case, as long as the end state is correct, usability will not be affected - animations might just look a bit off until the UI elements settle to their proper positions.
Waiting for Animations to End
Testing any kind of animation can be tricky, since animations need to run on the main thread, and they’re asynchronous - the test has to wait for the animation to finish before we can assert anything about its end state. For normal animations, we can invoke skipToEnd to avoid waiting. While this method is available for SpringAnimation, it’s not available for FlingAnimation since its end state is not initially known. A FlingAnimation’s ‘end’ is when the friction simulation reports that motion has slowed to an invisible level. For this reason, we have to actually run the physics animations.
To accommodate this, all tests of the layout itself, as well as any animation controller subclasses, use PhysicsAnimationLayoutTestCase. The layout provided to controllers by the test case is a TestablePhysicsAnimationLayout, a subclass of PhysicsAnimationLayout whose animation-related methods have been overridden to force them to run on the main thread via a Handler. Animations will simply crash if they’re called directly from the test thread, so this is important.
The test case also provides waitForPropertyAnimations
, which uses a CountDownLatch to wait for all animations on a given property to complete before continuing the test. This works since the test is not running on the same thread as the animation, so a blocking call to latch.await()
does not affect the animations’ progress. The latch is initialized with a count equal to the number of properties we’re listening to. We then add end listeners to the layout for each property, which call latch.countDown()
. Once all of the properties’ animations have completed, the latch count reaches zero and the test’s call to await()
returns, with the animations complete.