Merge changes I485f6346,I24b0c646 into main
* changes:
Animate alpha for bubbles and background (3/n)
Use a reveal animator for bubble icons (2/n)
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index 9c6ba8b..1dbf445 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -205,7 +205,6 @@
public BubbleBarView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
- setAlpha(0);
setVisibility(INVISIBLE);
mIconOverlapAmount = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_overlap);
mBubbleBarPadding = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_spacing);
@@ -320,6 +319,22 @@
}
/**
+ * Set alpha for bubble views
+ */
+ public void setBubbleAlpha(float alpha) {
+ for (int i = 0; i < getChildCount(); i++) {
+ getChildAt(i).setAlpha(alpha);
+ }
+ }
+
+ /**
+ * Set alpha for bar background
+ */
+ public void setBackgroundAlpha(float alpha) {
+ mBubbleBarBackground.setAlpha((int) (255 * alpha));
+ }
+
+ /**
* Sets new icon sizes and newBubbleBarPadding between icons and bubble bar borders.
*
* @param newIconSize new icon size
@@ -1029,7 +1044,7 @@
// where the bubble will end up when the animation ends
final float targetX = expandedX + expandedBarShift;
bv.setTranslationX(widthState * (targetX - collapsedX) + collapsedX);
- bv.setAlpha(1);
+ bv.setVisibility(VISIBLE);
} else {
// If bar is on the right, account for bubble bar expanding and shifting left
final float collapsedBarShift = onLeft ? 0 : currentWidth - collapsedWidth;
@@ -1039,9 +1054,9 @@
// the overflow.
if (widthState == 0) {
if (bv.isOverflow() || i > MAX_VISIBLE_BUBBLES_COLLAPSED - 1) {
- bv.setAlpha(0);
+ bv.setVisibility(INVISIBLE);
} else {
- bv.setAlpha(1);
+ bv.setVisibility(VISIBLE);
}
}
}
@@ -1349,7 +1364,7 @@
* touch bounds.
*/
public boolean isEventOverAnyItem(MotionEvent ev) {
- if (getVisibility() == View.VISIBLE) {
+ if (getVisibility() == VISIBLE) {
getBoundsOnScreen(mTempRect);
return mTempRect.contains((int) ev.getX(), (int) ev.getY());
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index d0be5ec..570b1b9 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;
@@ -80,6 +86,9 @@
// These are exposed to {@link BubbleStashController} to animate for stashing/un-stashing
private final MultiValueAlpha mBubbleBarAlpha;
+ private final AnimatedFloat mBubbleBarBubbleAlpha = new AnimatedFloat(this::updateBubbleAlpha);
+ private final AnimatedFloat mBubbleBarBackgroundAlpha = new AnimatedFloat(
+ this::updateBackgroundAlpha);
private final AnimatedFloat mBubbleBarScaleX = new AnimatedFloat(this::updateScaleX);
private final AnimatedFloat mBubbleBarScaleY = new AnimatedFloat(this::updateScaleY);
private final AnimatedFloat mBubbleBarBackgroundScaleX = new AnimatedFloat(
@@ -262,6 +271,14 @@
return mBubbleBarAlpha;
}
+ public AnimatedFloat getBubbleBarBubbleAlpha() {
+ return mBubbleBarBubbleAlpha;
+ }
+
+ public AnimatedFloat getBubbleBarBackgroundAlpha() {
+ return mBubbleBarBackgroundAlpha;
+ }
+
public AnimatedFloat getBubbleBarScaleX() {
return mBubbleBarScaleX;
}
@@ -555,6 +572,14 @@
mBarView.setBackgroundScaleY(scale);
}
+ private void updateBubbleAlpha(float alpha) {
+ mBarView.setBubbleAlpha(alpha);
+ }
+
+ private void updateBackgroundAlpha(float alpha) {
+ mBarView.setBackgroundAlpha(alpha);
+ }
+
//
// Manipulating the specific bubble views in the bar
//
@@ -840,6 +865,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..5d1e890 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
@@ -66,6 +67,8 @@
// bubble bar properties
private lateinit var bubbleBarAlpha: MultiPropertyFactory<View>.MultiProperty
+ private lateinit var bubbleBarBubbleAlpha: AnimatedFloat
+ private lateinit var bubbleBarBackgroundAlpha: AnimatedFloat
private lateinit var bubbleBarTranslationYAnimator: AnimatedFloat
private lateinit var bubbleBarBackgroundScaleX: AnimatedFloat
private lateinit var bubbleBarBackgroundScaleY: AnimatedFloat
@@ -149,6 +152,8 @@
bubbleBarTranslationYAnimator = bubbleBarViewController.bubbleBarTranslationY
// bubble bar has only alpha property, getting it at index 0
bubbleBarAlpha = bubbleBarViewController.bubbleBarAlpha.get(/* index= */ 0)
+ bubbleBarBubbleAlpha = bubbleBarViewController.bubbleBarBubbleAlpha
+ bubbleBarBackgroundAlpha = bubbleBarViewController.bubbleBarBackgroundAlpha
bubbleBarBackgroundScaleX = bubbleBarViewController.bubbleBarBackgroundScaleX
bubbleBarBackgroundScaleY = bubbleBarViewController.bubbleBarBackgroundScaleY
stashedHeight = bubbleStashedHandleViewController?.stashedHeight ?: 0
@@ -163,7 +168,9 @@
bubbleBarBackgroundScaleX.animateToValue(1f),
bubbleBarBackgroundScaleY.animateToValue(1f),
bubbleBarTranslationYAnimator.animateToValue(bubbleBarTranslationY),
- bubbleBarAlpha.animateToValue(1f)
+ bubbleBarAlpha.animateToValue(1f),
+ bubbleBarBubbleAlpha.animateToValue(1f),
+ bubbleBarBackgroundAlpha.animateToValue(1f)
)
} else {
isStashed = true
@@ -181,6 +188,8 @@
stashHandleViewAlpha?.value = 0f
this.bubbleBarTranslationYAnimator.updateValue(bubbleBarTranslationY)
bubbleBarAlpha.setValue(1f)
+ bubbleBarBubbleAlpha.updateValue(1f)
+ bubbleBarBackgroundAlpha.updateValue(1f)
bubbleBarBackgroundScaleX.updateValue(1f)
bubbleBarBackgroundScaleY.updateValue(1f)
isStashed = false
@@ -192,6 +201,9 @@
stashHandleViewAlpha?.value = 1f
this.bubbleBarTranslationYAnimator.updateValue(getStashTranslation())
bubbleBarAlpha.setValue(0f)
+ // Reset bubble and background alpha to 1 and only keep the bubble bar alpha at 0
+ bubbleBarBubbleAlpha.updateValue(1f)
+ bubbleBarBackgroundAlpha.updateValue(1f)
bubbleBarBackgroundScaleX.updateValue(getStashScaleX())
bubbleBarBackgroundScaleY.updateValue(getStashScaleY())
isStashed = true
@@ -258,6 +270,10 @@
override fun getHandleTranslationY(): Float? = bubbleStashedHandleViewController?.translationY
+ override fun getHandleBounds(bounds: Rect) {
+ bubbleStashedHandleViewController?.getBounds(bounds)
+ }
+
private fun getStashTranslation(): Float {
return (bubbleBarTranslationY - stashedHeight) / 2f
}
@@ -288,13 +304,22 @@
val alphaDuration = if (isStashed) duration else TASKBAR_STASH_ALPHA_DURATION
val alphaDelay = if (isStashed) TASKBAR_STASH_ALPHA_START_DELAY else 0L
animatorSet.play(
- createStashAlphaAnimator(isStashed).apply {
+ createBackgroundAlphaAnimator(isStashed).apply {
this.duration = max(0L, alphaDuration - alphaDelay)
this.startDelay = alphaDelay
this.interpolator = LINEAR
}
)
+ val iconAlphaTarget = if (isStashed) 0f else 1f
+ animatorSet.play(
+ bubbleBarBubbleAlpha.animateToValue(iconAlphaTarget).apply {
+ this.duration = TASKBAR_STASH_ALPHA_DURATION
+ this.startDelay = TASKBAR_STASH_ALPHA_START_DELAY
+ this.interpolator = LINEAR
+ }
+ )
+
animatorSet.play(
createSpringOnStashAnimator(isStashed).apply {
this.duration = duration
@@ -303,6 +328,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
@@ -326,10 +358,21 @@
}
)
+ animatorSet.doOnStart {
+ if (!isStashed) {
+ bubbleBarBackgroundAlpha.updateValue(0f)
+ bubbleBarBubbleAlpha.updateValue(0f)
+ bubbleBarAlpha.value = 1f
+ }
+ }
animatorSet.doOnEnd {
animator = null
controllersAfterInitAction.runAfterInit {
if (isStashed) {
+ bubbleBarAlpha.value = 0f
+ // reset bubble view alpha
+ bubbleBarBubbleAlpha.updateValue(1f)
+ bubbleBarBackgroundAlpha.updateValue(1f)
bubbleBarViewController.isExpanded = false
}
taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
@@ -338,11 +381,11 @@
return animatorSet
}
- private fun createStashAlphaAnimator(isStashed: Boolean): AnimatorSet {
+ private fun createBackgroundAlphaAnimator(isStashed: Boolean): AnimatorSet {
val stashHandleAlphaTarget = if (isStashed) 1f else 0f
val barAlphaTarget = if (isStashed) 0f else 1f
return AnimatorSet().apply {
- play(bubbleBarAlpha.animateToValue(barAlphaTarget))
+ play(bubbleBarBackgroundAlpha.animateToValue(barAlphaTarget))
play(stashHandleViewAlpha?.animateToValue(stashHandleAlphaTarget))
}
}
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..1d13956 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
@@ -80,6 +81,8 @@
private lateinit var barScaleX: AnimatedFloat
private lateinit var barScaleY: AnimatedFloat
private lateinit var barAlpha: MultiValueAlpha
+ private lateinit var bubbleAlpha: AnimatedFloat
+ private lateinit var backgroundAlpha: AnimatedFloat
private lateinit var stashedHandleAlpha: MultiValueAlpha
private lateinit var stashedHandleScale: AnimatedFloat
private lateinit var stashedHandleTranslationY: AnimatedFloat
@@ -299,14 +302,20 @@
barScaleX = AnimatedFloat { value -> bubbleBarView.scaleX = value }
barScaleY = AnimatedFloat { value -> bubbleBarView.scaleY = value }
barAlpha = MultiValueAlpha(bubbleBarView, 1 /* num alpha channels */)
+ bubbleAlpha = AnimatedFloat { value -> bubbleBarView.setBubbleAlpha(value) }
+ backgroundAlpha = AnimatedFloat { value -> bubbleBarView.setBackgroundAlpha(value) }
whenever(bubbleBarViewController.hasBubbles()).thenReturn(true)
whenever(bubbleBarViewController.bubbleBarTranslationY).thenReturn(barTranslationY)
whenever(bubbleBarViewController.bubbleBarBackgroundScaleX).thenReturn(barScaleX)
whenever(bubbleBarViewController.bubbleBarBackgroundScaleY).thenReturn(barScaleY)
whenever(bubbleBarViewController.bubbleBarAlpha).thenReturn(barAlpha)
+ whenever(bubbleBarViewController.bubbleBarBubbleAlpha).thenReturn(bubbleAlpha)
+ whenever(bubbleBarViewController.bubbleBarBackgroundAlpha).thenReturn(backgroundAlpha)
whenever(bubbleBarViewController.bubbleBarCollapsedWidth).thenReturn(BUBBLE_BAR_WIDTH)
whenever(bubbleBarViewController.bubbleBarCollapsedHeight).thenReturn(BUBBLE_BAR_HEIGHT)
+ whenever(bubbleBarViewController.createRevealAnimatorForStashChange(any()))
+ .thenReturn(AnimatorSet())
}
private fun setUpBubbleStashedHandleViewController() {