mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-03-04 01:46:49 +00:00
Merge "Animate the stash handle for new bubbles" into main
This commit is contained in:
committed by
Android (Google) Code Review
commit
98bbc2b46d
@@ -96,6 +96,8 @@ public class BubbleBarView extends FrameLayout {
|
||||
|
||||
private final BubbleBarBackground mBubbleBarBackground;
|
||||
|
||||
private boolean mIsAnimatingNewBubble = false;
|
||||
|
||||
/**
|
||||
* The current bounds of all the bubble bar. Note that these bounds may not account for
|
||||
* translation. The bounds should be retrieved using {@link #getBubbleBarBounds()} which
|
||||
@@ -457,6 +459,7 @@ public class BubbleBarView extends FrameLayout {
|
||||
|
||||
/** Prepares for animating a bubble while being stashed. */
|
||||
public void prepareForAnimatingBubbleWhileStashed(String bubbleKey) {
|
||||
mIsAnimatingNewBubble = true;
|
||||
// we're about to animate the new bubble in. the new bubble has already been added to this
|
||||
// view, but we're currently stashed, so before we can start the animation we need make
|
||||
// everything else in the bubble bar invisible, except for the bubble that's being animated.
|
||||
@@ -477,6 +480,9 @@ public class BubbleBarView extends FrameLayout {
|
||||
|
||||
/** Resets the state after the bubble animation completed. */
|
||||
public void onAnimatingBubbleCompleted() {
|
||||
mIsAnimatingNewBubble = false;
|
||||
// setting the background triggers relayout so no need to explicitly invalidate after the
|
||||
// animation
|
||||
setBackground(mBubbleBarBackground);
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
final BubbleView view = (BubbleView) getChildAt(i);
|
||||
@@ -521,6 +527,12 @@ public class BubbleBarView extends FrameLayout {
|
||||
* on the expanded state.
|
||||
*/
|
||||
private void updateChildrenRenderNodeProperties() {
|
||||
if (mIsAnimatingNewBubble) {
|
||||
// don't update bubbles if a new bubble animation is playing.
|
||||
// the bubble bar will redraw itself via onLayout after the animation.
|
||||
return;
|
||||
}
|
||||
|
||||
final float widthState = (float) mWidthAnimator.getAnimatedValue();
|
||||
final float currentWidth = getWidth();
|
||||
final float expandedWidth = expandedWidth();
|
||||
|
||||
@@ -51,6 +51,15 @@ public class BubbleStashController {
|
||||
*/
|
||||
private static final float STASHED_BAR_SCALE = 0.5f;
|
||||
|
||||
/** The duration of hiding and showing the stashed handle as part of a new bubble animation. */
|
||||
private static final long NEW_BUBBLE_HANDLE_ANIMATION_DURATION_MS = 200;
|
||||
|
||||
/** The translation Y value the handle animates to when hiding it for a new bubble. */
|
||||
private static final int NEW_BUBBLE_HIDE_HANDLE_ANIMATION_TRANSLATION_Y = -20;
|
||||
|
||||
/** The alpha value the handle animates to when hiding it for a new bubble. */
|
||||
public static final float NEW_BUBBLE_HIDE_HANDLE_ANIMATION_ALPHA = 0.5f;
|
||||
|
||||
protected final TaskbarActivityContext mActivity;
|
||||
|
||||
// Initialized in init.
|
||||
@@ -64,6 +73,7 @@ public class BubbleStashController {
|
||||
private AnimatedFloat mIconScaleForStash;
|
||||
private AnimatedFloat mIconTranslationYForStash;
|
||||
private MultiPropertyFactory.MultiProperty mBubbleStashedHandleAlpha;
|
||||
private AnimatedFloat mBubbleStashedHandleTranslationY;
|
||||
|
||||
private boolean mRequestedStashState;
|
||||
private boolean mRequestedExpandedState;
|
||||
@@ -95,6 +105,7 @@ public class BubbleStashController {
|
||||
|
||||
mBubbleStashedHandleAlpha = mHandleViewController.getStashedHandleAlpha().get(
|
||||
StashedHandleViewController.ALPHA_INDEX_STASHED);
|
||||
mBubbleStashedHandleTranslationY = mHandleViewController.getStashedHandleTranslationY();
|
||||
|
||||
mStashedHeight = mHandleViewController.getStashedHeight();
|
||||
mUnstashedHeight = mHandleViewController.getUnstashedHeight();
|
||||
@@ -362,4 +373,35 @@ public class BubbleStashController {
|
||||
public void setBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
|
||||
mHandleViewController.setBubbleBarLocation(bubbleBarLocation);
|
||||
}
|
||||
|
||||
/** Returns the x position of the center of the stashed handle. */
|
||||
public float getStashedHandleCenterX() {
|
||||
return mHandleViewController.getStashedHandleCenterX();
|
||||
}
|
||||
|
||||
/** Returns the animation for hiding the handle before a new bubble animates in. */
|
||||
public AnimatorSet buildHideHandleAnimationForNewBubble() {
|
||||
AnimatorSet animatorSet = new AnimatorSet();
|
||||
animatorSet.playTogether(
|
||||
mBubbleStashedHandleTranslationY.animateToValue(
|
||||
NEW_BUBBLE_HIDE_HANDLE_ANIMATION_TRANSLATION_Y),
|
||||
mBubbleStashedHandleAlpha.animateToValue(NEW_BUBBLE_HIDE_HANDLE_ANIMATION_ALPHA));
|
||||
animatorSet.setDuration(NEW_BUBBLE_HANDLE_ANIMATION_DURATION_MS);
|
||||
return animatorSet;
|
||||
}
|
||||
|
||||
/** Sets the alpha value of the stashed handle. */
|
||||
public void setStashAlpha(float alpha) {
|
||||
mBubbleStashedHandleAlpha.setValue(alpha);
|
||||
}
|
||||
|
||||
/** Returns the animation for showing the handle after a new bubble animated in. */
|
||||
public AnimatorSet buildShowHandleAnimationForNewBubble() {
|
||||
AnimatorSet animatorSet = new AnimatorSet();
|
||||
animatorSet.playTogether(
|
||||
mBubbleStashedHandleTranslationY.animateToValue(0),
|
||||
mBubbleStashedHandleAlpha.animateToValue(1));
|
||||
animatorSet.setDuration(NEW_BUBBLE_HANDLE_ANIMATION_DURATION_MS);
|
||||
return animatorSet;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import android.view.View;
|
||||
import android.view.ViewOutlineProvider;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.anim.AnimatedFloat;
|
||||
import com.android.launcher3.anim.RevealOutlineAnimation;
|
||||
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
|
||||
import com.android.launcher3.taskbar.StashedHandleView;
|
||||
@@ -47,7 +48,7 @@ public class BubbleStashedHandleViewController {
|
||||
|
||||
private final TaskbarActivityContext mActivity;
|
||||
private final StashedHandleView mStashedHandleView;
|
||||
private final MultiValueAlpha mTaskbarStashedHandleAlpha;
|
||||
private final MultiValueAlpha mStashedHandleAlpha;
|
||||
|
||||
// Initialized in init.
|
||||
private BubbleBarViewController mBarViewController;
|
||||
@@ -58,6 +59,12 @@ public class BubbleStashedHandleViewController {
|
||||
private int mStashedHandleWidth;
|
||||
private int mStashedHandleHeight;
|
||||
|
||||
private final AnimatedFloat mStashedHandleTranslationY =
|
||||
new AnimatedFloat(this::updateTranslationY);
|
||||
|
||||
// Modified when swipe up is happening on the stashed handle or task bar.
|
||||
private float mSwipeUpTranslationY;
|
||||
|
||||
// The bounds we want to clip to in the settled state when showing the stashed handle.
|
||||
private final Rect mStashedHandleBounds = new Rect();
|
||||
|
||||
@@ -75,7 +82,7 @@ public class BubbleStashedHandleViewController {
|
||||
StashedHandleView stashedHandleView) {
|
||||
mActivity = activity;
|
||||
mStashedHandleView = stashedHandleView;
|
||||
mTaskbarStashedHandleAlpha = new MultiValueAlpha(mStashedHandleView, 1);
|
||||
mStashedHandleAlpha = new MultiValueAlpha(mStashedHandleView, 1);
|
||||
}
|
||||
|
||||
public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers) {
|
||||
@@ -93,7 +100,7 @@ public class BubbleStashedHandleViewController {
|
||||
R.dimen.transient_taskbar_bottom_margin);
|
||||
mStashedHandleView.getLayoutParams().height = mBarSize + bottomMargin;
|
||||
|
||||
mTaskbarStashedHandleAlpha.get(0).setValue(0);
|
||||
mStashedHandleAlpha.get(0).setValue(0);
|
||||
|
||||
mStashedTaskbarHeight = resources.getDimensionPixelSize(
|
||||
R.dimen.bubblebar_stashed_size);
|
||||
@@ -231,18 +238,33 @@ public class BubbleStashedHandleViewController {
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns an animator for translation Y. */
|
||||
public AnimatedFloat getStashedHandleTranslationY() {
|
||||
return mStashedHandleTranslationY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the translation of the stashed handle during the swipe up gesture.
|
||||
*/
|
||||
public void setTranslationYForSwipe(float transY) {
|
||||
mStashedHandleView.setTranslationY(transY);
|
||||
mSwipeUpTranslationY = transY;
|
||||
updateTranslationY();
|
||||
}
|
||||
|
||||
private void updateTranslationY() {
|
||||
mStashedHandleView.setTranslationY(mStashedHandleTranslationY.value + mSwipeUpTranslationY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by {@link BubbleStashController} to animate the handle when stashing or un stashing.
|
||||
*/
|
||||
public MultiPropertyFactory<View> getStashedHandleAlpha() {
|
||||
return mTaskbarStashedHandleAlpha;
|
||||
return mStashedHandleAlpha;
|
||||
}
|
||||
|
||||
/** Returns the x position of the center of the stashed handle. */
|
||||
public float getStashedHandleCenterX() {
|
||||
return mStashedHandleBounds.exactCenterX();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,12 +18,16 @@ package com.android.launcher3.taskbar.bubbles.animation
|
||||
|
||||
import android.view.View
|
||||
import android.view.View.VISIBLE
|
||||
import androidx.core.animation.AnimatorSet
|
||||
import androidx.core.animation.ObjectAnimator
|
||||
import androidx.core.animation.doOnEnd
|
||||
import androidx.dynamicanimation.animation.DynamicAnimation
|
||||
import androidx.dynamicanimation.animation.SpringForce
|
||||
import com.android.launcher3.taskbar.bubbles.BubbleBarBubble
|
||||
import com.android.launcher3.taskbar.bubbles.BubbleBarView
|
||||
import com.android.launcher3.taskbar.bubbles.BubbleStashController
|
||||
import com.android.launcher3.taskbar.bubbles.BubbleView
|
||||
import com.android.systemui.util.doOnEnd
|
||||
import com.android.wm.shell.shared.animation.PhysicsAnimator
|
||||
|
||||
/** Handles animations for bubble bar bubbles. */
|
||||
@@ -39,7 +43,17 @@ constructor(
|
||||
/** The time to show the flyout. */
|
||||
const val FLYOUT_DELAY_MS: Long = 2500
|
||||
/** The translation Y the new bubble will animate to. */
|
||||
const val BUBBLE_ANIMATION_TRANSLATION_Y = -50f
|
||||
const val BUBBLE_ANIMATION_FINAL_TRANSLATION_Y = -50f
|
||||
/** The initial translation Y value the new bubble is set to before the animation starts. */
|
||||
// TODO(liranb): get rid of this and calculate this based on the y-distance between the
|
||||
// bubble and the stash handle.
|
||||
const val BUBBLE_ANIMATION_INITIAL_TRANSLATION_Y = 50f
|
||||
/** The initial scale Y value that the new bubble is set to before the animation starts. */
|
||||
const val BUBBLE_ANIMATION_INITIAL_SCALE_Y = 0.3f
|
||||
/** The initial alpha value that the new bubble is set to before the animation starts. */
|
||||
const val BUBBLE_ANIMATION_INITIAL_ALPHA = 0.5f
|
||||
/** The duration of the hide bubble animation. */
|
||||
const val HIDE_BUBBLE_ANIMATION_DURATION_MS = 250L
|
||||
}
|
||||
|
||||
/** An interface for scheduling jobs. */
|
||||
@@ -78,41 +92,94 @@ constructor(
|
||||
// the animation of a new bubble is divided into 2 parts. The first part shows the bubble
|
||||
// and the second part hides it after a delay.
|
||||
val showAnimation = buildShowAnimation(bubbleView, b.key, animator)
|
||||
val hideAnimation = buildHideAnimation(animator)
|
||||
val hideAnimation = buildHideAnimation(bubbleView)
|
||||
scheduler.post(showAnimation)
|
||||
scheduler.postDelayed(FLYOUT_DELAY_MS, hideAnimation)
|
||||
}
|
||||
|
||||
/** Returns a lambda that starts the animation that shows the new bubble. */
|
||||
/**
|
||||
* Returns a lambda that starts the animation that shows the new bubble.
|
||||
*
|
||||
* The animation is divided into 2 parts. First the stash handle starts animating up and fades
|
||||
* out. When it ends the bubble starts fading in. The bubble and stashed handle are aligned to
|
||||
* give the impression of the stash handle morphing into the bubble.
|
||||
*/
|
||||
private fun buildShowAnimation(
|
||||
bubbleView: BubbleView,
|
||||
key: String,
|
||||
animator: PhysicsAnimator<BubbleView>
|
||||
bubbleAnimator: PhysicsAnimator<BubbleView>
|
||||
): () -> Unit = {
|
||||
// calculate the initial translation x the bubble should have in order to align it with the
|
||||
// stash handle.
|
||||
val initialTranslationX =
|
||||
bubbleStashController.stashedHandleCenterX - bubbleView.centerXOnScreen
|
||||
bubbleBarView.prepareForAnimatingBubbleWhileStashed(key)
|
||||
animator.setDefaultSpringConfig(springConfig)
|
||||
animator
|
||||
bubbleAnimator.setDefaultSpringConfig(springConfig)
|
||||
bubbleAnimator
|
||||
.spring(DynamicAnimation.ALPHA, 1f)
|
||||
.spring(DynamicAnimation.TRANSLATION_Y, BUBBLE_ANIMATION_TRANSLATION_Y)
|
||||
.spring(DynamicAnimation.TRANSLATION_Y, BUBBLE_ANIMATION_FINAL_TRANSLATION_Y)
|
||||
.spring(DynamicAnimation.SCALE_Y, 1f)
|
||||
// prepare the bubble for the animation
|
||||
bubbleView.alpha = 0f
|
||||
bubbleView.translationX = initialTranslationX
|
||||
bubbleView.translationY = BUBBLE_ANIMATION_INITIAL_TRANSLATION_Y
|
||||
bubbleView.scaleY = BUBBLE_ANIMATION_INITIAL_SCALE_Y
|
||||
bubbleView.visibility = VISIBLE
|
||||
animator.start()
|
||||
// start the stashed handle animation. when it ends, start the bubble animation.
|
||||
val stashedHandleAnimation = bubbleStashController.buildHideHandleAnimationForNewBubble()
|
||||
stashedHandleAnimation.doOnEnd {
|
||||
bubbleView.alpha = BUBBLE_ANIMATION_INITIAL_ALPHA
|
||||
bubbleAnimator.start()
|
||||
bubbleStashController.setStashAlpha(0f)
|
||||
}
|
||||
stashedHandleAnimation.start()
|
||||
}
|
||||
|
||||
/** Returns a lambda that starts the animation that hides the new bubble. */
|
||||
private fun buildHideAnimation(animator: PhysicsAnimator<BubbleView>): () -> Unit = {
|
||||
animator.setDefaultSpringConfig(springConfig)
|
||||
animator
|
||||
.spring(DynamicAnimation.ALPHA, 0f)
|
||||
.spring(DynamicAnimation.TRANSLATION_Y, 0f)
|
||||
.addEndListener { _, _, _, canceled, _, _, allRelevantPropertyAnimsEnded ->
|
||||
if (!canceled && allRelevantPropertyAnimsEnded) {
|
||||
if (bubbleStashController.isStashed) {
|
||||
bubbleBarView.alpha = 0f
|
||||
}
|
||||
bubbleBarView.onAnimatingBubbleCompleted()
|
||||
}
|
||||
/**
|
||||
* Returns a lambda that starts the animation that hides the new bubble.
|
||||
*
|
||||
* Similarly to the show animation, this is divided into 2 parts. We first animate the bubble
|
||||
* out, and then animate the stash handle in. At the end of the animation we reset the values of
|
||||
* the bubble.
|
||||
*/
|
||||
private fun buildHideAnimation(bubbleView: BubbleView): () -> Unit = {
|
||||
val stashAnimation = bubbleStashController.buildShowHandleAnimationForNewBubble()
|
||||
val alphaAnimator =
|
||||
ObjectAnimator.ofFloat(bubbleView, View.ALPHA, BUBBLE_ANIMATION_INITIAL_ALPHA)
|
||||
val translationYAnimator =
|
||||
ObjectAnimator.ofFloat(
|
||||
bubbleView,
|
||||
View.TRANSLATION_Y,
|
||||
BUBBLE_ANIMATION_INITIAL_TRANSLATION_Y
|
||||
)
|
||||
val scaleYAnimator =
|
||||
ObjectAnimator.ofFloat(bubbleView, View.SCALE_Y, BUBBLE_ANIMATION_INITIAL_SCALE_Y)
|
||||
val hideBubbleAnimation = AnimatorSet()
|
||||
hideBubbleAnimation.playTogether(alphaAnimator, translationYAnimator, scaleYAnimator)
|
||||
hideBubbleAnimation.duration = HIDE_BUBBLE_ANIMATION_DURATION_MS
|
||||
hideBubbleAnimation.doOnEnd {
|
||||
// the bubble is now hidden, start the stash handle animation and reset bubble
|
||||
// properties
|
||||
bubbleStashController.setStashAlpha(
|
||||
BubbleStashController.NEW_BUBBLE_HIDE_HANDLE_ANIMATION_ALPHA
|
||||
)
|
||||
bubbleView.alpha = 0f
|
||||
stashAnimation.start()
|
||||
bubbleView.translationY = 0f
|
||||
bubbleView.scaleY = 1f
|
||||
if (bubbleStashController.isStashed) {
|
||||
bubbleBarView.alpha = 0f
|
||||
}
|
||||
animator.start()
|
||||
bubbleBarView.onAnimatingBubbleCompleted()
|
||||
}
|
||||
hideBubbleAnimation.start()
|
||||
}
|
||||
}
|
||||
|
||||
/** The X position in screen coordinates of the center of the bubble. */
|
||||
private val BubbleView.centerXOnScreen: Float
|
||||
get() {
|
||||
val screenCoordinates = IntArray(2)
|
||||
getLocationOnScreen(screenCoordinates)
|
||||
return screenCoordinates[0] + width / 2f
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user