Update bubble bar stash and unstash animation

Bubble bar should stash and unstash from the handle.
Update the animation to match what is used for the taskbar animation.
Fix the stash handle reveal animation to animate the stash bounds to
bubble bar bounds and back.
This gives the effect of the handle morphing into the bubble bar and
bubble bar morphing back into the handle.

Bug: 345680453
Flag: com.android.wm.shell.enable_bubble_bar
Test: atest TransientBubbleStashControllerTest
Test: have bubbles in bubble bar and be in app, swipe up for taskbar and
  observe the bubble bar handle transforming into the bubble bar
Test: with taskbar and bubbles expanded, check that bubble bar
  transforms into the handle
Change-Id: I8508e9207092774cbdb990e65f7f84e56a924d0c
This commit is contained in:
Ats Jenk
2024-08-29 17:48:03 -07:00
parent 9657710f29
commit 9ab2b8c785
9 changed files with 248 additions and 143 deletions
@@ -21,6 +21,7 @@ import static android.view.View.VISIBLE;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.Nullable;
import android.content.res.Resources;
import android.graphics.Outline;
import android.graphics.Rect;
@@ -28,6 +29,7 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.ViewOutlineProvider;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.anim.RevealOutlineAnimation;
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
@@ -49,23 +51,29 @@ public class BubbleStashedHandleViewController {
private final TaskbarActivityContext mActivity;
private final StashedHandleView mStashedHandleView;
private final MultiValueAlpha mStashedHandleAlpha;
private float mTranslationForSwipeY;
private float mTranslationForStashY;
// Initialized in init.
private BubbleBarViewController mBarViewController;
private BubbleStashController mBubbleStashController;
private RegionSamplingHelper mRegionSamplingHelper;
private int mBarSize;
private int mStashedTaskbarHeight;
// Height of the area for the stash handle. Handle will be drawn in the center of this.
// This is also the area where touch is handled on the handle.
private int mStashedBubbleBarHeight;
private int mStashedHandleWidth;
private int mStashedHandleHeight;
// The bounds we want to clip to in the settled state when showing the stashed handle.
// The bounds of the stashed handle in settled state.
private final Rect mStashedHandleBounds = new Rect();
private float mStashedHandleRadius;
// When the reveal animation is cancelled, we can assume it's about to create a new animation,
// which should start off at the same point the cancelled one left off.
private float mStartProgressForNextRevealAnim;
private boolean mWasLastRevealAnimReversed;
// Use a nullable boolean to handle initial case where the last animation direction is not known
@Nullable
private Boolean mWasLastRevealAnimReversed = null;
// XXX: if there are more of these maybe do state flags instead
private boolean mHiddenForSysui;
@@ -77,6 +85,7 @@ public class BubbleStashedHandleViewController {
mActivity = activity;
mStashedHandleView = stashedHandleView;
mStashedHandleAlpha = new MultiValueAlpha(mStashedHandleView, 1);
mStashedHandleAlpha.setUpdateVisibility(true);
}
/** Initialize controller. */
@@ -84,26 +93,31 @@ public class BubbleStashedHandleViewController {
mBarViewController = bubbleControllers.bubbleBarViewController;
mBubbleStashController = bubbleControllers.bubbleStashController;
DeviceProfile deviceProfile = mActivity.getDeviceProfile();
Resources resources = mActivity.getResources();
mStashedHandleHeight = resources.getDimensionPixelSize(
R.dimen.bubblebar_stashed_handle_height);
mStashedHandleWidth = resources.getDimensionPixelSize(
R.dimen.bubblebar_stashed_handle_width);
mBarSize = resources.getDimensionPixelSize(R.dimen.bubblebar_size);
final int bottomMargin = resources.getDimensionPixelSize(
R.dimen.transient_taskbar_bottom_margin);
mStashedHandleView.getLayoutParams().height = mBarSize + bottomMargin;
int barSize = resources.getDimensionPixelSize(R.dimen.bubblebar_size);
// Use the max translation for bubble bar whether it is on the home screen or in app.
// Use values directly from device profile to avoid referencing other bubble controllers
// during init flow.
int maxTy = Math.max(deviceProfile.hotseatBarBottomSpacePx,
deviceProfile.taskbarBottomMargin);
// Adjust handle view size to accommodate the handle morphing into the bubble bar
mStashedHandleView.getLayoutParams().height = barSize + maxTy;
mStashedHandleAlpha.get(0).setValue(0);
mStashedTaskbarHeight = resources.getDimensionPixelSize(
mStashedBubbleBarHeight = resources.getDimensionPixelSize(
R.dimen.bubblebar_stashed_size);
mStashedHandleView.setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
float stashedHandleRadius = view.getHeight() / 2f;
outline.setRoundRect(mStashedHandleBounds, stashedHandleRadius);
mStashedHandleRadius = view.getHeight() / 2f;
outline.setRoundRect(mStashedHandleBounds, mStashedHandleRadius);
}
});
@@ -132,28 +146,25 @@ public class BubbleStashedHandleViewController {
private void updateBounds(BubbleBarLocation bubbleBarLocation) {
// As more bubbles get added, the icon bounds become larger. To ensure a consistent
// handle bar position, we pin it to the edge of the screen.
final int stashedCenterY = mStashedHandleView.getHeight() - mStashedTaskbarHeight / 2;
final int stashedCenterY = mStashedHandleView.getHeight() - mStashedBubbleBarHeight / 2;
final int stashedCenterX;
if (bubbleBarLocation.isOnLeft(mStashedHandleView.isLayoutRtl())) {
final int left = mBarViewController.getHorizontalMargin();
mStashedHandleBounds.set(
left,
stashedCenterY - mStashedHandleHeight / 2,
left + mStashedHandleWidth,
stashedCenterY + mStashedHandleHeight / 2);
mStashedHandleView.setPivotX(0);
stashedCenterX = left + mStashedHandleWidth / 2;
} else {
final int right =
mActivity.getDeviceProfile().widthPx - mBarViewController.getHorizontalMargin();
mStashedHandleBounds.set(
right - mStashedHandleWidth,
stashedCenterY - mStashedHandleHeight / 2,
right,
stashedCenterY + mStashedHandleHeight / 2);
mStashedHandleView.setPivotX(mStashedHandleView.getWidth());
mStashedHandleView.getRight() - mBarViewController.getHorizontalMargin();
stashedCenterX = right - mStashedHandleWidth / 2;
}
mStashedHandleBounds.set(
stashedCenterX - mStashedHandleWidth / 2,
stashedCenterY - mStashedHandleHeight / 2,
stashedCenterX + mStashedHandleWidth / 2,
stashedCenterY + mStashedHandleHeight / 2
);
mStashedHandleView.updateSampledRegion(mStashedHandleBounds);
mStashedHandleView.setPivotY(mStashedHandleView.getHeight() - mStashedTaskbarHeight / 2f);
mStashedHandleView.setPivotX(stashedCenterX);
mStashedHandleView.setPivotY(stashedCenterY);
}
public void onDestroy() {
@@ -168,13 +179,6 @@ public class BubbleStashedHandleViewController {
return mStashedHandleHeight;
}
/**
* Returns the height when the bubble bar is unstashed (so the height of the bubble bar).
*/
public int getUnstashedHeight() {
return mBarSize;
}
/**
* Called when system ui state changes. Bubbles don't show when the device is locked.
*/
@@ -242,7 +246,20 @@ public class BubbleStashedHandleViewController {
* Sets the translation of the stashed handle during the swipe up gesture.
*/
public void setTranslationYForSwipe(float transY) {
mStashedHandleView.setTranslationY(transY);
mTranslationForSwipeY = transY;
updateTranslationY();
}
/**
* Sets the translation of the stashed handle during the spring on stash animation.
*/
public void setTranslationYForStash(float transY) {
mTranslationForStashY = transY;
updateTranslationY();
}
private void updateTranslationY() {
mStashedHandleView.setTranslationY(mTranslationForSwipeY + mTranslationForStashY);
}
/** Returns the translation of the stashed handle. */
@@ -263,18 +280,17 @@ public class BubbleStashedHandleViewController {
* the size of where the bubble bar icons will be.
*/
public Animator createRevealAnimToIsStashed(boolean isStashed) {
Rect bubbleBarBounds = new Rect(mBarViewController.getBubbleBarBounds());
Rect bubbleBarBounds = getLocalBubbleBarBounds();
// Account for the full visual height of the bubble bar
int heightDiff = (mBarSize - bubbleBarBounds.height()) / 2;
bubbleBarBounds.top -= heightDiff;
bubbleBarBounds.bottom += heightDiff;
float stashedHandleRadius = mStashedHandleView.getHeight() / 2f;
float bubbleBarRadius = bubbleBarBounds.height() / 2f;
final RevealOutlineAnimation handleRevealProvider = new RoundedRectRevealOutlineProvider(
stashedHandleRadius, stashedHandleRadius, bubbleBarBounds, mStashedHandleBounds);
bubbleBarRadius, mStashedHandleRadius, bubbleBarBounds, mStashedHandleBounds);
boolean isReversed = !isStashed;
boolean changingDirection = mWasLastRevealAnimReversed != isReversed;
// We are only changing direction when mWasLastRevealAnimReversed is set at least once
boolean changingDirection =
mWasLastRevealAnimReversed != null && mWasLastRevealAnimReversed != isReversed;
mWasLastRevealAnimReversed = isReversed;
if (changingDirection) {
mStartProgressForNextRevealAnim = 1f - mStartProgressForNextRevealAnim;
@@ -291,6 +307,21 @@ public class BubbleStashedHandleViewController {
return revealAnim;
}
/**
* Get bounds for the bubble bar in the space of the handle view
*/
private Rect getLocalBubbleBarBounds() {
// Position the bubble bar bounds to the space of handle view
Rect bubbleBarBounds = new Rect(mBarViewController.getBubbleBarBounds());
// Start by moving bubble bar bounds to the bottom of handle view
int height = bubbleBarBounds.height();
bubbleBarBounds.bottom = mStashedHandleView.getHeight();
bubbleBarBounds.top = bubbleBarBounds.bottom - height;
// Then apply translation that is applied to the bubble bar
bubbleBarBounds.offset(0, (int) mBubbleStashController.getBubbleBarTranslationY());
return bubbleBarBounds;
}
/** Checks that the stash handle is visible and that the motion event is within bounds. */
public boolean isEventOverHandle(MotionEvent ev) {
if (mStashedHandleView.getVisibility() != VISIBLE) {
@@ -299,7 +330,7 @@ public class BubbleStashedHandleViewController {
// the bounds of the handle only include the visible part, so we check that the Y coordinate
// is anywhere within the stashed height of bubble bar (same as taskbar stashed height).
final int top = mActivity.getDeviceProfile().heightPx - mStashedTaskbarHeight;
final int top = mActivity.getDeviceProfile().heightPx - mStashedBubbleBarHeight;
final float x = ev.getRawX();
return ev.getRawY() >= top && x >= mStashedHandleBounds.left
&& x <= mStashedHandleBounds.right;