summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Ats Jenk <atsjenk@google.com> 2023-12-05 16:17:46 -0800
committer Ats Jenk <atsjenk@google.com> 2023-12-15 09:29:42 -0800
commit4bbcb85dafce1329a3c6c94e825b72d0abbc19a6 (patch)
treec89545e0d37df656b2000f8fef632180d874abe0
parent145259a2f2ef54b24a01fa75ef6611d70fd735a7 (diff)
Animate the expanded view into the dismiss target
Use MagnetizedObject API to animate the expanded view into the dismiss circle. Animate expanded view away together with dismiss circle Bug: 283991264 Test: drag expanded view into dismiss target, release it Test: drag expanded view into dismiss target, drag it out Test: fling expanded view towards dismiss target Test: fling stuck expanded view out to reset Change-Id: I7c375d72ce8b9876342cbf8c0e9c9cb5b0042834
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java169
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt119
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java15
3 files changed, 238 insertions, 65 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
index 7f34ee0cdd3d..f794fef48f27 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
@@ -23,6 +23,8 @@ import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Point;
import android.util.Log;
+import android.util.Size;
+import android.view.View;
import android.widget.FrameLayout;
import androidx.annotation.Nullable;
@@ -33,6 +35,7 @@ import com.android.wm.shell.bubbles.BubbleOverflow;
import com.android.wm.shell.bubbles.BubblePositioner;
import com.android.wm.shell.bubbles.BubbleViewProvider;
import com.android.wm.shell.bubbles.animation.AnimatableScaleMatrix;
+import com.android.wm.shell.common.magnetictarget.MagnetizedObject.MagneticTarget;
/**
* Helper class to animate a {@link BubbleBarExpandedView} on a bubble.
@@ -44,6 +47,13 @@ public class BubbleBarAnimationHelper {
private static final float EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT = 0.1f;
private static final float EXPANDED_VIEW_ANIMATE_OUT_SCALE_AMOUNT = .75f;
private static final int EXPANDED_VIEW_ALPHA_ANIMATION_DURATION = 150;
+ private static final int EXPANDED_VIEW_SNAP_TO_DISMISS_DURATION = 100;
+ /**
+ * Additional scale applied to expanded view when it is positioned inside a magnetic target.
+ */
+ private static final float EXPANDED_VIEW_IN_TARGET_SCALE = 0.75f;
+ private static final int EXPANDED_VIEW_ANIMATE_POSITION_DURATION = 300;
+ private static final int EXPANDED_VIEW_DISMISS_DURATION = 250;
/** Spring config for the expanded view scale-in animation. */
private final PhysicsAnimator.SpringConfig mScaleInSpringConfig =
@@ -181,7 +191,8 @@ public class BubbleBarAnimationHelper {
Log.w(TAG, "Trying to animate collapse without a bubble");
return;
}
-
+ bbev.setScaleX(1f);
+ bbev.setScaleY(1f);
mExpandedViewContainerMatrix.setScaleX(1f);
mExpandedViewContainerMatrix.setScaleY(1f);
@@ -209,11 +220,124 @@ public class BubbleBarAnimationHelper {
}
/**
+ * Animates dismissal of currently expanded bubble
+ *
+ * @param endRunnable a runnable to run at the end of the animation
+ */
+ public void animateDismiss(Runnable endRunnable) {
+ mIsExpanded = false;
+ final BubbleBarExpandedView bbev = getExpandedView();
+ if (bbev == null) {
+ Log.w(TAG, "Trying to animate dismiss without a bubble");
+ return;
+ }
+
+ int[] location = bbev.getLocationOnScreen();
+ int diffFromBottom = mPositioner.getScreenRect().bottom - location[1];
+
+ bbev.animate()
+ // 2x distance from bottom so the view flies out
+ .translationYBy(diffFromBottom * 2)
+ .setDuration(EXPANDED_VIEW_DISMISS_DURATION)
+ .withEndAction(endRunnable)
+ .start();
+ }
+
+ /**
+ * Animate current expanded bubble back to its rest position
+ */
+ public void animateToRestPosition() {
+ BubbleBarExpandedView bbev = getExpandedView();
+ if (bbev == null) {
+ Log.w(TAG, "Trying to animate expanded view to rest position without a bubble");
+ return;
+ }
+ Point restPoint = getExpandedViewRestPosition(getExpandedViewSize());
+ bbev.animate()
+ .x(restPoint.x)
+ .y(restPoint.y)
+ .scaleX(1f)
+ .scaleY(1f)
+ .setDuration(EXPANDED_VIEW_ANIMATE_POSITION_DURATION)
+ .setInterpolator(Interpolators.EMPHASIZED_DECELERATE)
+ .withStartAction(() -> bbev.setAnimating(true))
+ .withEndAction(() -> bbev.setAnimating(false))
+ .start();
+ }
+
+ /**
+ * Animates currently expanded bubble into the given {@link MagneticTarget}.
+ *
+ * @param target magnetic target to snap to
+ * @param endRunnable a runnable to run at the end of the animation
+ */
+ public void animateIntoTarget(MagneticTarget target, @Nullable Runnable endRunnable) {
+ BubbleBarExpandedView bbev = getExpandedView();
+ if (bbev == null) {
+ Log.w(TAG, "Trying to snap the expanded view to target without a bubble");
+ return;
+ }
+ Point expandedViewCenter = getViewCenterOnScreen(bbev);
+
+ // Calculate the difference between the target's center coordinates and the object's.
+ // Animating the object's x/y properties by these values will center the object on top
+ // of the magnetic target.
+ float xDiff = target.getCenterOnScreen().x - expandedViewCenter.x;
+ float yDiff = target.getCenterOnScreen().y - expandedViewCenter.y;
+
+ // Calculate scale of expanded view so it fits inside the magnetic target
+ float bbevMaxSide = Math.max(bbev.getWidth(), bbev.getHeight());
+ float targetMaxSide = Math.max(target.getTargetView().getWidth(),
+ target.getTargetView().getHeight());
+ float scale = (targetMaxSide * EXPANDED_VIEW_IN_TARGET_SCALE) / bbevMaxSide;
+
+ bbev.animate()
+ .translationX(bbev.getTranslationX() + xDiff)
+ .translationY(bbev.getTranslationY() + yDiff)
+ .scaleX(scale)
+ .scaleY(scale)
+ .setDuration(EXPANDED_VIEW_SNAP_TO_DISMISS_DURATION)
+ .setInterpolator(Interpolators.EMPHASIZED)
+ .withStartAction(() -> bbev.setAnimating(true))
+ .withEndAction(() -> {
+ bbev.setAnimating(false);
+ if (endRunnable != null) {
+ endRunnable.run();
+ }
+ })
+ .start();
+ }
+
+ /**
+ * Animate currently expanded view when it is released from dismiss view
+ */
+ public void animateUnstuckFromDismissView() {
+ BubbleBarExpandedView expandedView = getExpandedView();
+ if (expandedView == null) {
+ Log.w(TAG, "Trying to unsnap the expanded view from dismiss without a bubble");
+ return;
+ }
+ expandedView
+ .animate()
+ .scaleX(1f)
+ .scaleY(1f)
+ .setDuration(EXPANDED_VIEW_SNAP_TO_DISMISS_DURATION)
+ .setInterpolator(Interpolators.EMPHASIZED)
+ .withStartAction(() -> expandedView.setAnimating(true))
+ .withEndAction(() -> expandedView.setAnimating(false))
+ .start();
+ }
+
+ /**
* Cancel current animations
*/
public void cancelAnimations() {
PhysicsAnimator.getInstance(mExpandedViewContainerMatrix).cancel();
mExpandedViewAlphaAnimator.cancel();
+ BubbleBarExpandedView bbev = getExpandedView();
+ if (bbev != null) {
+ bbev.animate().cancel();
+ }
}
private @Nullable BubbleBarExpandedView getExpandedView() {
@@ -231,21 +355,42 @@ public class BubbleBarAnimationHelper {
return;
}
- boolean isOverflowExpanded = mExpandedBubble.getKey().equals(BubbleOverflow.KEY);
- final int padding = mPositioner.getBubbleBarExpandedViewPadding();
- final int width = mPositioner.getExpandedViewWidthForBubbleBar(isOverflowExpanded);
- final int height = mPositioner.getExpandedViewHeightForBubbleBar(isOverflowExpanded);
+ final Size size = getExpandedViewSize();
+ Point position = getExpandedViewRestPosition(size);
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) bbev.getLayoutParams();
- lp.width = width;
- lp.height = height;
+ lp.width = size.getWidth();
+ lp.height = size.getHeight();
bbev.setLayoutParams(lp);
+ bbev.setX(position.x);
+ bbev.setY(position.y);
+ bbev.updateLocation();
+ bbev.maybeShowOverflow();
+ }
+
+ private Point getExpandedViewRestPosition(Size size) {
+ final int padding = mPositioner.getBubbleBarExpandedViewPadding();
+ Point point = new Point();
if (mLayerView.isOnLeft()) {
- bbev.setX(mPositioner.getInsets().left + padding);
+ point.x = mPositioner.getInsets().left + padding;
} else {
- bbev.setX(mPositioner.getAvailableRect().width() - width - padding);
+ point.x = mPositioner.getAvailableRect().width() - size.getWidth() - padding;
}
- bbev.setY(mPositioner.getExpandedViewBottomForBubbleBar() - height);
- bbev.updateLocation();
- bbev.maybeShowOverflow();
+ point.y = mPositioner.getExpandedViewBottomForBubbleBar() - size.getHeight();
+ return point;
+ }
+
+ private Size getExpandedViewSize() {
+ boolean isOverflowExpanded = mExpandedBubble.getKey().equals(BubbleOverflow.KEY);
+ final int width = mPositioner.getExpandedViewWidthForBubbleBar(isOverflowExpanded);
+ final int height = mPositioner.getExpandedViewHeightForBubbleBar(isOverflowExpanded);
+ return new Size(width, height);
+ }
+
+ private Point getViewCenterOnScreen(View view) {
+ Point center = new Point();
+ int[] onScreenLocation = view.getLocationOnScreen();
+ center.x = (int) (onScreenLocation[0] + (view.getWidth() / 2f));
+ center.y = (int) (onScreenLocation[1] + (view.getHeight() / 2f));
+ return center;
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt
index 4ea18f78f5b2..d21545079cc2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt
@@ -16,70 +16,67 @@
package com.android.wm.shell.bubbles.bar
-import android.animation.Animator
-import android.animation.AnimatorListenerAdapter
-import android.graphics.PointF
-import android.graphics.Rect
+import android.annotation.SuppressLint
import android.view.MotionEvent
import android.view.View
-import com.android.wm.shell.animation.Interpolators
import com.android.wm.shell.common.bubbles.DismissView
import com.android.wm.shell.common.bubbles.RelativeTouchListener
+import com.android.wm.shell.common.magnetictarget.MagnetizedObject
/** Controller for handling drag interactions with [BubbleBarExpandedView] */
+@SuppressLint("ClickableViewAccessibility")
class BubbleBarExpandedViewDragController(
private val expandedView: BubbleBarExpandedView,
private val dismissView: DismissView,
+ private val animationHelper: BubbleBarAnimationHelper,
private val onDismissed: () -> Unit
) {
+ var isStuckToDismiss: Boolean = false
+ private set
+
+ private var expandedViewInitialTranslationX = 0f
+ private var expandedViewInitialTranslationY = 0f
+ private val magnetizedExpandedView: MagnetizedObject<BubbleBarExpandedView> =
+ MagnetizedObject.magnetizeView(expandedView)
+ private val magnetizedDismissTarget: MagnetizedObject.MagneticTarget
+
init {
- expandedView.handleView.setOnTouchListener(HandleDragListener())
- }
+ magnetizedExpandedView.magnetListener = MagnetListener()
+ magnetizedExpandedView.animateStuckToTarget =
+ {
+ target: MagnetizedObject.MagneticTarget,
+ _: Float,
+ _: Float,
+ _: Boolean,
+ after: (() -> Unit)? ->
+ animationHelper.animateIntoTarget(target, after)
+ }
- private fun finishDrag(x: Float, y: Float, viewInitialX: Float, viewInitialY: Float) {
- val dismissCircleBounds = Rect().apply { dismissView.circle.getBoundsOnScreen(this) }
- if (dismissCircleBounds.contains(x.toInt(), y.toInt())) {
- onDismissed()
- } else {
- resetExpandedViewPosition(viewInitialX, viewInitialY)
- }
- dismissView.hide()
- }
+ magnetizedDismissTarget =
+ MagnetizedObject.MagneticTarget(dismissView.circle, dismissView.circle.width)
+ magnetizedExpandedView.addTarget(magnetizedDismissTarget)
- private fun resetExpandedViewPosition(initialX: Float, initialY: Float) {
- val listener =
- object : AnimatorListenerAdapter() {
- override fun onAnimationStart(animation: Animator) {
- expandedView.isAnimating = true
- }
+ val dragMotionEventHandler = HandleDragListener()
- override fun onAnimationEnd(animation: Animator) {
- expandedView.isAnimating = false
- }
+ expandedView.handleView.setOnTouchListener { view, event ->
+ if (event.actionMasked == MotionEvent.ACTION_DOWN) {
+ expandedViewInitialTranslationX = expandedView.translationX
+ expandedViewInitialTranslationY = expandedView.translationY
}
- expandedView
- .animate()
- .translationX(initialX)
- .translationY(initialY)
- .setDuration(RESET_POSITION_ANIM_DURATION)
- .setInterpolator(Interpolators.EMPHASIZED_DECELERATE)
- .setListener(listener)
- .start()
+ val magnetConsumed = magnetizedExpandedView.maybeConsumeMotionEvent(event)
+ // Move events can be consumed by the magnetized object
+ if (event.actionMasked == MotionEvent.ACTION_MOVE && magnetConsumed) {
+ return@setOnTouchListener true
+ }
+ return@setOnTouchListener dragMotionEventHandler.onTouch(view, event) || magnetConsumed
+ }
}
private inner class HandleDragListener : RelativeTouchListener() {
-
- private val expandedViewRestPosition = PointF()
-
override fun onDown(v: View, ev: MotionEvent): Boolean {
// While animating, don't allow new touch events
- if (expandedView.isAnimating) {
- return false
- }
- expandedViewRestPosition.x = expandedView.translationX
- expandedViewRestPosition.y = expandedView.translationY
- return true
+ return !expandedView.isAnimating
}
override fun onMove(
@@ -90,8 +87,8 @@ class BubbleBarExpandedViewDragController(
dx: Float,
dy: Float
) {
- expandedView.translationX = expandedViewRestPosition.x + dx
- expandedView.translationY = expandedViewRestPosition.y + dy
+ expandedView.translationX = expandedViewInitialTranslationX + dx
+ expandedView.translationY = expandedViewInitialTranslationY + dy
dismissView.show()
}
@@ -105,16 +102,40 @@ class BubbleBarExpandedViewDragController(
velX: Float,
velY: Float
) {
- finishDrag(ev.rawX, ev.rawY, expandedViewRestPosition.x, expandedViewRestPosition.y)
+ finishDrag()
}
override fun onCancel(v: View, ev: MotionEvent, viewInitialX: Float, viewInitialY: Float) {
- resetExpandedViewPosition(expandedViewRestPosition.x, expandedViewRestPosition.y)
- dismissView.hide()
+ finishDrag()
+ }
+
+ private fun finishDrag() {
+ if (!isStuckToDismiss) {
+ animationHelper.animateToRestPosition()
+ dismissView.hide()
+ }
}
}
- companion object {
- const val RESET_POSITION_ANIM_DURATION = 300L
+ private inner class MagnetListener : MagnetizedObject.MagnetListener {
+ override fun onStuckToTarget(target: MagnetizedObject.MagneticTarget) {
+ isStuckToDismiss = true
+ }
+
+ override fun onUnstuckFromTarget(
+ target: MagnetizedObject.MagneticTarget,
+ velX: Float,
+ velY: Float,
+ wasFlungOut: Boolean
+ ) {
+ isStuckToDismiss = false
+ animationHelper.animateUnstuckFromDismissView()
+ }
+
+ override fun onReleasedInTarget(target: MagnetizedObject.MagneticTarget) {
+ onDismissed()
+ dismissView.hide()
+ }
}
}
+
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
index bdb0e206e490..12114519d086 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
@@ -18,6 +18,7 @@ package com.android.wm.shell.bubbles.bar;
import static com.android.wm.shell.animation.Interpolators.ALPHA_IN;
import static com.android.wm.shell.animation.Interpolators.ALPHA_OUT;
+import static com.android.wm.shell.bubbles.Bubbles.DISMISS_USER_GESTURE;
import android.annotation.Nullable;
import android.content.Context;
@@ -36,7 +37,6 @@ import com.android.wm.shell.bubbles.BubbleController;
import com.android.wm.shell.bubbles.BubbleOverflow;
import com.android.wm.shell.bubbles.BubblePositioner;
import com.android.wm.shell.bubbles.BubbleViewProvider;
-import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.bubbles.DeviceConfig;
import com.android.wm.shell.bubbles.DismissViewUtils;
import com.android.wm.shell.common.bubbles.DismissView;
@@ -206,10 +206,13 @@ public class BubbleBarLayerView extends FrameLayout
}
});
- mDragController = new BubbleBarExpandedViewDragController(mExpandedView, mDismissView,
+ mDragController = new BubbleBarExpandedViewDragController(
+ mExpandedView,
+ mDismissView,
+ mAnimationHelper,
() -> {
mBubbleController.dismissBubble(mExpandedBubble.getKey(),
- Bubbles.DISMISS_USER_GESTURE);
+ DISMISS_USER_GESTURE);
return Unit.INSTANCE;
});
@@ -241,7 +244,11 @@ public class BubbleBarLayerView extends FrameLayout
mIsExpanded = false;
final BubbleBarExpandedView viewToRemove = mExpandedView;
mEducationViewController.hideEducation(/* animated = */ true);
- mAnimationHelper.animateCollapse(() -> removeView(viewToRemove));
+ if (mDragController != null && mDragController.isStuckToDismiss()) {
+ mAnimationHelper.animateDismiss(() -> removeView(viewToRemove));
+ } else {
+ mAnimationHelper.animateCollapse(() -> removeView(viewToRemove));
+ }
mBubbleController.getSysuiProxy().onStackExpandChanged(false);
mExpandedView = null;
mDragController = null;