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(