Merge "New Bubbles animations!" into sc-dev

This commit is contained in:
Josh Tsuji
2021-02-10 01:49:30 +00:00
committed by Android (Google) Code Review
5 changed files with 242 additions and 65 deletions

View File

@@ -398,6 +398,14 @@ public class Bubble implements BubbleViewProvider {
}
}
@Override
public void setExpandedContentAlpha(float alpha) {
if (mExpandedView != null) {
mExpandedView.setAlpha(alpha);
mExpandedView.setTaskViewAlpha(alpha);
}
}
/**
* Set visibility of bubble in the expanded state.
*
@@ -407,7 +415,7 @@ public class Bubble implements BubbleViewProvider {
* and setting {@code false} actually means rendering the expanded view in transparent.
*/
@Override
public void setContentVisibility(boolean visibility) {
public void setTaskViewVisibility(boolean visibility) {
if (mExpandedView != null) {
mExpandedView.setContentVisibility(visibility);
}

View File

@@ -85,6 +85,19 @@ public class BubbleExpandedView extends LinearLayout {
private boolean mImeVisible;
private boolean mNeedsNewHeight;
/**
* Whether we want the TaskView's content to be visible (alpha = 1f). If
* {@link #mIsAlphaAnimating} is true, this may not reflect the TaskView's actual alpha value
* until the animation ends.
*/
private boolean mIsContentVisible = false;
/**
* Whether we're animating the TaskView's alpha value. If so, we will hold off on applying alpha
* changes from {@link #setContentVisibility} until the animation ends.
*/
private boolean mIsAlphaAnimating = false;
private int mMinHeight;
private int mOverflowHeight;
private int mSettingsIconHeight;
@@ -464,6 +477,29 @@ public class BubbleExpandedView extends LinearLayout {
}
}
/**
* Whether we are currently animating the TaskView's alpha value. If this is set to true, calls
* to {@link #setContentVisibility} will not be applied until this is set to false again.
*/
void setAlphaAnimating(boolean animating) {
mIsAlphaAnimating = animating;
// If we're done animating, apply the correct
if (!animating) {
setContentVisibility(mIsContentVisible);
}
}
/**
* Sets the alpha of the underlying TaskView, since changing the expanded view's alpha does not
* affect the TaskView since it uses a Surface.
*/
void setTaskViewAlpha(float alpha) {
if (mTaskView != null) {
mTaskView.setAlpha(alpha);
}
}
/**
* Set visibility of contents in the expanded state.
*
@@ -477,16 +513,19 @@ public class BubbleExpandedView extends LinearLayout {
Log.d(TAG, "setContentVisibility: visibility=" + visibility
+ " bubble=" + getBubbleKey());
}
mIsContentVisible = visibility;
final float alpha = visibility ? 1f : 0f;
mPointerView.setAlpha(alpha);
if (mTaskView != null) {
if (mTaskView != null && !mIsAlphaAnimating) {
mTaskView.setAlpha(alpha);
}
}
@Nullable
View getTaskView() {
TaskView getTaskView() {
return mTaskView;
}

View File

@@ -167,8 +167,12 @@ class BubbleOverflow(
return dotPath
}
override fun setContentVisibility(visible: Boolean) {
expandedView?.setContentVisibility(visible)
override fun setExpandedContentAlpha(alpha: Float) {
expandedView?.alpha = alpha
}
override fun setTaskViewVisibility(visible: Boolean) {
// Overflow does not have a TaskView.
}
override fun getIconView(): BadgedImageView? {

View File

@@ -43,7 +43,6 @@ import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Settings;
import android.util.Log;
import android.view.Choreographer;
@@ -123,6 +122,10 @@ public class BubbleStackView extends FrameLayout
@VisibleForTesting
static final int FLYOUT_HIDE_AFTER = 5000;
private static final float EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT = 0.1f;
private static final int EXPANDED_VIEW_ALPHA_ANIMATION_DURATION = 150;
/**
* How long to wait to animate the stack temporarily invisible after a drag/flyout hide
* animation ends, if we are in fact temporarily invisible.
@@ -142,7 +145,7 @@ public class BubbleStackView extends FrameLayout
private final PhysicsAnimator.SpringConfig mTranslateSpringConfig =
new PhysicsAnimator.SpringConfig(
SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_NO_BOUNCY);
SpringForce.STIFFNESS_VERY_LOW, SpringForce.DAMPING_RATIO_NO_BOUNCY);
/**
* Handler to use for all delayed animations - this way, we can easily cancel them before
@@ -211,6 +214,9 @@ public class BubbleStackView extends FrameLayout
/** Container for the animating-out SurfaceView. */
private FrameLayout mAnimatingOutSurfaceContainer;
/** Animator for animating the alpha value of the animating out SurfaceView. */
private final ValueAnimator mAnimatingOutSurfaceAlphaAnimator = ValueAnimator.ofFloat(0f, 1f);
/**
* Buffer containing a screenshot of the animating-out bubble. This is drawn into the
* SurfaceView during animations.
@@ -261,6 +267,12 @@ public class BubbleStackView extends FrameLayout
/** Whether we're in the middle of dragging the stack around by touch. */
private boolean mIsDraggingStack = false;
/** Whether the expanded view has been hidden, because we are dragging out a bubble. */
private boolean mExpandedViewHidden = false;
/** Animator for animating the expanded view's alpha (including the TaskView inside it). */
private final ValueAnimator mExpandedViewAlphaAnimator = ValueAnimator.ofFloat(0f, 1f);
/**
* The pointer index of the ACTION_DOWN event we received prior to an ACTION_UP. We'll ignore
* touches from other pointer indices.
@@ -614,6 +626,12 @@ public class BubbleStackView extends FrameLayout
// Show the dismiss target, if we haven't already.
mDismissView.show();
if (mIsExpanded && mExpandedBubble != null && v.equals(mExpandedBubble.getIconView())) {
// Hide the expanded view if we're dragging out the expanded bubble, and we haven't
// already hidden it.
hideExpandedViewIfNeeded();
}
// First, see if the magnetized object consumes the event - if so, we shouldn't move the
// bubble since it's stuck to the target.
if (!passEventToMagnetizedObject(ev)) {
@@ -645,6 +663,9 @@ public class BubbleStackView extends FrameLayout
if (!passEventToMagnetizedObject(ev)) {
if (mBubbleData.isExpanded()) {
mExpandedAnimationController.snapBubbleBack(v, velX, velY);
// Re-show the expanded view if we hid it.
showExpandedViewIfNeeded();
} else {
// Fling the stack to the edge, and save whether or not it's going to end up on
// the left side of the screen.
@@ -937,6 +958,46 @@ public class BubbleStackView extends FrameLayout
animate()
.setInterpolator(Interpolators.PANEL_CLOSE_ACCELERATED)
.setDuration(FADE_IN_DURATION);
mExpandedViewAlphaAnimator.setDuration(EXPANDED_VIEW_ALPHA_ANIMATION_DURATION);
mExpandedViewAlphaAnimator.setInterpolator(Interpolators.PANEL_CLOSE_ACCELERATED);
mExpandedViewAlphaAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
// We need to be Z ordered on top in order for alpha animations to work.
mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(true);
mExpandedBubble.getExpandedView().setAlphaAnimating(true);
}
}
@Override
public void onAnimationEnd(Animator animation) {
if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(false);
mExpandedBubble.getExpandedView().setAlphaAnimating(false);
}
}
});
mExpandedViewAlphaAnimator.addUpdateListener(valueAnimator -> {
if (mExpandedBubble != null) {
mExpandedBubble.setExpandedContentAlpha((float) valueAnimator.getAnimatedValue());
}
});
mAnimatingOutSurfaceAlphaAnimator.setDuration(EXPANDED_VIEW_ALPHA_ANIMATION_DURATION);
mAnimatingOutSurfaceAlphaAnimator.setInterpolator(Interpolators.PANEL_CLOSE_ACCELERATED);
mAnimatingOutSurfaceAlphaAnimator.addUpdateListener(valueAnimator -> {
if (!mExpandedViewHidden) {
mAnimatingOutSurfaceView.setAlpha((float) valueAnimator.getAnimatedValue());
}
});
mAnimatingOutSurfaceAlphaAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
releaseAnimatingOutBubbleBuffer();
}
});
}
/**
@@ -1539,7 +1600,8 @@ public class BubbleStackView extends FrameLayout
// If we're expanded, screenshot the currently expanded bubble (before expanding the newly
// selected bubble) so we can animate it out.
if (mIsExpanded && mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
if (mIsExpanded && mExpandedBubble != null && mExpandedBubble.getExpandedView() != null
&& !mExpandedViewHidden) {
if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
// Before screenshotting, have the real ActivityView show on top of other surfaces
// so that the screenshot doesn't flicker on top of it.
@@ -1575,7 +1637,7 @@ public class BubbleStackView extends FrameLayout
mExpandedViewContainer.setAlpha(0.0f);
mSurfaceSynchronizer.syncSurfaceAndRun(() -> {
if (previouslySelected != null) {
previouslySelected.setContentVisibility(false);
previouslySelected.setTaskViewVisibility(false);
}
updateExpandedBubble();
@@ -1656,6 +1718,58 @@ public class BubbleStackView extends FrameLayout
requestUpdate();
}
/** Animate the expanded view hidden. This is done while we're dragging out a bubble. */
private void hideExpandedViewIfNeeded() {
if (mExpandedViewHidden
|| mExpandedBubble == null
|| mExpandedBubble.getExpandedView() == null) {
return;
}
mExpandedViewHidden = true;
// Scale down.
PhysicsAnimator.getInstance(mExpandedViewContainerMatrix)
.spring(AnimatableScaleMatrix.SCALE_X,
AnimatableScaleMatrix.getAnimatableValueForScaleFactor(
1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT),
mScaleOutSpringConfig)
.spring(AnimatableScaleMatrix.SCALE_Y,
AnimatableScaleMatrix.getAnimatableValueForScaleFactor(
1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT),
mScaleOutSpringConfig)
.addUpdateListener((target, values) ->
mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix))
.start();
// Animate alpha from 1f to 0f.
mExpandedViewAlphaAnimator.reverse();
}
/**
* Animate the expanded view visible again. This is done when we're done dragging out a bubble.
*/
private void showExpandedViewIfNeeded() {
if (!mExpandedViewHidden) {
return;
}
mExpandedViewHidden = false;
PhysicsAnimator.getInstance(mExpandedViewContainerMatrix)
.spring(AnimatableScaleMatrix.SCALE_X,
AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
mScaleOutSpringConfig)
.spring(AnimatableScaleMatrix.SCALE_Y,
AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
mScaleOutSpringConfig)
.addUpdateListener((target, values) ->
mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix))
.start();
mExpandedViewAlphaAnimator.start();
}
private void animateExpansion() {
cancelDelayedExpandCollapseSwitchAnimations();
final boolean showVertically = mPositioner.showBubblesVertically();
@@ -1714,7 +1828,7 @@ public class BubbleStackView extends FrameLayout
// Should not happen since we lay out before expanding, but just in case...
if (getWidth() > 0) {
startDelay = (long)
(ExpandedAnimationController.EXPAND_COLLAPSE_TARGET_ANIM_DURATION
(ExpandedAnimationController.EXPAND_COLLAPSE_TARGET_ANIM_DURATION * 1.2f
+ (distanceAnimated / getWidth()) * 30);
}
@@ -1728,20 +1842,29 @@ public class BubbleStackView extends FrameLayout
pivotX = mPositioner.getAvailableRect().right - mBubbleSize - mExpandedViewPadding;
}
mExpandedViewContainerMatrix.setScale(
0f, 0f,
1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
pivotX, pivotY);
} else {
mExpandedViewContainerMatrix.setScale(
0f, 0f,
bubbleWillBeAt + mBubbleSize / 2f, getExpandedViewY());
1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
bubbleWillBeAt + mBubbleSize / 2f,
getExpandedViewY());
}
mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(false);
if (mExpandedBubble.getExpandedView() != null) {
mExpandedBubble.setExpandedContentAlpha(0f);
// We'll be starting the alpha animation after a slight delay, so set this flag early
// here.
mExpandedBubble.getExpandedView().setAlphaAnimating(true);
}
mDelayedAnimationExecutor.executeDelayed(() -> {
mExpandedViewAlphaAnimator.start();
PhysicsAnimator.getInstance(mExpandedViewContainerMatrix).cancel();
PhysicsAnimator.getInstance(mExpandedViewContainerMatrix)
.spring(AnimatableScaleMatrix.SCALE_X,
@@ -1796,22 +1919,15 @@ public class BubbleStackView extends FrameLayout
// since we're about to animate collapsed.
mExpandedAnimationController.notifyPreparingToCollapse();
final long startDelay =
(long) (ExpandedAnimationController.EXPAND_COLLAPSE_TARGET_ANIM_DURATION * 0.6f);
mDelayedAnimationExecutor.executeDelayed(() -> {
mExpandedAnimationController.collapseBackToStack(
mStackAnimationController.getStackPositionAlongNearestHorizontalEdge()
/* collapseTo */,
() -> mBubbleContainer.setActiveController(mStackAnimationController));
}, startDelay);
mExpandedAnimationController.collapseBackToStack(
mStackAnimationController.getStackPositionAlongNearestHorizontalEdge()
/* collapseTo */,
() -> mBubbleContainer.setActiveController(mStackAnimationController));
if (mTaskbarScrim.getVisibility() == VISIBLE) {
mTaskbarScrim.animate().alpha(0f).start();
}
// We want to visually collapse into this bubble during the animation.
final View expandingFromBubble = mExpandedBubble.getIconView();
int index;
if (mExpandedBubble != null && BubbleOverflow.KEY.equals(mExpandedBubble.getKey())) {
index = mBubbleData.getBubbles().size();
@@ -1840,31 +1956,25 @@ public class BubbleStackView extends FrameLayout
getExpandedViewY());
}
mExpandedViewAlphaAnimator.reverse();
// When the animation completes, we should no longer be showing the content.
if (mExpandedBubble.getExpandedView() != null) {
mExpandedBubble.getExpandedView().setContentVisibility(false);
}
PhysicsAnimator.getInstance(mExpandedViewContainerMatrix).cancel();
PhysicsAnimator.getInstance(mExpandedViewContainerMatrix)
.spring(AnimatableScaleMatrix.SCALE_X, 0f, mScaleOutSpringConfig)
.spring(AnimatableScaleMatrix.SCALE_Y, 0f, mScaleOutSpringConfig)
.spring(AnimatableScaleMatrix.SCALE_X,
AnimatableScaleMatrix.getAnimatableValueForScaleFactor(
1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT),
mScaleOutSpringConfig)
.spring(AnimatableScaleMatrix.SCALE_Y,
AnimatableScaleMatrix.getAnimatableValueForScaleFactor(
1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT),
mScaleOutSpringConfig)
.addUpdateListener((target, values) -> {
if (expandingFromBubble != null) {
// Follow the bubble as it translates!
if (showVertically) {
mExpandedViewContainerMatrix.postTranslate(
0f, expandingFromBubble.getTranslationY()
- expandingFromBubbleAt);
} else {
mExpandedViewContainerMatrix.postTranslate(
expandingFromBubble.getTranslationX()
- expandingFromBubbleAt, 0f);
}
}
mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
// Hide early so we don't have a tiny little expanded view still visible at the
// end of the scale animation.
if (mExpandedViewContainerMatrix.getScaleX() < 0.05f) {
mExpandedViewContainer.setVisibility(View.INVISIBLE);
}
})
.withEndActions(() -> {
final BubbleViewProvider previouslySelected = mExpandedBubble;
@@ -1882,7 +1992,7 @@ public class BubbleStackView extends FrameLayout
updateBadgesAndZOrder(true /* setBadgeForCollapsedStack */);
afterExpandedViewAnimation();
if (previouslySelected != null) {
previouslySelected.setContentVisibility(false);
previouslySelected.setTaskViewVisibility(false);
}
if (mPositioner.showingInTaskbar()) {
@@ -1903,22 +2013,21 @@ public class BubbleStackView extends FrameLayout
// The surface contains a screenshot of the animating out bubble, so we just need to animate
// it out (and then release the GraphicBuffer).
PhysicsAnimator.getInstance(mAnimatingOutSurfaceContainer).cancel();
PhysicsAnimator animator = PhysicsAnimator.getInstance(mAnimatingOutSurfaceContainer)
.spring(DynamicAnimation.SCALE_X, 0f, mScaleOutSpringConfig)
.spring(DynamicAnimation.SCALE_Y, 0f, mScaleOutSpringConfig)
.withEndActions(this::releaseAnimatingOutBubbleBuffer);
mAnimatingOutSurfaceAlphaAnimator.reverse();
mExpandedViewAlphaAnimator.start();
if (mPositioner.showBubblesVertically()) {
float translationX = mStackAnimationController.isStackOnLeftSide()
? mAnimatingOutSurfaceContainer.getTranslationX() + mBubbleSize * 2
: mAnimatingOutSurfaceContainer.getTranslationX();
animator.spring(DynamicAnimation.TRANSLATION_X,
translationX,
mTranslateSpringConfig)
PhysicsAnimator.getInstance(mAnimatingOutSurfaceContainer)
.spring(DynamicAnimation.TRANSLATION_X, translationX, mTranslateSpringConfig)
.start();
} else {
animator.spring(DynamicAnimation.TRANSLATION_Y,
mAnimatingOutSurfaceContainer.getTranslationY() - mBubbleSize * 2,
PhysicsAnimator.getInstance(mAnimatingOutSurfaceContainer)
.spring(DynamicAnimation.TRANSLATION_Y,
mAnimatingOutSurfaceContainer.getTranslationY() - mBubbleSize,
mTranslateSpringConfig)
.start();
}
@@ -1947,7 +2056,8 @@ public class BubbleStackView extends FrameLayout
pivotX, pivotY);
} else {
mExpandedViewContainerMatrix.setScale(
0f, 0f,
1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
expandingFromBubbleDestination + mBubbleSize / 2f,
getExpandedViewY());
}
@@ -1972,10 +2082,7 @@ public class BubbleStackView extends FrameLayout
mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
})
.withEndActions(() -> {
if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(false);
}
mExpandedViewHidden = false;
mIsBubbleSwitchAnimating = false;
})
.start();
@@ -2489,6 +2596,7 @@ public class BubbleStackView extends FrameLayout
&& mExpandedBubble.getExpandedView() != null) {
BubbleExpandedView bev = mExpandedBubble.getExpandedView();
bev.setContentVisibility(false);
bev.setAlphaAnimating(!mIsExpansionAnimating);
mExpandedViewContainerMatrix.setScaleX(0f);
mExpandedViewContainerMatrix.setScaleY(0f);
mExpandedViewContainerMatrix.setTranslate(0f, 0f);
@@ -2586,7 +2694,14 @@ public class BubbleStackView extends FrameLayout
mAnimatingOutBubbleBuffer.getHardwareBuffer(),
mAnimatingOutBubbleBuffer.getColorSpace());
mSurfaceSynchronizer.syncSurfaceAndRun(() -> post(() -> onComplete.accept(true)));
mAnimatingOutSurfaceView.setAlpha(1f);
mExpandedViewContainer.setVisibility(View.GONE);
mSurfaceSynchronizer.syncSurfaceAndRun(() -> {
post(() -> {
onComplete.accept(true);
});
});
});
}
@@ -2618,7 +2733,9 @@ public class BubbleStackView extends FrameLayout
}
}
mExpandedViewContainer.setPadding(leftPadding, 0, rightPadding, 0);
mExpandedViewContainer.setVisibility(mIsExpanded ? VISIBLE : GONE);
if (mIsExpansionAnimating) {
mExpandedViewContainer.setVisibility(mIsExpanded ? VISIBLE : GONE);
}
if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
mExpandedViewContainer.setTranslationY(getExpandedViewY());
mExpandedViewContainer.setTranslationX(0f);

View File

@@ -29,7 +29,16 @@ import androidx.annotation.Nullable;
public interface BubbleViewProvider {
@Nullable BubbleExpandedView getExpandedView();
void setContentVisibility(boolean visible);
/**
* Sets the alpha of the expanded view content. This will be applied to both the expanded view
* container itself (the manage button, etc.) as well as the TaskView within it.
*/
void setExpandedContentAlpha(float alpha);
/**
* Sets whether the contents of the bubble's TaskView should be visible.
*/
void setTaskViewVisibility(boolean visible);
@Nullable View getIconView();