Merge changes I1360deb0,Id9a9eb85,I7f05f2ee,Ie48da88d into qt-dev

am: 06cbf65704

Change-Id: I666d3b5b62514410a651d914271b664370c67f84
This commit is contained in:
Josh Tsuji
2019-05-30 12:39:53 -07:00
committed by android-build-merger
8 changed files with 371 additions and 341 deletions

View File

@@ -330,9 +330,7 @@ public class BubbleStackView extends FrameLayout {
mSurfaceSynchronizer = synchronizer != null ? synchronizer : DEFAULT_SURFACE_SYNCHRONIZER;
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));
@@ -728,7 +726,7 @@ public class BubbleStackView extends FrameLayout {
public void updateBubbleOrder(List<Bubble> bubbles) {
for (int i = 0; i < bubbles.size(); i++) {
Bubble bubble = bubbles.get(i);
mBubbleContainer.moveViewTo(bubble.iconView, i);
mBubbleContainer.reorderView(bubble.iconView, i);
}
}
@@ -920,19 +918,17 @@ public class BubbleStackView extends FrameLayout {
};
if (shouldExpand) {
mBubbleContainer.setController(mExpandedAnimationController);
mExpandedAnimationController.expandFromStack(
mStackAnimationController.getStackPositionAlongNearestHorizontalEdge()
/* collapseTo */,
() -> {
updatePointerPosition();
updateAfter.run();
} /* after */);
mBubbleContainer.setActiveController(mExpandedAnimationController);
mExpandedAnimationController.expandFromStack(() -> {
updatePointerPosition();
updateAfter.run();
} /* after */);
} else {
mBubbleContainer.cancelAllAnimations();
mExpandedAnimationController.collapseBackToStack(
mStackAnimationController.getStackPositionAlongNearestHorizontalEdge(),
() -> {
mBubbleContainer.setController(mStackAnimationController);
mBubbleContainer.setActiveController(mStackAnimationController);
updateAfter.run();
});
}
@@ -1021,7 +1017,7 @@ public class BubbleStackView extends FrameLayout {
}
mStackAnimationController.cancelStackPositionAnimations();
mBubbleContainer.setController(mStackAnimationController);
mBubbleContainer.setActiveController(mStackAnimationController);
hideFlyoutImmediate();
mDraggingInDismissTarget = false;
@@ -1119,6 +1115,10 @@ public class BubbleStackView extends FrameLayout {
/** Called when a gesture is completed or cancelled. */
void onGestureFinished() {
mIsGestureInProgress = false;
if (mIsExpanded) {
mExpandedAnimationController.onGestureFinished();
}
}
/** Prepares and starts the desaturate/darken animation on the bubble stack. */
@@ -1209,6 +1209,7 @@ public class BubbleStackView extends FrameLayout {
*/
void magnetToStackIfNeededThenAnimateDismissal(
View touchedView, float velX, float velY, Runnable after) {
final View draggedOutBubble = mExpandedAnimationController.getDraggedOutBubble();
final Runnable animateDismissal = () -> {
mAfterMagnet = null;
@@ -1226,7 +1227,7 @@ public class BubbleStackView extends FrameLayout {
resetDesaturationAndDarken();
});
} else {
mExpandedAnimationController.dismissDraggedOutBubble(() -> {
mExpandedAnimationController.dismissDraggedOutBubble(draggedOutBubble, () -> {
mAnimatingMagnet = false;
mShowingDismiss = false;
mDraggingInDismissTarget = false;
@@ -1393,10 +1394,18 @@ public class BubbleStackView extends FrameLayout {
};
// Post in case layout isn't complete and getWidth returns 0.
post(() -> mFlyout.showFlyout(
updateMessage, mStackAnimationController.getStackPosition(), getWidth(),
mStackAnimationController.isStackOnLeftSide(),
bubble.iconView.getBadgeColor(), mAfterFlyoutHides));
post(() -> {
// An auto-expanding bubble could have been posted during the time it takes to
// layout.
if (isExpanded()) {
return;
}
mFlyout.showFlyout(
updateMessage, mStackAnimationController.getStackPosition(), getWidth(),
mStackAnimationController.isStackOnLeftSide(),
bubble.iconView.getBadgeColor(), mAfterFlyoutHides);
});
}
mFlyout.removeCallbacks(mHideFlyout);

View File

@@ -22,6 +22,7 @@ import android.graphics.PointF;
import android.view.View;
import android.view.WindowInsets;
import androidx.annotation.Nullable;
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.SpringForce;
@@ -63,12 +64,16 @@ public class ExpandedAnimationController
private Point mDisplaySize;
/** Size of dismiss target at bottom of screen. */
private float mPipDismissHeight;
/** Max number of bubbles shown in row above expanded view.*/
private int mBubblesMaxRendered;
/** Whether the dragged-out bubble is in the dismiss target. */
private boolean mIndividualBubbleWithinDismissTarget = false;
private boolean mAnimatingExpand = false;
private boolean mAnimatingCollapse = false;
private Runnable mAfterExpand;
private Runnable mAfterCollapse;
private PointF mCollapsePoint;
/**
* Whether the dragged out bubble is springing towards the touch point, rather than using the
* default behavior of moving directly to the touch point.
@@ -96,57 +101,61 @@ public class ExpandedAnimationController
/** The bubble currently being dragged out of the row (to potentially be dismissed). */
private View mBubbleDraggingOut;
/**
* Drag velocities for the dragging-out bubble when the drag finished. These are used by
* {@link #onChildRemoved} to animate out the bubble while respecting touch velocity.
*/
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.
*/
public void expandFromStack(PointF collapseTo, Runnable after) {
animationsForChildrenFromIndex(
0, /* startIndex */
new ChildAnimationConfigurator() {
@Override
public void configureAnimationForChildAtIndex(
int index, PhysicsAnimationLayout.PhysicsPropertyAnimator animation) {
animation.position(getBubbleLeft(index), getExpandedY());
}
})
.startAll(after);
public void expandFromStack(Runnable after) {
mAnimatingCollapse = false;
mAnimatingExpand = true;
mAfterExpand = after;
mCollapseToPoint = collapseTo;
startOrUpdateExpandAnimation();
}
/** Animate collapsing the bubbles back to their stacked position. */
public void collapseBackToStack(Runnable after) {
// Stack to the left if we're going to the left, or right if not.
final float sideMultiplier = mLayout.isFirstChildXLeftOfCenter(mCollapseToPoint.x) ? -1 : 1;
public void collapseBackToStack(PointF collapsePoint, Runnable after) {
mAnimatingExpand = false;
mAnimatingCollapse = true;
mAfterCollapse = after;
mCollapsePoint = collapsePoint;
startOrUpdateCollapseAnimation();
}
private void startOrUpdateExpandAnimation() {
animationsForChildrenFromIndex(
0, /* startIndex */
(index, animation) ->
(index, animation) -> animation.position(getBubbleLeft(index), getExpandedY()))
.startAll(() -> {
mAnimatingExpand = false;
if (mAfterExpand != null) {
mAfterExpand.run();
}
mAfterExpand = null;
});
}
private void startOrUpdateCollapseAnimation() {
// Stack to the left if we're going to the left, or right if not.
final float sideMultiplier = mLayout.isFirstChildXLeftOfCenter(mCollapsePoint.x) ? -1 : 1;
animationsForChildrenFromIndex(
0, /* startIndex */
(index, animation) -> {
animation.position(
mCollapseToPoint.x + (sideMultiplier * index * mStackOffsetPx),
mCollapseToPoint.y))
.startAll(after /* endAction */);
mCollapsePoint.x + (sideMultiplier * index * mStackOffsetPx),
mCollapsePoint.y);
})
.startAll(() -> {
mAnimatingCollapse = false;
if (mAfterCollapse != null) {
mAfterCollapse.run();
}
mAfterCollapse = null;
});
}
/** Prepares the given bubble to be dragged out. */
@@ -190,10 +199,10 @@ public class ExpandedAnimationController
}
/** Plays a dismiss animation on the dragged out bubble. */
public void dismissDraggedOutBubble(Runnable after) {
public void dismissDraggedOutBubble(View bubble, Runnable after) {
mIndividualBubbleWithinDismissTarget = false;
animationForChild(mBubbleDraggingOut)
animationForChild(bubble)
.withStiffness(SpringForce.STIFFNESS_HIGH)
.scaleX(1.1f)
.scaleY(1.1f)
@@ -203,6 +212,10 @@ public class ExpandedAnimationController
updateBubblePositions();
}
@Nullable public View getDraggedOutBubble() {
return mBubbleDraggingOut;
}
/** Magnets the given bubble to the dismiss target. */
public void magnetBubbleToDismiss(
View bubbleView, float velX, float velY, float destY, Runnable after) {
@@ -241,24 +254,17 @@ public class ExpandedAnimationController
final int index = mLayout.indexOfChild(bubbleView);
animationForChildAtIndex(index)
.position(getBubbleLeft(index), getExpandedY())
.withPositionStartVelocities(velX, velY)
.start(() -> bubbleView.setTranslationZ(0f) /* after */);
.position(getBubbleLeft(index), getExpandedY())
.withPositionStartVelocities(velX, velY)
.start(() -> bubbleView.setTranslationZ(0f) /* after */);
mBubbleDraggingOut = null;
mBubbleDraggedOutEnough = false;
updateBubblePositions();
}
/**
* Sets configuration variables so that when the given bubble is removed, the animations are
* started with the given velocities.
*/
public void prepareForDismissalWithVelocity(View bubbleView, float velX, float velY) {
mBubbleDraggingOut = bubbleView;
mBubbleDraggingOutVelX = velX;
mBubbleDraggingOutVelY = velY;
/** Resets bubble drag out gesture flags. */
public void onGestureFinished() {
mBubbleDraggedOutEnough = false;
mBubbleDraggingOut = null;
}
/**
@@ -296,6 +302,23 @@ 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);
// 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(
@@ -325,14 +348,21 @@ public class ExpandedAnimationController
@Override
void onChildAdded(View child, int index) {
child.setTranslationX(getXForChildAtIndex(index));
animationForChild(child)
.translationY(
getExpandedY() - mBubbleSizePx * ANIMATE_TRANSLATION_FACTOR, /* from */
getExpandedY() /* to */)
.start();
updateBubblePositions();
// If a bubble is added while the expand/collapse animations are playing, update the
// animation to include the new bubble.
if (mAnimatingExpand) {
startOrUpdateExpandAnimation();
} else if (mAnimatingCollapse) {
startOrUpdateCollapseAnimation();
} else {
child.setTranslationX(getXForChildAtIndex(index));
animationForChild(child)
.translationY(
getExpandedY() - mBubbleSizePx * ANIMATE_TRANSLATION_FACTOR, /* from */
getExpandedY() /* to */)
.start();
updateBubblePositions();
}
}
@Override
@@ -357,19 +387,15 @@ public class ExpandedAnimationController
}
@Override
protected void setChildVisibility(View child, int index, int visibility) {
if (visibility == View.VISIBLE) {
// Set alpha to 0 but then become visible immediately so the animation is visible.
child.setAlpha(0f);
child.setVisibility(View.VISIBLE);
}
animationForChild(child)
.alpha(visibility == View.GONE ? 0f : 1f)
.start(() -> super.setChildVisibility(child, index, visibility) /* after */);
void onChildReordered(View child, int oldIndex, int newIndex) {
updateBubblePositions();
}
private void updateBubblePositions() {
if (mAnimatingExpand || mAnimatingCollapse) {
return;
}
for (int i = 0; i < mLayout.getChildCount(); i++) {
final View bubble = mLayout.getChildAt(i);
@@ -378,6 +404,7 @@ public class ExpandedAnimationController
if (bubble.equals(mBubbleDraggingOut)) {
return;
}
animationForChild(bubble)
.translationX(getBubbleLeft(i))
.start();
@@ -403,10 +430,7 @@ public class ExpandedAnimationController
return 0;
}
int bubbleCount = mLayout.getChildCount();
if (bubbleCount > mBubblesMaxRendered) {
// Only shown bubbles are relevant for calculating position.
bubbleCount = mBubblesMaxRendered;
}
// Width calculations.
double bubble = bubbleCount * mBubbleSizePx;
float gap = (bubbleCount - 1) * mBubblePaddingPx;

View File

@@ -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,27 +139,39 @@ public class PhysicsAnimationLayout extends FrameLayout {
*/
abstract void onChildRemoved(View child, int index, Runnable finishRemoval);
/** Called when a child view has been reordered in the view hierachy. */
abstract void onChildReordered(View child, int oldIndex, int newIndex);
/**
* 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() {
return mLayout;
}
/**
* Sets the child's visibility when it moves beyond or within the limits set by a call to
* {@link PhysicsAnimationLayout#setMaxRenderedChildren}. This can be overridden to animate
* this transition.
*/
protected void setChildVisibility(View child, int index, int visibility) {
child.setVisibility(visibility);
}
/**
* Returns a {@link PhysicsPropertyAnimator} instance for the given child view.
*/
@@ -170,6 +184,9 @@ public class PhysicsAnimationLayout extends FrameLayout {
child.setTag(R.id.physics_animator_tag, animator);
}
animator.clearAnimator();
animator.setAssociatedController(this);
return animator;
}
@@ -235,32 +252,17 @@ public class PhysicsAnimationLayout extends FrameLayout {
new HashMap<>();
/** The currently active animation controller. */
private PhysicsAnimationController mController;
/**
* The maximum number of children to render and animate at a time. See
* {@link #setMaxRenderedChildren}.
*/
private int mMaxRenderedChildren = 5;
@Nullable protected PhysicsAnimationController mController;
public PhysicsAnimationLayout(Context context) {
super(context);
}
/**
* The maximum number of children to render and animate at a time. Any child views added beyond
* this limit will be set to {@link View#GONE}. If any animations attempt to run on the view,
* the corresponding property will be set with no animation.
*/
public void setMaxRenderedChildren(int max) {
this.mMaxRenderedChildren = max;
}
/**
* 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();
@@ -312,42 +314,11 @@ public class PhysicsAnimationLayout extends FrameLayout {
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
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.
if (mController != null) {
for (DynamicAnimation.ViewProperty property : mController.getAnimatedProperties()) {
setUpAnimationForChild(property, child, index);
}
mController.onChildAdded(child, index);
}
setChildrenVisibility();
addViewInternal(child, index, params, false /* isReorder */);
}
@Override
public void removeView(View view) {
removeViewAndThen(view, /* callback */ null);
}
@Override
public void removeViewAt(int index) {
removeView(getChildAt(index));
}
/** Immediately moves the view from wherever it currently is, to the given index. */
public void moveViewTo(View view, int index) {
super.removeView(view);
addView(view, index);
}
/**
* Let the controller know that this view should be removed, and then call the callback once the
* controller has finished any removal animations and the view has actually been removed.
*/
public void removeViewAndThen(View view, Runnable callback) {
if (mController != null) {
final int index = indexOfChild(view);
@@ -355,8 +326,6 @@ public class PhysicsAnimationLayout extends FrameLayout {
super.removeView(view);
addTransientView(view, index);
setChildrenVisibility();
// Tell the controller to animate this view out, and call the callback when it's
// finished.
mController.onChildRemoved(view, index, () -> {
@@ -364,19 +333,28 @@ public class PhysicsAnimationLayout extends FrameLayout {
// any are still running and then remove it.
cancelAnimationsOnView(view);
removeTransientView(view);
if (callback != null) {
callback.run();
}
});
} else {
// Without a controller, nobody will animate this view out, so it gets an unceremonious
// departure.
super.removeView(view);
}
}
if (callback != null) {
callback.run();
}
@Override
public void removeViewAt(int index) {
removeView(getChildAt(index));
}
/** Immediately re-orders the view to the given index. */
public void reorderView(View view, int index) {
final int oldIndex = indexOfChild(view);
super.removeView(view);
addViewInternal(view, index, view.getLayoutParams(), true /* isReorder */);
if (mController != null) {
mController.onChildReordered(view, oldIndex, index);
}
}
@@ -427,6 +405,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) {
@@ -453,6 +435,26 @@ public class PhysicsAnimationLayout extends FrameLayout {
}
}
/**
* Adds a view to the layout. If this addition is not the result of a call to
* {@link #reorderView}, this will also notify the controller via
* {@link PhysicsAnimationController#onChildAdded} and set up animations for the view.
*/
private void addViewInternal(
View child, int index, ViewGroup.LayoutParams params, boolean isReorder) {
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 setActiveController is called.
if (mController != null && !isReorder) {
for (DynamicAnimation.ViewProperty property : mController.getAnimatedProperties()) {
setUpAnimationForChild(property, child, index);
}
mController.onChildAdded(child, index);
}
}
/**
* Retrieves the animation of the given property from the view at the given index via the view
* tag system.
@@ -481,33 +483,16 @@ public class PhysicsAnimationLayout extends FrameLayout {
SpringAnimation newAnim = new SpringAnimation(child, property);
newAnim.addUpdateListener((animation, value, velocity) -> {
final int indexOfChild = indexOfChild(child);
final int nextAnimInChain =
mController.getNextAnimationInChain(property, indexOfChild);
final int nextAnimInChain = mController.getNextAnimationInChain(property, indexOfChild);
if (nextAnimInChain == PhysicsAnimationController.NONE || indexOfChild < 0) {
return;
}
final int animIndex = indexOfChild(child);
final float offset =
mController.getOffsetForChainedPropertyAnimation(property);
// If this property's animations should be chained, then check to see if there is a
// subsequent animation within the rendering limit, and if so, tell it to animate to
// this animation's new value (plus the offset).
if (nextAnimInChain < Math.min(getChildCount(), mMaxRenderedChildren)) {
getAnimationAtIndex(property, animIndex + 1)
final float offset = mController.getOffsetForChainedPropertyAnimation(property);
if (nextAnimInChain < getChildCount()) {
getAnimationAtIndex(property, nextAnimInChain)
.animateToFinalPosition(value + offset);
} else if (nextAnimInChain < getChildCount()) {
// If the next child view is not rendered, update the property directly without
// animating it, so that the view is still in the correct state if it later
// becomes visible.
for (int i = nextAnimInChain; i < getChildCount(); i++) {
// 'value' here is the value of the last child within the rendering limit,
// not the first child's value - so we want to subtract the last child's
// index when calculating the offset.
property.setValue(getChildAt(i), value + offset * (i - animIndex));
}
}
});
@@ -516,22 +501,6 @@ public class PhysicsAnimationLayout extends FrameLayout {
child.setTag(getTagIdForProperty(property), newAnim);
}
/** Hides children beyond the max rendering count. */
private void setChildrenVisibility() {
for (int i = 0; i < getChildCount(); i++) {
final int targetVisibility = i < mMaxRenderedChildren ? View.VISIBLE : View.GONE;
final View targetView = getChildAt(i);
if (targetView.getVisibility() != targetVisibility) {
if (mController != null) {
mController.setChildVisibility(targetView, i, targetVisibility);
} else {
targetView.setVisibility(targetVisibility);
}
}
}
}
/** Return a stable ID to use as a tag key for the given property's animations. */
private int getTagIdForProperty(DynamicAnimation.ViewProperty property) {
if (property.equals(DynamicAnimation.TRANSLATION_X)) {
@@ -592,7 +561,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 +594,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 +622,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 +634,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 +646,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 +668,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 +679,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 +728,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 +776,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 +792,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 +829,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

View File

@@ -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.
@@ -286,6 +271,8 @@ public class StackAnimationController extends
},
DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y);
// If we're flinging now, there's no more touch event to catch up to.
mFirstBubbleSpringingToTouch = false;
mIsMovingFromFlinging = true;
return destinationRelativeX;
}
@@ -656,19 +643,38 @@ 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 onChildReordered(View child, int oldIndex, int newIndex) {}
@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 +713,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 +743,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);

View File

@@ -60,8 +60,8 @@ public class ExpandedAnimationControllerTest extends PhysicsAnimationLayoutTestC
@Before
public void setUp() throws Exception {
super.setUp();
addOneMoreThanRenderLimitBubbles();
mLayout.setController(mExpandedController);
addOneMoreThanBubbleLimitBubbles();
mLayout.setActiveController(mExpandedController);
Resources res = mLayout.getResources();
mStackOffset = res.getDimensionPixelSize(R.dimen.bubble_stack_offset);
@@ -73,14 +73,14 @@ public class ExpandedAnimationControllerTest extends PhysicsAnimationLayoutTestC
@Test
public void testExpansionAndCollapse() throws InterruptedException {
Runnable afterExpand = Mockito.mock(Runnable.class);
mExpandedController.expandFromStack(mExpansionPoint, afterExpand);
mExpandedController.expandFromStack(afterExpand);
waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y);
testBubblesInCorrectExpandedPositions();
verify(afterExpand).run();
Runnable afterCollapse = Mockito.mock(Runnable.class);
mExpandedController.collapseBackToStack(afterCollapse);
mExpandedController.collapseBackToStack(mExpansionPoint, afterCollapse);
waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y);
testStackedAtPosition(mExpansionPoint.x, mExpansionPoint.y, -1);
@@ -139,7 +139,6 @@ public class ExpandedAnimationControllerTest extends PhysicsAnimationLayoutTestC
assertEquals(500f, draggedBubble.getTranslationY(), 1f);
// Snap it back and make sure it made it back correctly.
mExpandedController.prepareForDismissalWithVelocity(draggedBubble, 0f, 0f);
mLayout.removeView(draggedBubble);
waitForLayoutMessageQueue();
waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y);
@@ -169,7 +168,7 @@ public class ExpandedAnimationControllerTest extends PhysicsAnimationLayoutTestC
// Dismiss the now-magneted bubble, verify that the callback was called.
final Runnable afterDismiss = Mockito.mock(Runnable.class);
mExpandedController.dismissDraggedOutBubble(afterDismiss);
mExpandedController.dismissDraggedOutBubble(draggedOutView, afterDismiss);
waitForPropertyAnimations(DynamicAnimation.ALPHA);
verify(after).run();
@@ -224,7 +223,7 @@ public class ExpandedAnimationControllerTest extends PhysicsAnimationLayoutTestC
/** Expand the stack and wait for animations to finish. */
private void expand() throws InterruptedException {
mExpandedController.expandFromStack(mExpansionPoint, Mockito.mock(Runnable.class));
mExpandedController.expandFromStack(Mockito.mock(Runnable.class));
waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y);
}
@@ -236,26 +235,19 @@ public class ExpandedAnimationControllerTest extends PhysicsAnimationLayoutTestC
assertEquals(x + i * offsetMultiplier * mStackOffset,
mLayout.getChildAt(i).getTranslationX(), 2f);
assertEquals(y, mLayout.getChildAt(i).getTranslationY(), 2f);
if (i < mMaxRenderedBubbles) {
assertEquals(1f, mLayout.getChildAt(i).getAlpha(), .01f);
}
assertEquals(1f, mLayout.getChildAt(i).getAlpha(), .01f);
}
}
/** Check that children are in the correct positions for being expanded. */
private void testBubblesInCorrectExpandedPositions() {
// Check all the visible bubbles to see if they're in the right place.
for (int i = 0; i < Math.min(mLayout.getChildCount(), mMaxRenderedBubbles); i++) {
for (int i = 0; i < mLayout.getChildCount(); i++) {
assertEquals(getBubbleLeft(i),
mLayout.getChildAt(i).getTranslationX(),
2f);
assertEquals(mExpandedController.getExpandedY(),
mLayout.getChildAt(i).getTranslationY(), 2f);
if (i < mMaxRenderedBubbles) {
assertEquals(1f, mLayout.getChildAt(i).getAlpha(), .01f);
}
}
}
@@ -273,9 +265,7 @@ public class ExpandedAnimationControllerTest extends PhysicsAnimationLayoutTestC
return 0;
}
int bubbleCount = mLayout.getChildCount();
if (bubbleCount > mMaxRenderedBubbles) {
bubbleCount = mMaxRenderedBubbles;
}
// Width calculations.
double bubble = bubbleCount * mBubbleSize;
float gap = (bubbleCount - 1) * mBubblePadding;

View File

@@ -23,7 +23,6 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -76,22 +75,10 @@ public class PhysicsAnimationLayoutTest extends PhysicsAnimationLayoutTestCase {
mTestableController.setRemoveImmediately(false);
}
@Test
public void testRenderVisibility() throws InterruptedException {
mLayout.setController(mTestableController);
addOneMoreThanRenderLimitBubbles();
// The last child should be GONE, the rest VISIBLE.
for (int i = 0; i < mMaxRenderedBubbles + 1; i++) {
assertEquals(i == mMaxRenderedBubbles ? View.GONE : View.VISIBLE,
mLayout.getChildAt(i).getVisibility());
}
}
@Test
public void testHierarchyChanges() throws InterruptedException {
mLayout.setController(mTestableController);
addOneMoreThanRenderLimitBubbles();
mLayout.setActiveController(mTestableController);
addOneMoreThanBubbleLimitBubbles();
// Make sure the controller was notified of all the views we added.
for (View mView : mViews) {
@@ -115,8 +102,8 @@ public class PhysicsAnimationLayoutTest extends PhysicsAnimationLayoutTestCase {
@Test
public void testUpdateValueNotChained() throws InterruptedException {
mLayout.setController(mTestableController);
addOneMoreThanRenderLimitBubbles();
mLayout.setActiveController(mTestableController);
addOneMoreThanBubbleLimitBubbles();
// Don't chain any values.
mTestableController.setChainedProperties(Sets.newHashSet());
@@ -146,8 +133,8 @@ public class PhysicsAnimationLayoutTest extends PhysicsAnimationLayoutTestCase {
@Test
public void testSetEndActions() throws InterruptedException {
mLayout.setController(mTestableController);
addOneMoreThanRenderLimitBubbles();
mLayout.setActiveController(mTestableController);
addOneMoreThanBubbleLimitBubbles();
mTestableController.setChainedProperties(Sets.newHashSet());
final CountDownLatch xLatch = new CountDownLatch(1);
@@ -189,8 +176,8 @@ public class PhysicsAnimationLayoutTest extends PhysicsAnimationLayoutTestCase {
@Test
public void testRemoveEndListeners() throws InterruptedException {
mLayout.setController(mTestableController);
addOneMoreThanRenderLimitBubbles();
mLayout.setActiveController(mTestableController);
addOneMoreThanBubbleLimitBubbles();
mTestableController.setChainedProperties(Sets.newHashSet());
final CountDownLatch xLatch = new CountDownLatch(1);
@@ -229,8 +216,8 @@ public class PhysicsAnimationLayoutTest extends PhysicsAnimationLayoutTestCase {
public void testSetController() throws InterruptedException {
// 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);
addOneMoreThanBubbleLimitBubbles();
mLayout.setActiveController(mTestableController);
testChainedTranslationAnimations();
TestableAnimationController secondController =
@@ -243,7 +230,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 +253,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,8 +270,8 @@ public class PhysicsAnimationLayoutTest extends PhysicsAnimationLayoutTestCase {
@Test
public void testArePropertiesAnimating() throws InterruptedException {
mLayout.setController(mTestableController);
addOneMoreThanRenderLimitBubbles();
mLayout.setActiveController(mTestableController);
addOneMoreThanBubbleLimitBubbles();
assertFalse(mLayout.arePropertiesAnimating(
DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y));
@@ -307,8 +294,8 @@ public class PhysicsAnimationLayoutTest extends PhysicsAnimationLayoutTestCase {
@Test
public void testCancelAllAnimations() throws InterruptedException {
mLayout.setController(mTestableController);
addOneMoreThanRenderLimitBubbles();
mLayout.setActiveController(mTestableController);
addOneMoreThanBubbleLimitBubbles();
mTestableController.animationForChildAtIndex(0)
.position(1000, 1000)
@@ -321,29 +308,10 @@ public class PhysicsAnimationLayoutTest extends PhysicsAnimationLayoutTestCase {
assertTrue(mViews.get(0).getTranslationY() < 1000);
}
@Test
public void testSetChildVisibility() throws InterruptedException {
mLayout.setController(mTestableController);
addOneMoreThanRenderLimitBubbles();
// The last view should have been set to GONE by the controller, since we added one more
// than the limit and it got pushed off. None of the first children should have been set
// VISIBLE, since they would have been animated in by onChildAdded.
Mockito.verify(mTestableController).setChildVisibility(
mViews.get(mViews.size() - 1), 5, View.GONE);
Mockito.verify(mTestableController, never()).setChildVisibility(
any(View.class), anyInt(), eq(View.VISIBLE));
// Remove the first view, which should cause the last view to become visible again.
mLayout.removeView(mViews.get(0));
Mockito.verify(mTestableController).setChildVisibility(
mViews.get(mViews.size() - 1), 4, View.VISIBLE);
}
/** Standard test of chained translation animations. */
private void testChainedTranslationAnimations() throws InterruptedException {
mLayout.setController(mTestableController);
addOneMoreThanRenderLimitBubbles();
mLayout.setActiveController(mTestableController);
addOneMoreThanBubbleLimitBubbles();
assertEquals(0, mLayout.getChildAt(0).getTranslationX(), .1f);
assertEquals(0, mLayout.getChildAt(1).getTranslationX(), .1f);
@@ -354,11 +322,7 @@ public class PhysicsAnimationLayoutTest extends PhysicsAnimationLayoutTestCase {
waitForPropertyAnimations(DynamicAnimation.TRANSLATION_X);
// Since we enabled chaining, animating the first view to 100 should animate the second to
// 115 (since we set the offset to 15) and the third to 130, etc. Despite the sixth bubble
// not being visible, or animated, make sure that it has the appropriate chained
// translation.
for (int i = 0; i < mMaxRenderedBubbles + 1; i++) {
for (int i = 0; i < mLayout.getChildCount(); i++) {
assertEquals(
100 + i * TEST_TRANSLATION_X_OFFSET,
mLayout.getChildAt(i).getTranslationX(), .1f);
@@ -383,8 +347,8 @@ public class PhysicsAnimationLayoutTest extends PhysicsAnimationLayoutTestCase {
@Test
public void testPhysicsAnimator() throws InterruptedException {
mLayout.setController(mTestableController);
addOneMoreThanRenderLimitBubbles();
mLayout.setActiveController(mTestableController);
addOneMoreThanBubbleLimitBubbles();
Runnable afterAll = Mockito.mock(Runnable.class);
Runnable after = Mockito.spy(new Runnable() {
@@ -430,9 +394,9 @@ 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();
addOneMoreThanBubbleLimitBubbles();
Runnable allEnd = Mockito.mock(Runnable.class);
@@ -452,7 +416,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
@@ -523,8 +487,9 @@ public class PhysicsAnimationLayoutTest extends PhysicsAnimationLayoutTestCase {
}
@Override
protected void setChildVisibility(View child, int index, int visibility) {
super.setChildVisibility(child, index, visibility);
}
void onChildReordered(View child, int oldIndex, int newIndex) {}
@Override
void onActiveControllerForLayout(PhysicsAnimationLayout layout) {}
}
}

View File

@@ -56,7 +56,6 @@ public class PhysicsAnimationLayoutTestCase extends SysuiTestCase {
Handler mMainThreadHandler;
int mMaxRenderedBubbles;
int mSystemWindowInsetSize = 50;
int mCutoutInsetSize = 100;
@@ -69,6 +68,8 @@ public class PhysicsAnimationLayoutTestCase extends SysuiTestCase {
@Mock
private DisplayCutout mCutout;
private int mMaxBubbles;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -79,7 +80,7 @@ public class PhysicsAnimationLayoutTestCase extends SysuiTestCase {
mLayout.setTop(0);
mLayout.setBottom(mHeight);
mMaxRenderedBubbles =
mMaxBubbles =
getContext().getResources().getInteger(R.integer.bubbles_max_rendered);
mMainThreadHandler = new Handler(Looper.getMainLooper());
@@ -96,8 +97,8 @@ public class PhysicsAnimationLayoutTestCase extends SysuiTestCase {
}
/** Add one extra bubble over the limit, so we can make sure it's gone/chains appropriately. */
void addOneMoreThanRenderLimitBubbles() throws InterruptedException {
for (int i = 0; i < mMaxRenderedBubbles + 1; i++) {
void addOneMoreThanBubbleLimitBubbles() throws InterruptedException {
for (int i = 0; i < mMaxBubbles + 1; i++) {
final View newView = new FrameLayout(mContext);
mLayout.addView(newView, 0);
mViews.add(0, newView);
@@ -137,6 +138,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 +156,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)));
}
@@ -267,8 +275,15 @@ public class PhysicsAnimationLayoutTestCase extends SysuiTestCase {
}
@Override
protected void setChildVisibility(View child, int index, int visibility) {
mWrappedController.setChildVisibility(child, index, visibility);
void onChildReordered(View child, int oldIndex, int newIndex) {
runOnMainThreadAndBlock(
() -> mWrappedController.onChildReordered(child, oldIndex, newIndex));
}
@Override
void onActiveControllerForLayout(PhysicsAnimationLayout layout) {
runOnMainThreadAndBlock(
() -> mWrappedController.onActiveControllerForLayout(layout));
}
@Override

View File

@@ -54,8 +54,8 @@ public class StackAnimationControllerTest extends PhysicsAnimationLayoutTestCase
@Before
public void setUp() throws Exception {
super.setUp();
mLayout.setController(mStackController);
addOneMoreThanRenderLimitBubbles();
mLayout.setActiveController(mStackController);
addOneMoreThanBubbleLimitBubbles();
mStackOffset = mLayout.getResources().getDimensionPixelSize(R.dimen.bubble_stack_offset);
}