Stability and logic fixes to PhysicsAnimationLayout to address bugs that leave Bubbles in a bad state.
- Ignore attempts to start animations from controllers that aren't the active controller. - Use -Float.MAX_VALUE for the start velocity default, not 0, so negative velocities aren't discarded. - Update the SpringForce's final position directly rather than using animateToFinalPosition (the latter is susceptible to race conditions if animateToFinalPosition is called again before the next animation frame, a bug in DynamicAnimation). Test: atest SystemUITests Fixes: 131625234 Change-Id: Ie48da88db6c241896bba17bb800a2f91ab61651e
This commit is contained in:
@@ -332,7 +332,7 @@ public class BubbleStackView extends FrameLayout {
|
||||
mBubbleContainer = new PhysicsAnimationLayout(context);
|
||||
mBubbleContainer.setMaxRenderedChildren(
|
||||
getResources().getInteger(R.integer.bubbles_max_rendered));
|
||||
mBubbleContainer.setController(mStackAnimationController);
|
||||
mBubbleContainer.setActiveController(mStackAnimationController);
|
||||
mBubbleContainer.setElevation(elevation);
|
||||
mBubbleContainer.setClipChildren(false);
|
||||
addView(mBubbleContainer, new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
|
||||
@@ -909,7 +909,7 @@ public class BubbleStackView extends FrameLayout {
|
||||
};
|
||||
|
||||
if (shouldExpand) {
|
||||
mBubbleContainer.setController(mExpandedAnimationController);
|
||||
mBubbleContainer.setActiveController(mExpandedAnimationController);
|
||||
mExpandedAnimationController.expandFromStack(
|
||||
mStackAnimationController.getStackPositionAlongNearestHorizontalEdge()
|
||||
/* collapseTo */,
|
||||
@@ -921,7 +921,7 @@ public class BubbleStackView extends FrameLayout {
|
||||
mBubbleContainer.cancelAllAnimations();
|
||||
mExpandedAnimationController.collapseBackToStack(
|
||||
() -> {
|
||||
mBubbleContainer.setController(mStackAnimationController);
|
||||
mBubbleContainer.setActiveController(mStackAnimationController);
|
||||
updateAfter.run();
|
||||
});
|
||||
}
|
||||
@@ -1014,7 +1014,7 @@ public class BubbleStackView extends FrameLayout {
|
||||
}
|
||||
|
||||
mStackAnimationController.cancelStackPositionAnimations();
|
||||
mBubbleContainer.setController(mStackAnimationController);
|
||||
mBubbleContainer.setActiveController(mStackAnimationController);
|
||||
hideFlyoutImmediate();
|
||||
|
||||
mDraggingInDismissTarget = false;
|
||||
|
||||
@@ -103,20 +103,6 @@ public class ExpandedAnimationController
|
||||
private float mBubbleDraggingOutVelX;
|
||||
private float mBubbleDraggingOutVelY;
|
||||
|
||||
@Override
|
||||
protected void setLayout(PhysicsAnimationLayout layout) {
|
||||
super.setLayout(layout);
|
||||
|
||||
final Resources res = layout.getResources();
|
||||
mStackOffsetPx = res.getDimensionPixelSize(R.dimen.bubble_stack_offset);
|
||||
mBubblePaddingPx = res.getDimensionPixelSize(R.dimen.bubble_padding);
|
||||
mBubbleSizePx = res.getDimensionPixelSize(R.dimen.individual_bubble_size);
|
||||
mStatusBarHeight =
|
||||
res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
|
||||
mPipDismissHeight = res.getDimensionPixelSize(R.dimen.pip_dismiss_gradient_height);
|
||||
mBubblesMaxRendered = res.getInteger(R.integer.bubbles_max_rendered);
|
||||
}
|
||||
|
||||
/**
|
||||
* Animates expanding the bubbles into a row along the top of the screen.
|
||||
*/
|
||||
@@ -296,6 +282,24 @@ public class ExpandedAnimationController
|
||||
: 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
void onActiveControllerForLayout(PhysicsAnimationLayout layout) {
|
||||
final Resources res = layout.getResources();
|
||||
mStackOffsetPx = res.getDimensionPixelSize(R.dimen.bubble_stack_offset);
|
||||
mBubblePaddingPx = res.getDimensionPixelSize(R.dimen.bubble_padding);
|
||||
mBubbleSizePx = res.getDimensionPixelSize(R.dimen.individual_bubble_size);
|
||||
mStatusBarHeight =
|
||||
res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
|
||||
mPipDismissHeight = res.getDimensionPixelSize(R.dimen.pip_dismiss_gradient_height);
|
||||
mBubblesMaxRendered = res.getInteger(R.integer.bubbles_max_rendered);
|
||||
|
||||
// Ensure that all child views are at 1x scale, and visible, in case they were animating
|
||||
// in.
|
||||
mLayout.setVisibility(View.VISIBLE);
|
||||
animationsForChildrenFromIndex(0 /* startIndex */, (index, animation) ->
|
||||
animation.scaleX(1f).scaleY(1f).alpha(1f)).startAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
Set<DynamicAnimation.ViewProperty> getAnimatedProperties() {
|
||||
return Sets.newHashSet(
|
||||
|
||||
@@ -17,10 +17,12 @@
|
||||
package com.android.systemui.bubbles.animation;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.dynamicanimation.animation.DynamicAnimation;
|
||||
import androidx.dynamicanimation.animation.SpringAnimation;
|
||||
import androidx.dynamicanimation.animation.SpringForce;
|
||||
@@ -137,12 +139,30 @@ public class PhysicsAnimationLayout extends FrameLayout {
|
||||
*/
|
||||
abstract void onChildRemoved(View child, int index, Runnable finishRemoval);
|
||||
|
||||
/**
|
||||
* Called when the controller is set as the active animation controller for the given
|
||||
* layout. Once active, the controller can start animations using the animator instances
|
||||
* returned by {@link #animationForChild}.
|
||||
*
|
||||
* While all animations started by the previous controller will be cancelled, the new
|
||||
* controller should not make any assumptions about the state of the layout or its children.
|
||||
* Their translation, alpha, scale, etc. values may have been changed by the previous
|
||||
* controller and should be reset here if relevant.
|
||||
*/
|
||||
abstract void onActiveControllerForLayout(PhysicsAnimationLayout layout);
|
||||
|
||||
protected PhysicsAnimationLayout mLayout;
|
||||
|
||||
PhysicsAnimationController() { }
|
||||
|
||||
/** Whether this controller is the currently active controller for its associated layout. */
|
||||
protected boolean isActiveController() {
|
||||
return this == mLayout.mController;
|
||||
}
|
||||
|
||||
protected void setLayout(PhysicsAnimationLayout layout) {
|
||||
this.mLayout = layout;
|
||||
onActiveControllerForLayout(layout);
|
||||
}
|
||||
|
||||
protected PhysicsAnimationLayout getLayout() {
|
||||
@@ -170,6 +190,9 @@ public class PhysicsAnimationLayout extends FrameLayout {
|
||||
child.setTag(R.id.physics_animator_tag, animator);
|
||||
}
|
||||
|
||||
animator.clearAnimator();
|
||||
animator.setAssociatedController(this);
|
||||
|
||||
return animator;
|
||||
}
|
||||
|
||||
@@ -235,7 +258,7 @@ public class PhysicsAnimationLayout extends FrameLayout {
|
||||
new HashMap<>();
|
||||
|
||||
/** The currently active animation controller. */
|
||||
private PhysicsAnimationController mController;
|
||||
@Nullable protected PhysicsAnimationController mController;
|
||||
|
||||
/**
|
||||
* The maximum number of children to render and animate at a time. See
|
||||
@@ -260,7 +283,7 @@ public class PhysicsAnimationLayout extends FrameLayout {
|
||||
* Sets the animation controller and constructs or reconfigures the layout's physics animations
|
||||
* to meet the controller's specifications.
|
||||
*/
|
||||
public void setController(PhysicsAnimationController controller) {
|
||||
public void setActiveController(PhysicsAnimationController controller) {
|
||||
cancelAllAnimations();
|
||||
mEndActionForProperty.clear();
|
||||
|
||||
@@ -315,7 +338,7 @@ public class PhysicsAnimationLayout extends FrameLayout {
|
||||
super.addView(child, index, params);
|
||||
|
||||
// Set up animations for the new view, if the controller is set. If it isn't set, we'll be
|
||||
// setting up animations for all children when setController is called.
|
||||
// setting up animations for all children when setActiveController is called.
|
||||
if (mController != null) {
|
||||
for (DynamicAnimation.ViewProperty property : mController.getAnimatedProperties()) {
|
||||
setUpAnimationForChild(property, child, index);
|
||||
@@ -427,6 +450,10 @@ public class PhysicsAnimationLayout extends FrameLayout {
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isActiveController(PhysicsAnimationController controller) {
|
||||
return mController == controller;
|
||||
}
|
||||
|
||||
/** Whether the first child would be left of center if translated to the given x value. */
|
||||
protected boolean isFirstChildXLeftOfCenter(float x) {
|
||||
if (getChildCount() > 0) {
|
||||
@@ -592,7 +619,7 @@ public class PhysicsAnimationLayout extends FrameLayout {
|
||||
private View mView;
|
||||
|
||||
/** Start velocity to use for all property animations. */
|
||||
private float mDefaultStartVelocity = 0f;
|
||||
private float mDefaultStartVelocity = -Float.MAX_VALUE;
|
||||
|
||||
/** Start delay to use when start is called. */
|
||||
private long mStartDelay = 0;
|
||||
@@ -625,6 +652,15 @@ public class PhysicsAnimationLayout extends FrameLayout {
|
||||
*/
|
||||
private Map<DynamicAnimation.ViewProperty, Float> mAnimatedProperties = new HashMap<>();
|
||||
|
||||
/**
|
||||
* All of the initial property values that have been set. These values will be instantly set
|
||||
* when {@link #start} is called, just before the animation begins.
|
||||
*/
|
||||
private Map<DynamicAnimation.ViewProperty, Float> mInitialPropertyValues = new HashMap<>();
|
||||
|
||||
/** The animation controller that last retrieved this animator instance. */
|
||||
private PhysicsAnimationController mAssociatedController;
|
||||
|
||||
protected PhysicsPropertyAnimator(View view) {
|
||||
this.mView = view;
|
||||
}
|
||||
@@ -644,7 +680,7 @@ public class PhysicsAnimationLayout extends FrameLayout {
|
||||
|
||||
/** Set the view's alpha value to 'from', then animate it to the given value. */
|
||||
public PhysicsPropertyAnimator alpha(float from, float to, Runnable... endActions) {
|
||||
mView.setAlpha(from);
|
||||
mInitialPropertyValues.put(DynamicAnimation.ALPHA, from);
|
||||
return alpha(to, endActions);
|
||||
}
|
||||
|
||||
@@ -656,7 +692,7 @@ public class PhysicsAnimationLayout extends FrameLayout {
|
||||
/** Set the view's translationX value to 'from', then animate it to the given value. */
|
||||
public PhysicsPropertyAnimator translationX(
|
||||
float from, float to, Runnable... endActions) {
|
||||
mView.setTranslationX(from);
|
||||
mInitialPropertyValues.put(DynamicAnimation.TRANSLATION_X, from);
|
||||
return translationX(to, endActions);
|
||||
}
|
||||
|
||||
@@ -668,7 +704,7 @@ public class PhysicsAnimationLayout extends FrameLayout {
|
||||
/** Set the view's translationY value to 'from', then animate it to the given value. */
|
||||
public PhysicsPropertyAnimator translationY(
|
||||
float from, float to, Runnable... endActions) {
|
||||
mView.setTranslationY(from);
|
||||
mInitialPropertyValues.put(DynamicAnimation.TRANSLATION_Y, from);
|
||||
return translationY(to, endActions);
|
||||
}
|
||||
|
||||
@@ -690,7 +726,7 @@ public class PhysicsAnimationLayout extends FrameLayout {
|
||||
|
||||
/** Set the view's scaleX value to 'from', then animate it to the given value. */
|
||||
public PhysicsPropertyAnimator scaleX(float from, float to, Runnable... endActions) {
|
||||
mView.setScaleX(from);
|
||||
mInitialPropertyValues.put(DynamicAnimation.SCALE_X, from);
|
||||
return scaleX(to, endActions);
|
||||
}
|
||||
|
||||
@@ -701,7 +737,7 @@ public class PhysicsAnimationLayout extends FrameLayout {
|
||||
|
||||
/** Set the view's scaleY value to 'from', then animate it to the given value. */
|
||||
public PhysicsPropertyAnimator scaleY(float from, float to, Runnable... endActions) {
|
||||
mView.setScaleY(from);
|
||||
mInitialPropertyValues.put(DynamicAnimation.SCALE_Y, from);
|
||||
return scaleY(to, endActions);
|
||||
}
|
||||
|
||||
@@ -750,6 +786,13 @@ public class PhysicsAnimationLayout extends FrameLayout {
|
||||
* animated property on every child (including chained animations) have ended.
|
||||
*/
|
||||
public void start(Runnable... after) {
|
||||
if (!isActiveController(mAssociatedController)) {
|
||||
Log.w(TAG, "Only the active animation controller is allowed to start animations. "
|
||||
+ "Use PhysicsAnimationLayout#setActiveController to set the active "
|
||||
+ "animation controller.");
|
||||
return;
|
||||
}
|
||||
|
||||
final Set<DynamicAnimation.ViewProperty> properties = getAnimatedProperties();
|
||||
|
||||
// If there are end actions, set an end listener on the layout for all the properties
|
||||
@@ -791,6 +834,10 @@ public class PhysicsAnimationLayout extends FrameLayout {
|
||||
|
||||
// Actually start the animations.
|
||||
for (DynamicAnimation.ViewProperty property : properties) {
|
||||
if (mInitialPropertyValues.containsKey(property)) {
|
||||
property.setValue(mView, mInitialPropertyValues.get(property));
|
||||
}
|
||||
|
||||
final SpringForce defaultSpringForce = mController.getSpringForce(property, mView);
|
||||
animateValueForChild(
|
||||
property,
|
||||
@@ -803,14 +850,7 @@ public class PhysicsAnimationLayout extends FrameLayout {
|
||||
mEndActionsForProperty.get(property));
|
||||
}
|
||||
|
||||
// Clear out the animator.
|
||||
mAnimatedProperties.clear();
|
||||
mPositionStartVelocities.clear();
|
||||
mDefaultStartVelocity = 0;
|
||||
mStartDelay = 0;
|
||||
mStiffness = -1;
|
||||
mDampingRatio = -1;
|
||||
mEndActionsForProperty.clear();
|
||||
clearAnimator();
|
||||
}
|
||||
|
||||
/** Returns the set of properties that will animate once {@link #start} is called. */
|
||||
@@ -847,20 +887,50 @@ public class PhysicsAnimationLayout extends FrameLayout {
|
||||
});
|
||||
}
|
||||
|
||||
animation.getSpring().setStiffness(stiffness);
|
||||
animation.getSpring().setDampingRatio(dampingRatio);
|
||||
final SpringForce animationSpring = animation.getSpring();
|
||||
|
||||
if (startVel > 0) {
|
||||
animation.setStartVelocity(startVel);
|
||||
if (animationSpring == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Runnable configureAndStartAnimation = () -> {
|
||||
animationSpring.setStiffness(stiffness);
|
||||
animationSpring.setDampingRatio(dampingRatio);
|
||||
|
||||
if (startVel > -Float.MAX_VALUE) {
|
||||
animation.setStartVelocity(startVel);
|
||||
}
|
||||
|
||||
animationSpring.setFinalPosition(value);
|
||||
animation.start();
|
||||
};
|
||||
|
||||
if (startDelay > 0) {
|
||||
postDelayed(() -> animation.animateToFinalPosition(value), startDelay);
|
||||
postDelayed(configureAndStartAnimation, startDelay);
|
||||
} else {
|
||||
animation.animateToFinalPosition(value);
|
||||
configureAndStartAnimation.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void clearAnimator() {
|
||||
mInitialPropertyValues.clear();
|
||||
mAnimatedProperties.clear();
|
||||
mPositionStartVelocities.clear();
|
||||
mDefaultStartVelocity = -Float.MAX_VALUE;
|
||||
mStartDelay = 0;
|
||||
mStiffness = -1;
|
||||
mDampingRatio = -1;
|
||||
mEndActionsForProperty.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the controller that last retrieved this animator instance, so that we can prevent
|
||||
* {@link #start} from actually starting animations if called by a non-active controller.
|
||||
*/
|
||||
private void setAssociatedController(PhysicsAnimationController controller) {
|
||||
mAssociatedController = controller;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -154,21 +154,6 @@ public class StackAnimationController extends
|
||||
/** Height of the status bar. */
|
||||
private float mStatusBarHeight;
|
||||
|
||||
@Override
|
||||
protected void setLayout(PhysicsAnimationLayout layout) {
|
||||
super.setLayout(layout);
|
||||
|
||||
Resources res = layout.getResources();
|
||||
mStackOffset = res.getDimensionPixelSize(R.dimen.bubble_stack_offset);
|
||||
mIndividualBubbleSize = res.getDimensionPixelSize(R.dimen.individual_bubble_size);
|
||||
mBubblePadding = res.getDimensionPixelSize(R.dimen.bubble_padding);
|
||||
mBubbleOffscreen = res.getDimensionPixelSize(R.dimen.bubble_stack_offscreen);
|
||||
mStackStartingVerticalOffset =
|
||||
res.getDimensionPixelSize(R.dimen.bubble_stack_starting_offset_y);
|
||||
mStatusBarHeight =
|
||||
res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantly move the first bubble to the given point, and animate the rest of the stack behind
|
||||
* it with the 'following' effect.
|
||||
@@ -656,19 +641,35 @@ public class StackAnimationController extends
|
||||
|
||||
if (mLayout.getChildCount() > 0) {
|
||||
animationForChildAtIndex(0).translationX(mStackPosition.x).start();
|
||||
} else {
|
||||
// Set the start position back to the default since we're out of bubbles. New bubbles
|
||||
// will then animate in from the start position.
|
||||
mStackPosition = getDefaultStartPosition();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void onActiveControllerForLayout(PhysicsAnimationLayout layout) {
|
||||
Resources res = layout.getResources();
|
||||
mStackOffset = res.getDimensionPixelSize(R.dimen.bubble_stack_offset);
|
||||
mIndividualBubbleSize = res.getDimensionPixelSize(R.dimen.individual_bubble_size);
|
||||
mBubblePadding = res.getDimensionPixelSize(R.dimen.bubble_padding);
|
||||
mBubbleOffscreen = res.getDimensionPixelSize(R.dimen.bubble_stack_offscreen);
|
||||
mStackStartingVerticalOffset =
|
||||
res.getDimensionPixelSize(R.dimen.bubble_stack_starting_offset_y);
|
||||
mStatusBarHeight =
|
||||
res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
|
||||
}
|
||||
|
||||
/** Moves the stack, without any animation, to the starting position. */
|
||||
private void moveStackToStartPosition() {
|
||||
// Post to ensure that the layout's width and height have been calculated.
|
||||
mLayout.setVisibility(View.INVISIBLE);
|
||||
mLayout.post(() -> {
|
||||
setStackPosition(mRestingStackPosition == null
|
||||
? getDefaultStartPosition()
|
||||
: mRestingStackPosition);
|
||||
mStackMovedToStartPosition = true;
|
||||
setStackPosition(
|
||||
mRestingStackPosition == null
|
||||
? getDefaultStartPosition()
|
||||
: mRestingStackPosition);
|
||||
mLayout.setVisibility(View.VISIBLE);
|
||||
|
||||
// Animate in the top bubble now that we're visible.
|
||||
@@ -707,15 +708,20 @@ public class StackAnimationController extends
|
||||
Log.d(TAG, String.format("Setting position to (%f, %f).", pos.x, pos.y));
|
||||
mStackPosition.set(pos.x, pos.y);
|
||||
|
||||
mLayout.cancelAllAnimations();
|
||||
cancelStackPositionAnimations();
|
||||
// If we're not the active controller, we don't want to physically move the bubble views.
|
||||
if (isActiveController()) {
|
||||
mLayout.cancelAllAnimations();
|
||||
cancelStackPositionAnimations();
|
||||
|
||||
// Since we're not using the chained animations, apply the offsets manually.
|
||||
final float xOffset = getOffsetForChainedPropertyAnimation(DynamicAnimation.TRANSLATION_X);
|
||||
final float yOffset = getOffsetForChainedPropertyAnimation(DynamicAnimation.TRANSLATION_Y);
|
||||
for (int i = 0; i < mLayout.getChildCount(); i++) {
|
||||
mLayout.getChildAt(i).setTranslationX(pos.x + (i * xOffset));
|
||||
mLayout.getChildAt(i).setTranslationY(pos.y + (i * yOffset));
|
||||
// Since we're not using the chained animations, apply the offsets manually.
|
||||
final float xOffset = getOffsetForChainedPropertyAnimation(
|
||||
DynamicAnimation.TRANSLATION_X);
|
||||
final float yOffset = getOffsetForChainedPropertyAnimation(
|
||||
DynamicAnimation.TRANSLATION_Y);
|
||||
for (int i = 0; i < mLayout.getChildCount(); i++) {
|
||||
mLayout.getChildAt(i).setTranslationX(pos.x + (i * xOffset));
|
||||
mLayout.getChildAt(i).setTranslationY(pos.y + (i * yOffset));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -732,6 +738,10 @@ public class StackAnimationController extends
|
||||
|
||||
/** Animates in the given bubble. */
|
||||
private void animateInBubble(View child) {
|
||||
if (!isActiveController()) {
|
||||
return;
|
||||
}
|
||||
|
||||
child.setTranslationY(mStackPosition.y);
|
||||
|
||||
float xOffset = getOffsetForChainedPropertyAnimation(DynamicAnimation.TRANSLATION_X);
|
||||
|
||||
@@ -61,7 +61,7 @@ public class ExpandedAnimationControllerTest extends PhysicsAnimationLayoutTestC
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
addOneMoreThanRenderLimitBubbles();
|
||||
mLayout.setController(mExpandedController);
|
||||
mLayout.setActiveController(mExpandedController);
|
||||
|
||||
Resources res = mLayout.getResources();
|
||||
mStackOffset = res.getDimensionPixelSize(R.dimen.bubble_stack_offset);
|
||||
|
||||
@@ -78,7 +78,7 @@ public class PhysicsAnimationLayoutTest extends PhysicsAnimationLayoutTestCase {
|
||||
|
||||
@Test
|
||||
public void testRenderVisibility() throws InterruptedException {
|
||||
mLayout.setController(mTestableController);
|
||||
mLayout.setActiveController(mTestableController);
|
||||
addOneMoreThanRenderLimitBubbles();
|
||||
|
||||
// The last child should be GONE, the rest VISIBLE.
|
||||
@@ -90,7 +90,7 @@ public class PhysicsAnimationLayoutTest extends PhysicsAnimationLayoutTestCase {
|
||||
|
||||
@Test
|
||||
public void testHierarchyChanges() throws InterruptedException {
|
||||
mLayout.setController(mTestableController);
|
||||
mLayout.setActiveController(mTestableController);
|
||||
addOneMoreThanRenderLimitBubbles();
|
||||
|
||||
// Make sure the controller was notified of all the views we added.
|
||||
@@ -115,7 +115,7 @@ public class PhysicsAnimationLayoutTest extends PhysicsAnimationLayoutTestCase {
|
||||
|
||||
@Test
|
||||
public void testUpdateValueNotChained() throws InterruptedException {
|
||||
mLayout.setController(mTestableController);
|
||||
mLayout.setActiveController(mTestableController);
|
||||
addOneMoreThanRenderLimitBubbles();
|
||||
|
||||
// Don't chain any values.
|
||||
@@ -146,7 +146,7 @@ public class PhysicsAnimationLayoutTest extends PhysicsAnimationLayoutTestCase {
|
||||
|
||||
@Test
|
||||
public void testSetEndActions() throws InterruptedException {
|
||||
mLayout.setController(mTestableController);
|
||||
mLayout.setActiveController(mTestableController);
|
||||
addOneMoreThanRenderLimitBubbles();
|
||||
mTestableController.setChainedProperties(Sets.newHashSet());
|
||||
|
||||
@@ -189,7 +189,7 @@ public class PhysicsAnimationLayoutTest extends PhysicsAnimationLayoutTestCase {
|
||||
|
||||
@Test
|
||||
public void testRemoveEndListeners() throws InterruptedException {
|
||||
mLayout.setController(mTestableController);
|
||||
mLayout.setActiveController(mTestableController);
|
||||
addOneMoreThanRenderLimitBubbles();
|
||||
mTestableController.setChainedProperties(Sets.newHashSet());
|
||||
|
||||
@@ -230,7 +230,7 @@ public class PhysicsAnimationLayoutTest extends PhysicsAnimationLayoutTestCase {
|
||||
// Add the bubbles, then set the controller, to make sure that a controller added to an
|
||||
// already-initialized view works correctly.
|
||||
addOneMoreThanRenderLimitBubbles();
|
||||
mLayout.setController(mTestableController);
|
||||
mLayout.setActiveController(mTestableController);
|
||||
testChainedTranslationAnimations();
|
||||
|
||||
TestableAnimationController secondController =
|
||||
@@ -243,7 +243,7 @@ public class PhysicsAnimationLayoutTest extends PhysicsAnimationLayoutTestCase {
|
||||
DynamicAnimation.SCALE_X, 10f);
|
||||
secondController.setRemoveImmediately(true);
|
||||
|
||||
mLayout.setController(secondController);
|
||||
mLayout.setActiveController(secondController);
|
||||
mTestableController.animationForChildAtIndex(0)
|
||||
.scaleX(1.5f)
|
||||
.start();
|
||||
@@ -266,7 +266,7 @@ public class PhysicsAnimationLayoutTest extends PhysicsAnimationLayoutTestCase {
|
||||
Mockito.verify(secondController, Mockito.atLeastOnce())
|
||||
.getOffsetForChainedPropertyAnimation(eq(DynamicAnimation.SCALE_X));
|
||||
|
||||
mLayout.setController(mTestableController);
|
||||
mLayout.setActiveController(mTestableController);
|
||||
mTestableController.animationForChildAtIndex(0)
|
||||
.translationX(100f)
|
||||
.start();
|
||||
@@ -283,7 +283,7 @@ public class PhysicsAnimationLayoutTest extends PhysicsAnimationLayoutTestCase {
|
||||
|
||||
@Test
|
||||
public void testArePropertiesAnimating() throws InterruptedException {
|
||||
mLayout.setController(mTestableController);
|
||||
mLayout.setActiveController(mTestableController);
|
||||
addOneMoreThanRenderLimitBubbles();
|
||||
|
||||
assertFalse(mLayout.arePropertiesAnimating(
|
||||
@@ -307,7 +307,7 @@ public class PhysicsAnimationLayoutTest extends PhysicsAnimationLayoutTestCase {
|
||||
|
||||
@Test
|
||||
public void testCancelAllAnimations() throws InterruptedException {
|
||||
mLayout.setController(mTestableController);
|
||||
mLayout.setActiveController(mTestableController);
|
||||
addOneMoreThanRenderLimitBubbles();
|
||||
|
||||
mTestableController.animationForChildAtIndex(0)
|
||||
@@ -323,7 +323,7 @@ public class PhysicsAnimationLayoutTest extends PhysicsAnimationLayoutTestCase {
|
||||
|
||||
@Test
|
||||
public void testSetChildVisibility() throws InterruptedException {
|
||||
mLayout.setController(mTestableController);
|
||||
mLayout.setActiveController(mTestableController);
|
||||
addOneMoreThanRenderLimitBubbles();
|
||||
|
||||
// The last view should have been set to GONE by the controller, since we added one more
|
||||
@@ -342,7 +342,7 @@ public class PhysicsAnimationLayoutTest extends PhysicsAnimationLayoutTestCase {
|
||||
|
||||
/** Standard test of chained translation animations. */
|
||||
private void testChainedTranslationAnimations() throws InterruptedException {
|
||||
mLayout.setController(mTestableController);
|
||||
mLayout.setActiveController(mTestableController);
|
||||
addOneMoreThanRenderLimitBubbles();
|
||||
|
||||
assertEquals(0, mLayout.getChildAt(0).getTranslationX(), .1f);
|
||||
@@ -383,7 +383,7 @@ public class PhysicsAnimationLayoutTest extends PhysicsAnimationLayoutTestCase {
|
||||
|
||||
@Test
|
||||
public void testPhysicsAnimator() throws InterruptedException {
|
||||
mLayout.setController(mTestableController);
|
||||
mLayout.setActiveController(mTestableController);
|
||||
addOneMoreThanRenderLimitBubbles();
|
||||
|
||||
Runnable afterAll = Mockito.mock(Runnable.class);
|
||||
@@ -430,7 +430,7 @@ public class PhysicsAnimationLayoutTest extends PhysicsAnimationLayoutTestCase {
|
||||
// Don't chain since we're going to invoke each animation independently.
|
||||
mTestableController.setChainedProperties(new HashSet<>());
|
||||
|
||||
mLayout.setController(mTestableController);
|
||||
mLayout.setActiveController(mTestableController);
|
||||
|
||||
addOneMoreThanRenderLimitBubbles();
|
||||
|
||||
@@ -452,7 +452,7 @@ public class PhysicsAnimationLayoutTest extends PhysicsAnimationLayoutTestCase {
|
||||
|
||||
@Test
|
||||
public void testAnimationsForChildrenFromIndex_noChildren() {
|
||||
mLayout.setController(mTestableController);
|
||||
mLayout.setActiveController(mTestableController);
|
||||
|
||||
final Runnable after = Mockito.mock(Runnable.class);
|
||||
mTestableController
|
||||
@@ -522,6 +522,9 @@ public class PhysicsAnimationLayoutTest extends PhysicsAnimationLayoutTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void onActiveControllerForLayout(PhysicsAnimationLayout layout) {}
|
||||
|
||||
@Override
|
||||
protected void setChildVisibility(View child, int index, int visibility) {
|
||||
super.setChildVisibility(child, index, visibility);
|
||||
|
||||
@@ -137,6 +137,13 @@ public class PhysicsAnimationLayoutTestCase extends SysuiTestCase {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isActiveController(PhysicsAnimationController controller) {
|
||||
// Return true since otherwise all test controllers will be seen as inactive since they
|
||||
// are wrapped by MainThreadAnimationControllerWrapper.
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean post(Runnable action) {
|
||||
return mMainThreadHandler.post(action);
|
||||
@@ -148,9 +155,9 @@ public class PhysicsAnimationLayoutTestCase extends SysuiTestCase {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setController(PhysicsAnimationController controller) {
|
||||
public void setActiveController(PhysicsAnimationController controller) {
|
||||
runOnMainThreadAndBlock(
|
||||
() -> super.setController(
|
||||
() -> super.setActiveController(
|
||||
new MainThreadAnimationControllerWrapper(controller)));
|
||||
}
|
||||
|
||||
@@ -266,6 +273,12 @@ public class PhysicsAnimationLayoutTestCase extends SysuiTestCase {
|
||||
() -> mWrappedController.onChildRemoved(child, index, finishRemoval));
|
||||
}
|
||||
|
||||
@Override
|
||||
void onActiveControllerForLayout(PhysicsAnimationLayout layout) {
|
||||
runOnMainThreadAndBlock(
|
||||
() -> mWrappedController.onActiveControllerForLayout(layout));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setChildVisibility(View child, int index, int visibility) {
|
||||
mWrappedController.setChildVisibility(child, index, visibility);
|
||||
|
||||
@@ -54,7 +54,7 @@ public class StackAnimationControllerTest extends PhysicsAnimationLayoutTestCase
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
mLayout.setController(mStackController);
|
||||
mLayout.setActiveController(mStackController);
|
||||
addOneMoreThanRenderLimitBubbles();
|
||||
mStackOffset = mLayout.getResources().getDimensionPixelSize(R.dimen.bubble_stack_offset);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user