summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java133
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java77
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTestCase.java6
7 files changed, 166 insertions, 103 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 5540dc648ca0..37de67ff155c 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -726,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);
}
}
@@ -908,16 +908,14 @@ public class BubbleStackView extends FrameLayout {
if (shouldExpand) {
mBubbleContainer.setActiveController(mExpandedAnimationController);
- mExpandedAnimationController.expandFromStack(
- mStackAnimationController.getStackPositionAlongNearestHorizontalEdge()
- /* collapseTo */,
- () -> {
- updatePointerPosition();
- updateAfter.run();
- } /* after */);
+ mExpandedAnimationController.expandFromStack(() -> {
+ updatePointerPosition();
+ updateAfter.run();
+ } /* after */);
} else {
mBubbleContainer.cancelAllAnimations();
mExpandedAnimationController.collapseBackToStack(
+ mStackAnimationController.getStackPositionAlongNearestHorizontalEdge(),
() -> {
mBubbleContainer.setActiveController(mStackAnimationController);
updateAfter.run();
@@ -1110,6 +1108,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. */
@@ -1200,6 +1202,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;
@@ -1217,7 +1220,7 @@ public class BubbleStackView extends FrameLayout {
resetDesaturationAndDarken();
});
} else {
- mExpandedAnimationController.dismissDraggedOutBubble(() -> {
+ mExpandedAnimationController.dismissDraggedOutBubble(draggedOutBubble, () -> {
mAnimatingMagnet = false;
mShowingDismiss = false;
mDraggingInDismissTarget = false;
@@ -1384,10 +1387,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);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
index 67ae18600f09..1fa0e12452e1 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
@@ -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;
@@ -67,6 +68,12 @@ public class ExpandedAnimationController
/** 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.
@@ -95,42 +102,60 @@ public class ExpandedAnimationController
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;
-
- /**
* Animates expanding the bubbles into a row along the top of the screen.
*/
- public void expandFromStack(PointF collapseTo, Runnable after) {
+ public void expandFromStack(Runnable after) {
+ mAnimatingCollapse = false;
+ mAnimatingExpand = true;
+ mAfterExpand = after;
+
+ startOrUpdateExpandAnimation();
+ }
+
+ /** Animate collapsing the bubbles back to their stacked position. */
+ public void collapseBackToStack(PointF collapsePoint, Runnable after) {
+ mAnimatingExpand = false;
+ mAnimatingCollapse = true;
+ mAfterCollapse = after;
+ mCollapsePoint = collapsePoint;
+
+ startOrUpdateCollapseAnimation();
+ }
+
+ private void startOrUpdateExpandAnimation() {
animationsForChildrenFromIndex(
0, /* startIndex */
- new ChildAnimationConfigurator() {
- @Override
- public void configureAnimationForChildAtIndex(
- int index, PhysicsAnimationLayout.PhysicsPropertyAnimator animation) {
- animation.position(getBubbleLeft(index), getExpandedY());
+ (index, animation) -> animation.position(getBubbleLeft(index), getExpandedY()))
+ .startAll(() -> {
+ mAnimatingExpand = false;
+
+ if (mAfterExpand != null) {
+ mAfterExpand.run();
}
- })
- .startAll(after);
- mCollapseToPoint = collapseTo;
+ mAfterExpand = null;
+ });
}
- /** Animate collapsing the bubbles back to their stacked position. */
- public void collapseBackToStack(Runnable after) {
+ private void startOrUpdateCollapseAnimation() {
// Stack to the left if we're going to the left, or right if not.
- final float sideMultiplier = mLayout.isFirstChildXLeftOfCenter(mCollapseToPoint.x) ? -1 : 1;
-
+ final float sideMultiplier = mLayout.isFirstChildXLeftOfCenter(mCollapsePoint.x) ? -1 : 1;
animationsForChildrenFromIndex(
0, /* startIndex */
- (index, animation) ->
+ (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. */
@@ -174,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)
@@ -187,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) {
@@ -225,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;
}
/**
@@ -326,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,7 +386,16 @@ public class ExpandedAnimationController
updateBubblePositions();
}
+ @Override
+ 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);
@@ -366,6 +404,7 @@ public class ExpandedAnimationController
if (bubble.equals(mBubbleDraggingOut)) {
return;
}
+
animationForChild(bubble)
.translationX(getBubbleLeft(i))
.start();
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java
index b8535adfc280..3a3339249d5b 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java
@@ -139,6 +139,9 @@ 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
@@ -311,40 +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 setActiveController is called.
- if (mController != null) {
- for (DynamicAnimation.ViewProperty property : mController.getAnimatedProperties()) {
- setUpAnimationForChild(property, child, index);
- }
-
- mController.onChildAdded(child, index);
- }
+ 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);
@@ -359,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);
}
}
@@ -453,6 +436,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.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
index 6f1304b5fbcd..ab8752e4195f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
@@ -651,6 +651,9 @@ public class StackAnimationController extends
}
@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);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java
index 5df5c6e32db9..b324235106c2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java
@@ -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);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTest.java
index 95e01774f948..f8b32c213109 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTest.java
@@ -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;
@@ -488,6 +487,9 @@ public class PhysicsAnimationLayoutTest extends PhysicsAnimationLayoutTestCase {
}
@Override
+ void onChildReordered(View child, int oldIndex, int newIndex) {}
+
+ @Override
void onActiveControllerForLayout(PhysicsAnimationLayout layout) {}
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTestCase.java
index f17d7a7da9f3..f633f3996d13 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTestCase.java
@@ -275,6 +275,12 @@ public class PhysicsAnimationLayoutTestCase extends SysuiTestCase {
}
@Override
+ void onChildReordered(View child, int oldIndex, int newIndex) {
+ runOnMainThreadAndBlock(
+ () -> mWrappedController.onChildReordered(child, oldIndex, newIndex));
+ }
+
+ @Override
void onActiveControllerForLayout(PhysicsAnimationLayout layout) {
runOnMainThreadAndBlock(
() -> mWrappedController.onActiveControllerForLayout(layout));