Use a reveal animator for bubble icons (2/n)
Use a similar animation for bubble bar icons as we use for taskbar. When
stashing or unstashing, use a reveal animator to show the icons.
Previously we were scaling the icons to the desired size.
New reveal animator matches what is used for taskbar.
Bug: 345488489
Test: TransientBubbleStashControllerTest
Test: stash and unstash bubble bar in app by swiping up from taskbar
Test: expand and collapse bubble bar in app by swiping up on bar
Test: expand and collapse bubble bar on home screen by tapping on it
Flag: com.android.wm.shell.enable_bubble_bar
Change-Id: I24b0c64673d6becfa2ed68993bb95fe78e105670
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index d0be5ec..c6803dc 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -18,6 +18,11 @@
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
+import static com.android.launcher3.taskbar.bubbles.BubbleView.STASH_TRANSLATION_Y;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.PointF;
@@ -34,6 +39,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatedFloat;
+import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
import com.android.launcher3.taskbar.TaskbarActivityContext;
import com.android.launcher3.taskbar.TaskbarControllers;
import com.android.launcher3.taskbar.TaskbarInsetsController;
@@ -840,6 +846,53 @@
}
/**
+ * Create an animator for showing or hiding bubbles when stashed state changes
+ *
+ * @param isStashed {@code true} when bubble bar should be stashed to the handle
+ */
+ public Animator createRevealAnimatorForStashChange(boolean isStashed) {
+ Rect stashedHandleBounds = new Rect();
+ mBubbleStashController.getHandleBounds(stashedHandleBounds);
+ int childCount = mBarView.getChildCount();
+ float newChildWidth = (float) stashedHandleBounds.width() / childCount;
+ float stashTranslationY = -mBubbleStashController.getBubbleBarTranslationY();
+ AnimatorSet animatorSet = new AnimatorSet();
+ for (int i = 0; i < childCount; i++) {
+ BubbleView child = (BubbleView) mBarView.getChildAt(i);
+ final float startTransY = isStashed ? 0f : stashTranslationY;
+ final float endTransY = isStashed ? stashTranslationY : 0f;
+ animatorSet.play(
+ ObjectAnimator.ofFloat(child, STASH_TRANSLATION_Y, startTransY, endTransY));
+ animatorSet.play(
+ createRevealAnimForBubble(child, isStashed, stashedHandleBounds,
+ newChildWidth));
+ }
+ return animatorSet;
+ }
+
+ private Animator createRevealAnimForBubble(BubbleView bubbleView, boolean isStashed,
+ Rect stashedHandleBounds, float newWidth) {
+ Rect viewBounds = new Rect(0, 0, bubbleView.getWidth(), bubbleView.getHeight());
+
+ int viewCenterY = viewBounds.centerY();
+ int halfHandleHeight = stashedHandleBounds.height() / 2;
+ int widthDelta = Math.max(0, (int) (viewBounds.width() - newWidth) / 2);
+
+ Rect stashedViewBounds = new Rect(
+ viewBounds.left + widthDelta,
+ viewCenterY - halfHandleHeight,
+ viewBounds.right - widthDelta,
+ viewCenterY + halfHandleHeight
+ );
+
+ float viewRadius = 0f; // Use 0 to not clip the new message dot or the app icon
+ float stashedRadius = stashedViewBounds.height() / 2f;
+
+ return new RoundedRectRevealOutlineProvider(viewRadius, stashedRadius, viewBounds,
+ stashedViewBounds).createRevealAnimator(bubbleView, !isStashed, 0);
+ }
+
+ /**
* Listener to receive updates about bubble bar bounds changing
*/
public interface BubbleBarBoundsChangeListener {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
index fdd385a..3640c3b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
@@ -187,6 +187,13 @@
}
/**
+ * Returns bounds of the stashed handle view
+ */
+ public void getBounds(Rect bounds) {
+ bounds.set(mStashedHandleBounds);
+ }
+
+ /**
* Called when system ui state changes. Bubbles don't show when the device is locked.
*/
public void setHiddenForSysui(boolean hidden) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
index 591a9da..cc6b49a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
@@ -20,12 +20,14 @@
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.AttributeSet;
+import android.util.FloatProperty;
import android.view.LayoutInflater;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.ImageView;
@@ -48,12 +50,27 @@
public static final int DEFAULT_PATH_SIZE = 100;
+ public static FloatProperty<BubbleView> STASH_TRANSLATION_Y = new FloatProperty<>(
+ "stashTranslationY") {
+ @Override
+ public void setValue(BubbleView bubbleView, float transY) {
+ bubbleView.setStashTranslationY(transY);
+ }
+
+ @Override
+ public Float get(BubbleView bubbleView) {
+ return bubbleView.mStashTranslationY;
+ }
+ };
+
private final ImageView mBubbleIcon;
private final ImageView mAppIcon;
private int mBubbleSize;
private float mDragTranslationX;
private float mOffsetX;
+ private float mTranslationY;
+ private float mStashTranslationY;
private DotRenderer mDotRenderer;
private DotRenderer.DrawParams mDrawParams;
@@ -110,6 +127,10 @@
setFocusable(true);
setClickable(true);
+
+ // We manage the shadow ourselves when creating the bitmap
+ setOutlineAmbientShadowColor(Color.TRANSPARENT);
+ setOutlineSpotShadowColor(Color.TRANSPARENT);
}
private void updateBubbleSizeAndDotRender() {
@@ -152,16 +173,34 @@
applyDragTranslation();
}
+ private void applyDragTranslation() {
+ setTranslationX(mDragTranslationX + mOffsetX);
+ }
+
+ /**
+ * Set translation in y direction during stash and unstash from handle
+ */
+ public void setStashTranslationY(float translationY) {
+ mStashTranslationY = translationY;
+ applyTranslationY();
+ }
+
+ @Override
+ public void setTranslationY(float translationY) {
+ mTranslationY = translationY;
+ applyTranslationY();
+ }
+
+ private void applyTranslationY() {
+ super.setTranslationY(mTranslationY + mStashTranslationY);
+ }
+
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
updateBubbleSizeAndDotRender();
}
- private void applyDragTranslation() {
- setTranslationX(mDragTranslationX + mOffsetX);
- }
-
@Override
public void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
index 8d63217..9721792 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
@@ -16,6 +16,7 @@
package com.android.launcher3.taskbar.bubbles.stashing
+import android.graphics.Rect
import android.view.InsetsController
import android.view.MotionEvent
import android.view.View
@@ -146,6 +147,9 @@
/** Returns the translation of the handle. */
fun getHandleTranslationY(): Float?
+ /** Returns bounds of the handle */
+ fun getHandleBounds(bounds: Rect)
+
/**
* Returns bubble bar Y position according to [isBubblesShowingOnHome] and
* [isBubblesShowingOnOverview] values. Default implementation only analyse
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
index eaf4bf9..7d6f7ad 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
@@ -19,6 +19,7 @@
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.AnimatorSet
+import android.graphics.Rect
import android.view.MotionEvent
import android.view.View
import com.android.launcher3.anim.AnimatedFloat
@@ -200,6 +201,10 @@
override fun getHandleTranslationY(): Float? = null
+ override fun getHandleBounds(bounds: Rect) {
+ // no op since does not have a handle view
+ }
+
private fun updateExpandedState(expand: Boolean) {
if (bubbleBarViewController.isHiddenForNoBubbles) {
// If there are no bubbles the bar is invisible, nothing to do here.
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
index 0700ab7..5f7c79c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
@@ -19,6 +19,7 @@
import android.animation.Animator
import android.animation.AnimatorSet
import android.content.Context
+import android.graphics.Rect
import android.view.MotionEvent
import android.view.View
import androidx.annotation.VisibleForTesting
@@ -258,6 +259,10 @@
override fun getHandleTranslationY(): Float? = bubbleStashedHandleViewController?.translationY
+ override fun getHandleBounds(bounds: Rect) {
+ bubbleStashedHandleViewController?.getBounds(bounds)
+ }
+
private fun getStashTranslation(): Float {
return (bubbleBarTranslationY - stashedHeight) / 2f
}
@@ -303,6 +308,13 @@
)
animatorSet.play(
+ bubbleBarViewController.createRevealAnimatorForStashChange(isStashed).apply {
+ this.duration = duration
+ this.interpolator = EMPHASIZED
+ }
+ )
+
+ animatorSet.play(
bubbleStashedHandleViewController?.createRevealAnimToIsStashed(isStashed)?.apply {
this.duration = duration
this.interpolator = EMPHASIZED
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
index a745b66..20f1ff8 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
@@ -16,6 +16,7 @@
package com.android.launcher3.taskbar.bubbles.stashing
+import android.animation.AnimatorSet
import android.animation.AnimatorTestRule
import android.content.Context
import android.view.View
@@ -307,6 +308,8 @@
whenever(bubbleBarViewController.bubbleBarAlpha).thenReturn(barAlpha)
whenever(bubbleBarViewController.bubbleBarCollapsedWidth).thenReturn(BUBBLE_BAR_WIDTH)
whenever(bubbleBarViewController.bubbleBarCollapsedHeight).thenReturn(BUBBLE_BAR_HEIGHT)
+ whenever(bubbleBarViewController.createRevealAnimatorForStashChange(any()))
+ .thenReturn(AnimatorSet())
}
private fun setUpBubbleStashedHandleViewController() {