Merge "Update expanded view "drag to dismiss" animation" into main
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 2018993..a13de9f 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -266,6 +266,10 @@
<dimen name="bubble_bar_manage_menu_item_height">52dp</dimen>
<!-- Size of the icons in the bubble bar manage menu. -->
<dimen name="bubble_bar_manage_menu_item_icon_size">20dp</dimen>
+ <!-- Corner radius for expanded view when bubble bar is used -->
+ <dimen name="bubble_bar_expanded_view_corner_radius">16dp</dimen>
+ <!-- Corner radius for expanded view while it is being dragged -->
+ <dimen name="bubble_bar_expanded_view_corner_radius_dragged">28dp</dimen>
<!-- Bottom and end margin for compat buttons. -->
<dimen name="compat_button_margin">24dp</dimen>
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 84a616f..4e995bc 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
@@ -15,17 +15,28 @@
*/
package com.android.wm.shell.bubbles.bar;
+import static android.view.View.SCALE_X;
+import static android.view.View.SCALE_Y;
+import static android.view.View.TRANSLATION_X;
+import static android.view.View.TRANSLATION_Y;
import static android.view.View.VISIBLE;
+import static android.view.View.X;
+import static android.view.View.Y;
+
+import static com.android.wm.shell.animation.Interpolators.EMPHASIZED;
+import static com.android.wm.shell.animation.Interpolators.EMPHASIZED_DECELERATE;
+import static com.android.wm.shell.bubbles.bar.BubbleBarExpandedView.CORNER_RADIUS;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.Log;
import android.util.Size;
-import android.view.View;
import android.widget.FrameLayout;
import androidx.annotation.Nullable;
@@ -48,15 +59,16 @@
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;
- private static final int EXPANDED_VIEW_ANIMATE_POSITION_DURATION = 300;
+ private static final int EXPANDED_VIEW_SNAP_TO_DISMISS_DURATION = 400;
+ private static final int EXPANDED_VIEW_ANIMATE_TO_REST_DURATION = 400;
private static final int EXPANDED_VIEW_DISMISS_DURATION = 250;
- private static final int EXPANDED_VIEW_DRAG_ANIMATION_DURATION = 150;
+ private static final int EXPANDED_VIEW_DRAG_ANIMATION_DURATION = 400;
/**
* Additional scale applied to expanded view when it is positioned inside a magnetic target.
*/
- private static final float EXPANDED_VIEW_IN_TARGET_SCALE = 0.6f;
- private static final float EXPANDED_VIEW_DRAG_SCALE = 0.5f;
+ private static final float EXPANDED_VIEW_IN_TARGET_SCALE = 0.2f;
+ private static final float EXPANDED_VIEW_DRAG_SCALE = 0.4f;
+ private static final float DISMISS_VIEW_SCALE = 1.25f;
/** Spring config for the expanded view scale-in animation. */
private final PhysicsAnimator.SpringConfig mScaleInSpringConfig =
@@ -72,6 +84,9 @@
/** Animator for animating the expanded view's alpha (including the TaskView inside it). */
private final ValueAnimator mExpandedViewAlphaAnimator = ValueAnimator.ofFloat(0f, 1f);
+ @Nullable
+ private Animator mRunningDragAnimator;
+
private final Context mContext;
private final BubbleBarLayerView mLayerView;
private final BubblePositioner mPositioner;
@@ -232,14 +247,18 @@
Log.w(TAG, "Trying to animate start drag without a bubble");
return;
}
- bbev.setPivotX(bbev.getWidth() / 2f);
- bbev.setPivotY(0f);
- bbev.animate()
- .scaleX(EXPANDED_VIEW_DRAG_SCALE)
- .scaleY(EXPANDED_VIEW_DRAG_SCALE)
- .setInterpolator(Interpolators.EMPHASIZED)
- .setDuration(EXPANDED_VIEW_DRAG_ANIMATION_DURATION)
- .start();
+ setDragPivot(bbev);
+ AnimatorSet animatorSet = new AnimatorSet();
+ // Corner radius gets scaled, apply the reverse scale to ensure we have the desired radius
+ final float cornerRadius = bbev.getDraggedCornerRadius() / EXPANDED_VIEW_DRAG_SCALE;
+ animatorSet.playTogether(
+ ObjectAnimator.ofFloat(bbev, SCALE_X, EXPANDED_VIEW_DRAG_SCALE),
+ ObjectAnimator.ofFloat(bbev, SCALE_Y, EXPANDED_VIEW_DRAG_SCALE),
+ ObjectAnimator.ofFloat(bbev, CORNER_RADIUS, cornerRadius)
+ );
+ animatorSet.setDuration(EXPANDED_VIEW_DRAG_ANIMATION_DURATION).setInterpolator(EMPHASIZED);
+ animatorSet.addListener(new DragAnimatorListenerAdapter(bbev));
+ startNewDragAnimation(animatorSet);
}
/**
@@ -258,6 +277,7 @@
int[] location = bbev.getLocationOnScreen();
int diffFromBottom = mPositioner.getScreenRect().bottom - location[1];
+ cancelAnimations();
bbev.animate()
// 2x distance from bottom so the view flies out
.translationYBy(diffFromBottom * 2)
@@ -276,19 +296,24 @@
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);
- bbev.resetPivot();
- })
- .start();
+
+ AnimatorSet animatorSet = new AnimatorSet();
+ animatorSet.playTogether(
+ ObjectAnimator.ofFloat(bbev, X, restPoint.x),
+ ObjectAnimator.ofFloat(bbev, Y, restPoint.y),
+ ObjectAnimator.ofFloat(bbev, SCALE_X, 1f),
+ ObjectAnimator.ofFloat(bbev, SCALE_Y, 1f),
+ ObjectAnimator.ofFloat(bbev, CORNER_RADIUS, bbev.getRestingCornerRadius())
+ );
+ animatorSet.setDuration(EXPANDED_VIEW_ANIMATE_TO_REST_DURATION).setInterpolator(EMPHASIZED);
+ animatorSet.addListener(new DragAnimatorListenerAdapter(bbev) {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ bbev.resetPivot();
+ }
+ });
+ startNewDragAnimation(animatorSet);
}
/**
@@ -304,17 +329,7 @@
return;
}
- // Calculate scale of expanded view so it fits inside the magnetic target
- float bbevMaxSide = Math.max(bbev.getWidth(), bbev.getHeight());
- View targetView = target.getTargetView();
- float targetMaxSide = Math.max(targetView.getWidth(), targetView.getHeight());
- // Reduce target size to have some padding between the target and expanded view
- targetMaxSide *= EXPANDED_VIEW_IN_TARGET_SCALE;
- float scaleInTarget = targetMaxSide / bbevMaxSide;
-
- // Scale around the top center of the expanded view. Same as when dragging.
- bbev.setPivotX(bbev.getWidth() / 2f);
- bbev.setPivotY(0);
+ setDragPivot(bbev);
// When the view animates into the target, it is scaled down with the pivot at center top.
// Find the point on the view that would be the center of the view at its final scale.
@@ -330,13 +345,13 @@
// Get scaled width of the view and adjust mTmpLocation so that point on x-axis is at the
// center of the view at its current size.
float currentWidth = bbev.getWidth() * bbev.getScaleX();
- mTmpLocation[0] += currentWidth / 2;
+ mTmpLocation[0] += (int) (currentWidth / 2f);
// Since pivotY is at the top of the view, at final scale, top coordinate of the view
// remains the same.
// Get height of the view at final scale and adjust mTmpLocation so that point on y-axis is
// moved down by half of the height at final scale.
- float targetHeight = bbev.getHeight() * scaleInTarget;
- mTmpLocation[1] += targetHeight / 2;
+ float targetHeight = bbev.getHeight() * EXPANDED_VIEW_IN_TARGET_SCALE;
+ mTmpLocation[1] += (int) (targetHeight / 2f);
// mTmpLocation is now set to the point on the view that will be the center of the view once
// scale is applied.
@@ -344,41 +359,61 @@
float xDiff = target.getCenterOnScreen().x - mTmpLocation[0];
float yDiff = target.getCenterOnScreen().y - mTmpLocation[1];
- bbev.animate()
- .translationX(bbev.getTranslationX() + xDiff)
- .translationY(bbev.getTranslationY() + yDiff)
- .scaleX(scaleInTarget)
- .scaleY(scaleInTarget)
- .setDuration(EXPANDED_VIEW_SNAP_TO_DISMISS_DURATION)
- .setInterpolator(Interpolators.EMPHASIZED)
- .withStartAction(() -> bbev.setAnimating(true))
- .withEndAction(() -> {
- bbev.setAnimating(false);
- if (endRunnable != null) {
- endRunnable.run();
- }
- })
- .start();
+ // Corner radius gets scaled, apply the reverse scale to ensure we have the desired radius
+ final float cornerRadius = bbev.getDraggedCornerRadius() / EXPANDED_VIEW_IN_TARGET_SCALE;
+
+ AnimatorSet animatorSet = new AnimatorSet();
+ animatorSet.playTogether(
+ // Move expanded view to the center of dismiss view
+ ObjectAnimator.ofFloat(bbev, TRANSLATION_X, bbev.getTranslationX() + xDiff),
+ ObjectAnimator.ofFloat(bbev, TRANSLATION_Y, bbev.getTranslationY() + yDiff),
+ // Scale expanded view down
+ ObjectAnimator.ofFloat(bbev, SCALE_X, EXPANDED_VIEW_IN_TARGET_SCALE),
+ ObjectAnimator.ofFloat(bbev, SCALE_Y, EXPANDED_VIEW_IN_TARGET_SCALE),
+ // Update corner radius for expanded view
+ ObjectAnimator.ofFloat(bbev, CORNER_RADIUS, cornerRadius),
+ // Scale dismiss view up
+ ObjectAnimator.ofFloat(target.getTargetView(), SCALE_X, DISMISS_VIEW_SCALE),
+ ObjectAnimator.ofFloat(target.getTargetView(), SCALE_Y, DISMISS_VIEW_SCALE)
+ );
+ animatorSet.setDuration(EXPANDED_VIEW_SNAP_TO_DISMISS_DURATION).setInterpolator(
+ EMPHASIZED_DECELERATE);
+ animatorSet.addListener(new DragAnimatorListenerAdapter(bbev) {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ if (endRunnable != null) {
+ endRunnable.run();
+ }
+ }
+ });
+ startNewDragAnimation(animatorSet);
}
/**
* Animate currently expanded view when it is released from dismiss view
*/
- public void animateUnstuckFromDismissView() {
- BubbleBarExpandedView expandedView = getExpandedView();
- if (expandedView == null) {
+ public void animateUnstuckFromDismissView(MagneticTarget target) {
+ BubbleBarExpandedView bbev = getExpandedView();
+ if (bbev == null) {
Log.w(TAG, "Trying to unsnap the expanded view from dismiss without a bubble");
return;
}
- expandedView
- .animate()
- .scaleX(EXPANDED_VIEW_DRAG_SCALE)
- .scaleY(EXPANDED_VIEW_DRAG_SCALE)
- .setDuration(EXPANDED_VIEW_SNAP_TO_DISMISS_DURATION)
- .setInterpolator(Interpolators.EMPHASIZED)
- .withStartAction(() -> expandedView.setAnimating(true))
- .withEndAction(() -> expandedView.setAnimating(false))
- .start();
+ setDragPivot(bbev);
+ // Corner radius gets scaled, apply the reverse scale to ensure we have the desired radius
+ final float cornerRadius = bbev.getDraggedCornerRadius() / EXPANDED_VIEW_DRAG_SCALE;
+ AnimatorSet animatorSet = new AnimatorSet();
+ animatorSet.playTogether(
+ ObjectAnimator.ofFloat(bbev, SCALE_X, EXPANDED_VIEW_DRAG_SCALE),
+ ObjectAnimator.ofFloat(bbev, SCALE_Y, EXPANDED_VIEW_DRAG_SCALE),
+ ObjectAnimator.ofFloat(bbev, CORNER_RADIUS, cornerRadius),
+ ObjectAnimator.ofFloat(target.getTargetView(), SCALE_X, 1f),
+ ObjectAnimator.ofFloat(target.getTargetView(), SCALE_Y, 1f)
+ );
+ animatorSet.setDuration(EXPANDED_VIEW_SNAP_TO_DISMISS_DURATION).setInterpolator(
+ EMPHASIZED_DECELERATE);
+ animatorSet.addListener(new DragAnimatorListenerAdapter(bbev));
+ startNewDragAnimation(animatorSet);
}
/**
@@ -391,6 +426,10 @@
if (bbev != null) {
bbev.animate().cancel();
}
+ if (mRunningDragAnimator != null) {
+ mRunningDragAnimator.cancel();
+ mRunningDragAnimator = null;
+ }
}
private @Nullable BubbleBarExpandedView getExpandedView() {
@@ -438,4 +477,35 @@
final int height = mPositioner.getExpandedViewHeightForBubbleBar(isOverflowExpanded);
return new Size(width, height);
}
+
+ private void startNewDragAnimation(Animator animator) {
+ cancelAnimations();
+ mRunningDragAnimator = animator;
+ animator.start();
+ }
+
+ private static void setDragPivot(BubbleBarExpandedView bbev) {
+ bbev.setPivotX(bbev.getWidth() / 2f);
+ bbev.setPivotY(0f);
+ }
+
+ private class DragAnimatorListenerAdapter extends AnimatorListenerAdapter {
+
+ private final BubbleBarExpandedView mBubbleBarExpandedView;
+
+ DragAnimatorListenerAdapter(BubbleBarExpandedView bbev) {
+ mBubbleBarExpandedView = bbev;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mBubbleBarExpandedView.setAnimating(true);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mBubbleBarExpandedView.setAnimating(false);
+ mRunningDragAnimator = null;
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
index ebb8e3e..eddd43f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
@@ -27,13 +27,13 @@
import android.graphics.Outline;
import android.graphics.Rect;
import android.util.AttributeSet;
+import android.util.FloatProperty;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.widget.FrameLayout;
-import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.wm.shell.R;
import com.android.wm.shell.bubbles.Bubble;
import com.android.wm.shell.bubbles.BubbleExpandedViewManager;
@@ -61,6 +61,23 @@
void onBackPressed();
}
+ /**
+ * A property wrapper around corner radius for the expanded view, handled by
+ * {@link #setCornerRadius(float)} and {@link #getCornerRadius()} methods.
+ */
+ public static final FloatProperty<BubbleBarExpandedView> CORNER_RADIUS = new FloatProperty<>(
+ "cornerRadius") {
+ @Override
+ public void setValue(BubbleBarExpandedView bbev, float radius) {
+ bbev.setCornerRadius(radius);
+ }
+
+ @Override
+ public Float get(BubbleBarExpandedView bbev) {
+ return bbev.getCornerRadius();
+ }
+ };
+
private static final String TAG = BubbleBarExpandedView.class.getSimpleName();
private static final int INVALID_TASK_ID = -1;
@@ -78,7 +95,12 @@
private int mCaptionHeight;
private int mBackgroundColor;
- private float mCornerRadius = 0f;
+ /** Corner radius used when view is resting */
+ private float mRestingCornerRadius = 0f;
+ /** Corner radius applied while dragging */
+ private float mDraggedCornerRadius = 0f;
+ /** Current corner radius */
+ private float mCurrentCornerRadius = 0f;
/**
* Whether we want the {@code TaskView}'s content to be visible (alpha = 1f). If
@@ -118,7 +140,7 @@
setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
- outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mCornerRadius);
+ outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mCurrentCornerRadius);
}
});
}
@@ -155,7 +177,7 @@
new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT);
addView(mTaskView, lp);
mTaskView.setEnableSurfaceClipping(true);
- mTaskView.setCornerRadius(mCornerRadius);
+ mTaskView.setCornerRadius(mCurrentCornerRadius);
mTaskView.setVisibility(VISIBLE);
// Handle view needs to draw on top of task view.
@@ -198,22 +220,24 @@
// TODO (b/275087636): call this when theme/config changes
/** Updates the view based on the current theme. */
public void applyThemeAttrs() {
- boolean supportsRoundedCorners = ScreenDecorationsUtils.supportsRoundedCornersOnWindows(
- mContext.getResources());
+ mRestingCornerRadius = getResources().getDimensionPixelSize(
+ R.dimen.bubble_bar_expanded_view_corner_radius
+ );
+ mDraggedCornerRadius = getResources().getDimensionPixelSize(
+ R.dimen.bubble_bar_expanded_view_corner_radius_dragged
+ );
+
+ mCurrentCornerRadius = mRestingCornerRadius;
+
final TypedArray ta = mContext.obtainStyledAttributes(new int[]{
- android.R.attr.dialogCornerRadius,
android.R.attr.colorBackgroundFloating});
- mCornerRadius = supportsRoundedCorners ? ta.getDimensionPixelSize(0, 0) : 0;
- mCornerRadius = mCornerRadius / 2f;
- mBackgroundColor = ta.getColor(1, Color.WHITE);
-
+ mBackgroundColor = ta.getColor(0, Color.WHITE);
ta.recycle();
-
mCaptionHeight = getResources().getDimensionPixelSize(
R.dimen.bubble_bar_expanded_view_caption_height);
if (mTaskView != null) {
- mTaskView.setCornerRadius(mCornerRadius);
+ mTaskView.setCornerRadius(mCurrentCornerRadius);
updateHandleColor(true /* animated */);
}
}
@@ -396,4 +420,30 @@
public boolean isAnimating() {
return mIsAnimating;
}
+
+ /** @return corner radius that should be applied while view is in rest */
+ public float getRestingCornerRadius() {
+ return mRestingCornerRadius;
+ }
+
+ /** @return corner radius that should be applied while view is being dragged */
+ public float getDraggedCornerRadius() {
+ return mDraggedCornerRadius;
+ }
+
+ /** @return current corner radius */
+ public float getCornerRadius() {
+ return mCurrentCornerRadius;
+ }
+
+ /** Update corner radius */
+ public void setCornerRadius(float cornerRadius) {
+ if (mCurrentCornerRadius != cornerRadius) {
+ mCurrentCornerRadius = cornerRadius;
+ if (mTaskView != null) {
+ mTaskView.setCornerRadius(cornerRadius);
+ }
+ invalidateOutline();
+ }
+ }
}
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 1abbcb6..7d37d60 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
@@ -141,7 +141,7 @@
wasFlungOut: Boolean
) {
isStuckToDismiss = false
- animationHelper.animateUnstuckFromDismissView()
+ animationHelper.animateUnstuckFromDismissView(target)
}
override fun onReleasedInTarget(