Merge "ActivityView animations!" into rvc-dev
This commit is contained in:
@@ -1222,10 +1222,6 @@
|
||||
<dimen name="bubble_dismiss_slop">16dp</dimen>
|
||||
<!-- Height of button allowing users to adjust settings for bubbles. -->
|
||||
<dimen name="bubble_manage_button_height">48dp</dimen>
|
||||
<!-- How far, horizontally, to animate the expanded view over when animating in/out. -->
|
||||
<dimen name="bubble_expanded_animate_x_distance">100dp</dimen>
|
||||
<!-- How far, vertically, to animate the expanded view over when animating in/out. -->
|
||||
<dimen name="bubble_expanded_animate_y_distance">500dp</dimen>
|
||||
<!-- Max width of the message bubble-->
|
||||
<dimen name="bubble_message_max_width">144dp</dimen>
|
||||
<!-- Min width of the message bubble -->
|
||||
|
||||
@@ -22,6 +22,7 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
|
||||
import static android.graphics.PixelFormat.TRANSPARENT;
|
||||
import static android.view.Display.INVALID_DISPLAY;
|
||||
import static android.view.InsetsState.ITYPE_IME;
|
||||
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
|
||||
import static android.view.ViewRootImpl.sNewInsetsMode;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
|
||||
@@ -33,7 +34,6 @@ import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_EXPAND
|
||||
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
|
||||
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.ActivityOptions;
|
||||
import android.app.ActivityTaskManager;
|
||||
@@ -46,6 +46,7 @@ import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Outline;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.ShapeDrawable;
|
||||
@@ -55,12 +56,19 @@ import android.os.RemoteException;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewOutlineProvider;
|
||||
import android.view.WindowInsets;
|
||||
import android.view.WindowManager;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.internal.policy.ScreenDecorationsUtils;
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.R;
|
||||
@@ -88,6 +96,7 @@ public class BubbleExpandedView extends LinearLayout {
|
||||
// The triangle pointing to the expanded view
|
||||
private View mPointerView;
|
||||
private int mPointerMargin;
|
||||
@Nullable private int[] mExpandedViewContainerLocation;
|
||||
|
||||
private AlphaOptimizedButton mSettingsIcon;
|
||||
|
||||
@@ -121,6 +130,16 @@ public class BubbleExpandedView extends LinearLayout {
|
||||
private View mVirtualImeView;
|
||||
private WindowManager mVirtualDisplayWindowManager;
|
||||
private boolean mImeShowing = false;
|
||||
private float mCornerRadius = 0f;
|
||||
|
||||
/**
|
||||
* Container for the ActivityView that has a solid, round-rect background that shows if the
|
||||
* ActivityView hasn't loaded.
|
||||
*/
|
||||
private FrameLayout mActivityViewContainer = new FrameLayout(getContext());
|
||||
|
||||
/** The SurfaceView that the ActivityView draws to. */
|
||||
@Nullable private SurfaceView mActivitySurface;
|
||||
|
||||
private ActivityView.StateCallback mStateCallback = new ActivityView.StateCallback() {
|
||||
@Override
|
||||
@@ -269,7 +288,28 @@ public class BubbleExpandedView extends LinearLayout {
|
||||
|
||||
// Set ActivityView's alpha value as zero, since there is no view content to be shown.
|
||||
setContentVisibility(false);
|
||||
addView(mActivityView);
|
||||
|
||||
mActivityViewContainer.setBackgroundColor(Color.WHITE);
|
||||
mActivityViewContainer.setOutlineProvider(new ViewOutlineProvider() {
|
||||
@Override
|
||||
public void getOutline(View view, Outline outline) {
|
||||
outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mCornerRadius);
|
||||
}
|
||||
});
|
||||
mActivityViewContainer.setClipToOutline(true);
|
||||
mActivityViewContainer.addView(mActivityView);
|
||||
mActivityViewContainer.setLayoutParams(
|
||||
new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
|
||||
addView(mActivityViewContainer);
|
||||
|
||||
if (mActivityView != null
|
||||
&& mActivityView.getChildCount() > 0
|
||||
&& mActivityView.getChildAt(0) instanceof SurfaceView) {
|
||||
// Retrieve the surface from the ActivityView so we can screenshot it and change its
|
||||
// z-ordering. This should always be possible, since ActivityView's constructor adds the
|
||||
// SurfaceView as its first child.
|
||||
mActivitySurface = (SurfaceView) mActivityView.getChildAt(0);
|
||||
}
|
||||
|
||||
// Expanded stack layout, top to bottom:
|
||||
// Expanded view container
|
||||
@@ -327,6 +367,39 @@ public class BubbleExpandedView extends LinearLayout {
|
||||
return mBubble != null ? mBubble.getKey() : "null";
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks the ActivityView's surface to draw on top of all other views in the window. This is
|
||||
* useful for ordering surfaces during animations, but should otherwise be set to false so that
|
||||
* bubbles and menus can draw over the ActivityView.
|
||||
*/
|
||||
void setSurfaceZOrderedOnTop(boolean onTop) {
|
||||
if (mActivitySurface == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mActivitySurface.setZOrderedOnTop(onTop, true);
|
||||
}
|
||||
|
||||
/** Return a GraphicBuffer with the contents of the ActivityView's underlying surface. */
|
||||
@Nullable SurfaceControl.ScreenshotGraphicBuffer snapshotActivitySurface() {
|
||||
if (mActivitySurface == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return SurfaceControl.captureLayers(
|
||||
mActivitySurface.getSurfaceControl(),
|
||||
new Rect(0, 0, mActivityView.getWidth(), mActivityView.getHeight()),
|
||||
1 /* scale */);
|
||||
}
|
||||
|
||||
int[] getActivityViewLocationOnScreen() {
|
||||
if (mActivityView != null) {
|
||||
return mActivityView.getLocationOnScreen();
|
||||
} else {
|
||||
return new int[]{0, 0};
|
||||
}
|
||||
}
|
||||
|
||||
void setManageClickListener(OnClickListener manageClickListener) {
|
||||
findViewById(R.id.settings_button).setOnClickListener(manageClickListener);
|
||||
}
|
||||
@@ -345,12 +418,12 @@ public class BubbleExpandedView extends LinearLayout {
|
||||
void applyThemeAttrs() {
|
||||
final TypedArray ta = mContext.obtainStyledAttributes(
|
||||
new int[] {android.R.attr.dialogCornerRadius});
|
||||
float cornerRadius = ta.getDimensionPixelSize(0, 0);
|
||||
mCornerRadius = ta.getDimensionPixelSize(0, 0);
|
||||
ta.recycle();
|
||||
|
||||
if (mActivityView != null && ScreenDecorationsUtils.supportsRoundedCornersOnWindows(
|
||||
mContext.getResources())) {
|
||||
mActivityView.setCornerRadius(cornerRadius);
|
||||
mActivityView.setCornerRadius(mCornerRadius);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -398,6 +471,7 @@ public class BubbleExpandedView extends LinearLayout {
|
||||
mPointerView.setAlpha(alpha);
|
||||
if (mActivityView != null) {
|
||||
mActivityView.setAlpha(alpha);
|
||||
mActivityView.bringToFront();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -557,6 +631,11 @@ public class BubbleExpandedView extends LinearLayout {
|
||||
if (DEBUG_BUBBLE_EXPANDED_VIEW) {
|
||||
Log.d(TAG, "updateHeight: bubble=" + getBubbleKey());
|
||||
}
|
||||
|
||||
if (mExpandedViewContainerLocation == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (usingActivityView()) {
|
||||
float desiredHeight = mOverflowHeight;
|
||||
if (!mIsOverflow) {
|
||||
@@ -564,7 +643,7 @@ public class BubbleExpandedView extends LinearLayout {
|
||||
}
|
||||
float height = Math.min(desiredHeight, getMaxExpandedHeight());
|
||||
height = Math.max(height, mIsOverflow? mOverflowHeight : mMinHeight);
|
||||
LayoutParams lp = (LayoutParams) mActivityView.getLayoutParams();
|
||||
ViewGroup.LayoutParams lp = mActivityView.getLayoutParams();
|
||||
mNeedsNewHeight = lp.height != height;
|
||||
if (!mKeyboardVisible) {
|
||||
// If the keyboard is visible... don't adjust the height because that will cause
|
||||
@@ -574,7 +653,8 @@ public class BubbleExpandedView extends LinearLayout {
|
||||
mNeedsNewHeight = false;
|
||||
}
|
||||
if (DEBUG_BUBBLE_EXPANDED_VIEW) {
|
||||
Log.d(TAG, "updateHeight: bubble=" + getBubbleKey() + " height=" + height
|
||||
Log.d(TAG, "updateHeight: bubble=" + getBubbleKey()
|
||||
+ " height=" + height
|
||||
+ " mNeedsNewHeight=" + mNeedsNewHeight);
|
||||
}
|
||||
}
|
||||
@@ -582,28 +662,40 @@ public class BubbleExpandedView extends LinearLayout {
|
||||
|
||||
private int getMaxExpandedHeight() {
|
||||
mWindowManager.getDefaultDisplay().getRealSize(mDisplaySize);
|
||||
int[] windowLocation = mActivityView.getLocationOnScreen();
|
||||
int bottomInset = getRootWindowInsets() != null
|
||||
? getRootWindowInsets().getStableInsetBottom()
|
||||
: 0;
|
||||
return mDisplaySize.y - windowLocation[1] - mSettingsIconHeight - mPointerHeight
|
||||
|
||||
return mDisplaySize.y
|
||||
- mExpandedViewContainerLocation[1]
|
||||
- getPaddingTop()
|
||||
- getPaddingBottom()
|
||||
- mSettingsIconHeight
|
||||
- mPointerHeight
|
||||
- mPointerMargin - bottomInset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update appearance of the expanded view being displayed.
|
||||
*
|
||||
* @param containerLocationOnScreen The location on-screen of the container the expanded view is
|
||||
* added to. This allows us to calculate max height without
|
||||
* waiting for layout.
|
||||
*/
|
||||
public void updateView() {
|
||||
public void updateView(int[] containerLocationOnScreen) {
|
||||
if (DEBUG_BUBBLE_EXPANDED_VIEW) {
|
||||
Log.d(TAG, "updateView: bubble="
|
||||
+ getBubbleKey());
|
||||
}
|
||||
|
||||
mExpandedViewContainerLocation = containerLocationOnScreen;
|
||||
|
||||
if (usingActivityView()
|
||||
&& mActivityView.getVisibility() == VISIBLE
|
||||
&& mActivityView.isAttachedToWindow()) {
|
||||
mActivityView.onLocationChanged();
|
||||
updateHeight();
|
||||
}
|
||||
updateHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -56,6 +56,8 @@ import android.view.DisplayCutout;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewOutlineProvider;
|
||||
@@ -82,6 +84,7 @@ import com.android.internal.util.ContrastColorUtil;
|
||||
import com.android.systemui.Interpolators;
|
||||
import com.android.systemui.Prefs;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.bubbles.animation.AnimatableScaleMatrix;
|
||||
import com.android.systemui.bubbles.animation.ExpandedAnimationController;
|
||||
import com.android.systemui.bubbles.animation.PhysicsAnimationLayout;
|
||||
import com.android.systemui.bubbles.animation.StackAnimationController;
|
||||
@@ -147,6 +150,16 @@ public class BubbleStackView extends FrameLayout
|
||||
StackAnimationController.IME_ANIMATION_STIFFNESS,
|
||||
StackAnimationController.DEFAULT_BOUNCINESS);
|
||||
|
||||
private final PhysicsAnimator.SpringConfig mScaleInSpringConfig =
|
||||
new PhysicsAnimator.SpringConfig(300f, 0.9f);
|
||||
|
||||
private final PhysicsAnimator.SpringConfig mScaleOutSpringConfig =
|
||||
new PhysicsAnimator.SpringConfig(900f, 1f);
|
||||
|
||||
private final PhysicsAnimator.SpringConfig mTranslateSpringConfig =
|
||||
new PhysicsAnimator.SpringConfig(
|
||||
SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_NO_BOUNCY);
|
||||
|
||||
/**
|
||||
* Interface to synchronize {@link View} state and the screen.
|
||||
*
|
||||
@@ -186,8 +199,6 @@ public class BubbleStackView extends FrameLayout
|
||||
|
||||
private Point mDisplaySize;
|
||||
|
||||
private final SpringAnimation mExpandedViewXAnim;
|
||||
private final SpringAnimation mExpandedViewYAnim;
|
||||
private final BubbleData mBubbleData;
|
||||
|
||||
private final ValueAnimator mDesaturateAndDarkenAnimator;
|
||||
@@ -199,6 +210,24 @@ public class BubbleStackView extends FrameLayout
|
||||
|
||||
private FrameLayout mExpandedViewContainer;
|
||||
|
||||
/** Matrix used to scale the expanded view container with a given pivot point. */
|
||||
private final AnimatableScaleMatrix mExpandedViewContainerMatrix = new AnimatableScaleMatrix();
|
||||
|
||||
/**
|
||||
* SurfaceView that we draw screenshots of animating-out bubbles into. This allows us to animate
|
||||
* between bubble activities without needing both to be alive at the same time.
|
||||
*/
|
||||
private SurfaceView mAnimatingOutSurfaceView;
|
||||
|
||||
/** Container for the animating-out SurfaceView. */
|
||||
private FrameLayout mAnimatingOutSurfaceContainer;
|
||||
|
||||
/**
|
||||
* Buffer containing a screenshot of the animating-out bubble. This is drawn into the
|
||||
* SurfaceView during animations.
|
||||
*/
|
||||
private SurfaceControl.ScreenshotGraphicBuffer mAnimatingOutBubbleBuffer;
|
||||
|
||||
private BubbleFlyoutView mFlyout;
|
||||
/** Runnable that fades out the flyout and then sets it to GONE. */
|
||||
private Runnable mHideFlyout = () -> animateFlyoutCollapsed(true, 0 /* velX */);
|
||||
@@ -230,8 +259,7 @@ public class BubbleStackView extends FrameLayout
|
||||
private int mBubblePaddingTop;
|
||||
private int mBubbleTouchPadding;
|
||||
private int mExpandedViewPadding;
|
||||
private int mExpandedAnimateXDistance;
|
||||
private int mExpandedAnimateYDistance;
|
||||
private int mCornerRadius;
|
||||
private int mPointerHeight;
|
||||
private int mStatusBarHeight;
|
||||
private int mImeOffset;
|
||||
@@ -680,10 +708,6 @@ public class BubbleStackView extends FrameLayout
|
||||
mBubbleElevation = res.getDimensionPixelSize(R.dimen.bubble_elevation);
|
||||
mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
|
||||
mBubbleTouchPadding = res.getDimensionPixelSize(R.dimen.bubble_touch_padding);
|
||||
mExpandedAnimateXDistance =
|
||||
res.getDimensionPixelSize(R.dimen.bubble_expanded_animate_x_distance);
|
||||
mExpandedAnimateYDistance =
|
||||
res.getDimensionPixelSize(R.dimen.bubble_expanded_animate_y_distance);
|
||||
mPointerHeight = res.getDimensionPixelSize(R.dimen.bubble_pointer_height);
|
||||
|
||||
mStatusBarHeight =
|
||||
@@ -698,6 +722,11 @@ public class BubbleStackView extends FrameLayout
|
||||
mExpandedViewPadding = res.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding);
|
||||
int elevation = res.getDimensionPixelSize(R.dimen.bubble_elevation);
|
||||
|
||||
final TypedArray ta = mContext.obtainStyledAttributes(
|
||||
new int[] {android.R.attr.dialogCornerRadius});
|
||||
mCornerRadius = ta.getDimensionPixelSize(0, 0);
|
||||
ta.recycle();
|
||||
|
||||
final Runnable onBubbleAnimatedOut = () -> {
|
||||
if (getBubbleCount() == 0) {
|
||||
allBubblesAnimatedOutAction.run();
|
||||
@@ -731,6 +760,24 @@ public class BubbleStackView extends FrameLayout
|
||||
mExpandedViewContainer.setClipChildren(false);
|
||||
addView(mExpandedViewContainer);
|
||||
|
||||
mAnimatingOutSurfaceContainer = new FrameLayout(getContext());
|
||||
mAnimatingOutSurfaceContainer.setLayoutParams(
|
||||
new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
|
||||
addView(mAnimatingOutSurfaceContainer);
|
||||
|
||||
mAnimatingOutSurfaceView = new SurfaceView(getContext());
|
||||
mAnimatingOutSurfaceView.setUseAlpha();
|
||||
mAnimatingOutSurfaceView.setZOrderOnTop(true);
|
||||
mAnimatingOutSurfaceView.setCornerRadius(mCornerRadius);
|
||||
mAnimatingOutSurfaceView.setLayoutParams(new ViewGroup.LayoutParams(0, 0));
|
||||
mAnimatingOutSurfaceContainer.addView(mAnimatingOutSurfaceView);
|
||||
|
||||
mAnimatingOutSurfaceContainer.setPadding(
|
||||
mExpandedViewPadding,
|
||||
mExpandedViewPadding,
|
||||
mExpandedViewPadding,
|
||||
mExpandedViewPadding);
|
||||
|
||||
setUpManageMenu();
|
||||
|
||||
setUpFlyout();
|
||||
@@ -776,26 +823,6 @@ public class BubbleStackView extends FrameLayout
|
||||
// MagnetizedObjects.
|
||||
mMagneticTarget = new MagnetizedObject.MagneticTarget(mDismissTargetCircle, dismissRadius);
|
||||
|
||||
mExpandedViewXAnim =
|
||||
new SpringAnimation(mExpandedViewContainer, DynamicAnimation.TRANSLATION_X);
|
||||
mExpandedViewXAnim.setSpring(
|
||||
new SpringForce()
|
||||
.setStiffness(SpringForce.STIFFNESS_LOW)
|
||||
.setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY));
|
||||
|
||||
mExpandedViewYAnim =
|
||||
new SpringAnimation(mExpandedViewContainer, DynamicAnimation.TRANSLATION_Y);
|
||||
mExpandedViewYAnim.setSpring(
|
||||
new SpringForce()
|
||||
.setStiffness(SpringForce.STIFFNESS_LOW)
|
||||
.setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY));
|
||||
mExpandedViewYAnim.addEndListener((anim, cancelled, value, velocity) -> {
|
||||
if (mIsExpanded && mExpandedBubble != null
|
||||
&& mExpandedBubble.getExpandedView() != null) {
|
||||
mExpandedBubble.getExpandedView().updateView();
|
||||
}
|
||||
});
|
||||
|
||||
setClipChildren(false);
|
||||
setFocusable(true);
|
||||
mBubbleContainer.bringToFront();
|
||||
@@ -830,7 +857,7 @@ public class BubbleStackView extends FrameLayout
|
||||
if (mIsExpanded) {
|
||||
mExpandedViewContainer.setTranslationY(getExpandedViewY());
|
||||
if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
|
||||
mExpandedBubble.getExpandedView().updateView();
|
||||
mExpandedBubble.getExpandedView().updateView(getLocationOnScreen());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -954,15 +981,10 @@ public class BubbleStackView extends FrameLayout
|
||||
|
||||
PhysicsAnimator.getInstance(mManageMenu).setDefaultSpringConfig(mManageSpringConfig);
|
||||
|
||||
final TypedArray ta = mContext.obtainStyledAttributes(
|
||||
new int[] {android.R.attr.dialogCornerRadius});
|
||||
final int menuCornerRadius = ta.getDimensionPixelSize(0, 0);
|
||||
ta.recycle();
|
||||
|
||||
mManageMenu.setOutlineProvider(new ViewOutlineProvider() {
|
||||
@Override
|
||||
public void getOutline(View view, Outline outline) {
|
||||
outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), menuCornerRadius);
|
||||
outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mCornerRadius);
|
||||
}
|
||||
});
|
||||
mManageMenu.setClipToOutline(true);
|
||||
@@ -1447,6 +1469,31 @@ public class BubbleStackView extends FrameLayout
|
||||
mBubbleData.setShowingOverflow(true);
|
||||
}
|
||||
|
||||
// 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 (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.
|
||||
mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(true);
|
||||
}
|
||||
|
||||
try {
|
||||
screenshotAnimatingOutBubbleIntoSurface((success) -> {
|
||||
mAnimatingOutSurfaceContainer.setVisibility(
|
||||
success ? View.VISIBLE : View.INVISIBLE);
|
||||
showNewlySelectedBubble(bubbleToSelect);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
showNewlySelectedBubble(bubbleToSelect);
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
showNewlySelectedBubble(bubbleToSelect);
|
||||
}
|
||||
}
|
||||
|
||||
private void showNewlySelectedBubble(BubbleViewProvider bubbleToSelect) {
|
||||
final BubbleViewProvider previouslySelected = mExpandedBubble;
|
||||
mExpandedBubble = bubbleToSelect;
|
||||
updatePointerPosition();
|
||||
@@ -1637,50 +1684,18 @@ public class BubbleStackView extends FrameLayout
|
||||
}
|
||||
|
||||
private void beforeExpandedViewAnimation() {
|
||||
mIsExpansionAnimating = true;
|
||||
hideFlyoutImmediate();
|
||||
updateExpandedBubble();
|
||||
updateExpandedView();
|
||||
mIsExpansionAnimating = true;
|
||||
}
|
||||
|
||||
private void afterExpandedViewAnimation() {
|
||||
updateExpandedView();
|
||||
mIsExpansionAnimating = false;
|
||||
updateExpandedView();
|
||||
requestUpdate();
|
||||
}
|
||||
|
||||
private void animateCollapse() {
|
||||
// Hide the menu if it's visible.
|
||||
showManageMenu(false);
|
||||
|
||||
mIsExpanded = false;
|
||||
final BubbleViewProvider previouslySelected = mExpandedBubble;
|
||||
beforeExpandedViewAnimation();
|
||||
maybeShowManageEducation(false);
|
||||
|
||||
if (DEBUG_BUBBLE_STACK_VIEW) {
|
||||
Log.d(TAG, "animateCollapse");
|
||||
Log.d(TAG, BubbleDebugConfig.formatBubblesString(getBubblesOnScreen(),
|
||||
mExpandedBubble));
|
||||
}
|
||||
updateOverflowVisibility();
|
||||
mBubbleContainer.cancelAllAnimations();
|
||||
mExpandedAnimationController.collapseBackToStack(
|
||||
mStackAnimationController.getStackPositionAlongNearestHorizontalEdge()
|
||||
/* collapseTo */,
|
||||
() -> {
|
||||
mBubbleContainer.setActiveController(mStackAnimationController);
|
||||
afterExpandedViewAnimation();
|
||||
previouslySelected.setContentVisibility(false);
|
||||
});
|
||||
|
||||
mExpandedViewXAnim.animateToFinalPosition(getCollapsedX());
|
||||
mExpandedViewYAnim.animateToFinalPosition(getCollapsedY());
|
||||
mExpandedViewContainer.animate()
|
||||
.setDuration(100)
|
||||
.alpha(0f);
|
||||
}
|
||||
|
||||
private void animateExpansion() {
|
||||
mIsExpanded = true;
|
||||
hideStackUserEducation(true /* fromExpansion */);
|
||||
@@ -1688,32 +1703,196 @@ public class BubbleStackView extends FrameLayout
|
||||
|
||||
mBubbleContainer.setActiveController(mExpandedAnimationController);
|
||||
updateOverflowVisibility();
|
||||
updatePointerPosition();
|
||||
mExpandedAnimationController.expandFromStack(() -> {
|
||||
updatePointerPosition();
|
||||
afterExpandedViewAnimation();
|
||||
maybeShowManageEducation(true);
|
||||
} /* after */);
|
||||
|
||||
mExpandedViewContainer.setTranslationX(getCollapsedX());
|
||||
mExpandedViewContainer.setTranslationY(getCollapsedY());
|
||||
mExpandedViewContainer.setAlpha(0f);
|
||||
mExpandedViewContainer.setTranslationX(0);
|
||||
mExpandedViewContainer.setTranslationY(getExpandedViewY());
|
||||
mExpandedViewContainer.setAlpha(1f);
|
||||
|
||||
// X-value of the bubble we're expanding, once it's settled in its row.
|
||||
final float bubbleWillBeAtX =
|
||||
mExpandedAnimationController.getBubbleLeft(
|
||||
mBubbleData.getBubbles().indexOf(mExpandedBubble));
|
||||
|
||||
// How far horizontally the bubble will be animating. We'll wait a bit longer for bubbles
|
||||
// that are animating farther, so that the expanded view doesn't move as much.
|
||||
final float horizontalDistanceAnimated =
|
||||
Math.abs(bubbleWillBeAtX
|
||||
- mStackAnimationController.getStackPosition().x);
|
||||
|
||||
// Wait for the path animation target to reach its end, and add a small amount of extra time
|
||||
// if the bubble is moving a lot horizontally.
|
||||
long startDelay = 0L;
|
||||
|
||||
// Should not happen since we lay out before expanding, but just in case...
|
||||
if (getWidth() > 0) {
|
||||
startDelay = (long)
|
||||
(ExpandedAnimationController.EXPAND_COLLAPSE_TARGET_ANIM_DURATION
|
||||
+ (horizontalDistanceAnimated / getWidth()) * 30);
|
||||
}
|
||||
|
||||
// Set the pivot point for the scale, so the expanded view animates out from the bubble.
|
||||
mExpandedViewContainerMatrix.setScale(
|
||||
0f, 0f,
|
||||
bubbleWillBeAtX + mBubbleSize / 2f, getExpandedViewY());
|
||||
mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
|
||||
|
||||
if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
|
||||
mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(false);
|
||||
}
|
||||
|
||||
postDelayed(() -> PhysicsAnimator.getInstance(mExpandedViewContainerMatrix)
|
||||
.spring(AnimatableScaleMatrix.SCALE_X,
|
||||
AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
|
||||
mScaleInSpringConfig)
|
||||
.spring(AnimatableScaleMatrix.SCALE_Y,
|
||||
AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
|
||||
mScaleInSpringConfig)
|
||||
.addUpdateListener((target, values) -> {
|
||||
mExpandedViewContainerMatrix.postTranslate(
|
||||
mExpandedBubble.getIconView().getTranslationX()
|
||||
- bubbleWillBeAtX,
|
||||
0);
|
||||
mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
|
||||
})
|
||||
.withEndActions(() -> {
|
||||
if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
|
||||
mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(false);
|
||||
}
|
||||
})
|
||||
.start(), startDelay);
|
||||
|
||||
mExpandedViewXAnim.animateToFinalPosition(0f);
|
||||
mExpandedViewYAnim.animateToFinalPosition(getExpandedViewY());
|
||||
mExpandedViewContainer.animate()
|
||||
.setDuration(100)
|
||||
.alpha(1f);
|
||||
}
|
||||
|
||||
private float getCollapsedX() {
|
||||
return mStackAnimationController.getStackPosition().x < getWidth() / 2
|
||||
? -mExpandedAnimateXDistance
|
||||
: mExpandedAnimateXDistance;
|
||||
private void animateCollapse() {
|
||||
// Hide the menu if it's visible.
|
||||
showManageMenu(false);
|
||||
|
||||
mIsExpanded = false;
|
||||
|
||||
mBubbleContainer.cancelAllAnimations();
|
||||
|
||||
// If we were in the middle of swapping, the animating-out surface would have been scaling
|
||||
// to zero - finish it off.
|
||||
PhysicsAnimator.getInstance(mAnimatingOutSurfaceContainer).cancel();
|
||||
mAnimatingOutSurfaceContainer.setScaleX(0f);
|
||||
mAnimatingOutSurfaceContainer.setScaleY(0f);
|
||||
|
||||
if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
|
||||
mExpandedBubble.getExpandedView().hideImeIfVisible();
|
||||
}
|
||||
|
||||
final long startDelay =
|
||||
(long) (ExpandedAnimationController.EXPAND_COLLAPSE_TARGET_ANIM_DURATION * 0.6f);
|
||||
postDelayed(() -> mExpandedAnimationController.collapseBackToStack(
|
||||
mStackAnimationController.getStackPositionAlongNearestHorizontalEdge()
|
||||
/* collapseTo */,
|
||||
() -> {
|
||||
mBubbleContainer.setActiveController(mStackAnimationController);
|
||||
}), startDelay);
|
||||
|
||||
// We want to visually collapse into this bubble during the animation.
|
||||
final View expandingFromBubble = mExpandedBubble.getIconView();
|
||||
|
||||
// X-value the bubble is animating from (back into the stack).
|
||||
final float expandingFromBubbleAtX =
|
||||
mExpandedAnimationController.getBubbleLeft(
|
||||
mBubbleData.getBubbles().indexOf(mExpandedBubble));
|
||||
|
||||
// Set the pivot point.
|
||||
mExpandedViewContainerMatrix.setScale(
|
||||
1f, 1f,
|
||||
expandingFromBubbleAtX + mBubbleSize / 2f,
|
||||
getExpandedViewY());
|
||||
|
||||
PhysicsAnimator.getInstance(mExpandedViewContainerMatrix).cancel();
|
||||
PhysicsAnimator.getInstance(mExpandedViewContainerMatrix)
|
||||
.spring(AnimatableScaleMatrix.SCALE_X, 0f, mScaleOutSpringConfig)
|
||||
.spring(AnimatableScaleMatrix.SCALE_Y, 0f, mScaleOutSpringConfig)
|
||||
.addUpdateListener((target, values) -> {
|
||||
if (expandingFromBubble != null) {
|
||||
// Follow the bubble as it translates!
|
||||
mExpandedViewContainerMatrix.postTranslate(
|
||||
expandingFromBubble.getTranslationX()
|
||||
- expandingFromBubbleAtX, 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;
|
||||
beforeExpandedViewAnimation();
|
||||
maybeShowManageEducation(false);
|
||||
|
||||
if (DEBUG_BUBBLE_STACK_VIEW) {
|
||||
Log.d(TAG, "animateCollapse");
|
||||
Log.d(TAG, BubbleDebugConfig.formatBubblesString(getBubblesOnScreen(),
|
||||
mExpandedBubble));
|
||||
}
|
||||
updateOverflowVisibility();
|
||||
|
||||
afterExpandedViewAnimation();
|
||||
previouslySelected.setContentVisibility(false);
|
||||
})
|
||||
.start();
|
||||
}
|
||||
|
||||
private float getCollapsedY() {
|
||||
return Math.min(mStackAnimationController.getStackPosition().y,
|
||||
mExpandedAnimateYDistance);
|
||||
private void animateSwitchBubbles() {
|
||||
// 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.getInstance(mAnimatingOutSurfaceContainer)
|
||||
.spring(DynamicAnimation.SCALE_X, 0f, mScaleOutSpringConfig)
|
||||
.spring(DynamicAnimation.SCALE_Y, 0f, mScaleOutSpringConfig)
|
||||
.spring(DynamicAnimation.TRANSLATION_Y,
|
||||
mAnimatingOutSurfaceContainer.getTranslationY() - mBubbleSize * 2,
|
||||
mTranslateSpringConfig)
|
||||
.withEndActions(this::releaseAnimatingOutBubbleBuffer)
|
||||
.start();
|
||||
|
||||
float expandingFromBubbleDestinationX =
|
||||
mExpandedAnimationController.getBubbleLeft(
|
||||
mBubbleData.getBubbles().indexOf(mExpandedBubble));
|
||||
|
||||
mExpandedViewContainer.setAlpha(1f);
|
||||
mExpandedViewContainer.setVisibility(View.VISIBLE);
|
||||
|
||||
mExpandedViewContainerMatrix.setScale(
|
||||
0f, 0f, expandingFromBubbleDestinationX + mBubbleSize / 2f, getExpandedViewY());
|
||||
mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
|
||||
|
||||
mExpandedViewContainer.postDelayed(() -> {
|
||||
if (!mIsExpanded) {
|
||||
return;
|
||||
}
|
||||
|
||||
PhysicsAnimator.getInstance(mExpandedViewContainerMatrix)
|
||||
.spring(AnimatableScaleMatrix.SCALE_X,
|
||||
AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
|
||||
mScaleInSpringConfig)
|
||||
.spring(AnimatableScaleMatrix.SCALE_Y,
|
||||
AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
|
||||
mScaleInSpringConfig)
|
||||
.addUpdateListener((target, values) -> {
|
||||
mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
|
||||
})
|
||||
.withEndActions(() -> {
|
||||
if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
|
||||
mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(false);
|
||||
}
|
||||
})
|
||||
.start();
|
||||
}, 25);
|
||||
}
|
||||
|
||||
private void notifyExpansionChanged(BubbleViewProvider bubble, boolean expanded) {
|
||||
@@ -2228,11 +2407,114 @@ public class BubbleStackView extends FrameLayout
|
||||
if (mIsExpanded && mExpandedBubble != null
|
||||
&& mExpandedBubble.getExpandedView() != null) {
|
||||
BubbleExpandedView bev = mExpandedBubble.getExpandedView();
|
||||
bev.setContentVisibility(false);
|
||||
mExpandedViewContainerMatrix.setScaleX(0f);
|
||||
mExpandedViewContainerMatrix.setScaleY(0f);
|
||||
mExpandedViewContainer.setVisibility(View.INVISIBLE);
|
||||
mExpandedViewContainer.setAlpha(0f);
|
||||
mExpandedViewContainer.addView(bev);
|
||||
bev.setManageClickListener((view) -> showManageMenu(!mShowingManage));
|
||||
bev.populateExpandedView();
|
||||
mExpandedViewContainer.setVisibility(VISIBLE);
|
||||
mExpandedViewContainer.setAlpha(1.0f);
|
||||
|
||||
if (!mIsExpansionAnimating) {
|
||||
mSurfaceSynchronizer.syncSurfaceAndRun(() -> {
|
||||
post(this::animateSwitchBubbles);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests a snapshot from the currently expanded bubble's ActivityView and displays it in a
|
||||
* SurfaceView. This allows us to load a newly expanded bubble's Activity into the ActivityView,
|
||||
* while animating the (screenshot of the) previously selected bubble's content away.
|
||||
*
|
||||
* @param onComplete Callback to run once we're done here - called with 'false' if something
|
||||
* went wrong, or 'true' if the SurfaceView is now showing a screenshot of the
|
||||
* expanded bubble.
|
||||
*/
|
||||
private void screenshotAnimatingOutBubbleIntoSurface(Consumer<Boolean> onComplete) {
|
||||
if (mExpandedBubble == null || mExpandedBubble.getExpandedView() == null) {
|
||||
// You can't animate null.
|
||||
onComplete.accept(false);
|
||||
return;
|
||||
}
|
||||
|
||||
final BubbleExpandedView animatingOutExpandedView = mExpandedBubble.getExpandedView();
|
||||
|
||||
// Release the previous screenshot if it hasn't been released already.
|
||||
if (mAnimatingOutBubbleBuffer != null) {
|
||||
releaseAnimatingOutBubbleBuffer();
|
||||
}
|
||||
|
||||
try {
|
||||
mAnimatingOutBubbleBuffer = animatingOutExpandedView.snapshotActivitySurface();
|
||||
} catch (Exception e) {
|
||||
// If we fail for any reason, print the stack trace and then notify the callback of our
|
||||
// failure. This is not expected to occur, but it's not worth crashing over.
|
||||
Log.wtf(TAG, e);
|
||||
onComplete.accept(false);
|
||||
}
|
||||
|
||||
if (mAnimatingOutBubbleBuffer == null
|
||||
|| mAnimatingOutBubbleBuffer.getGraphicBuffer() == null) {
|
||||
// While no exception was thrown, we were unable to get a snapshot.
|
||||
onComplete.accept(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure the surface container's properties have been reset.
|
||||
PhysicsAnimator.getInstance(mAnimatingOutSurfaceContainer).cancel();
|
||||
mAnimatingOutSurfaceContainer.setScaleX(1f);
|
||||
mAnimatingOutSurfaceContainer.setScaleY(1f);
|
||||
mAnimatingOutSurfaceContainer.setTranslationX(0);
|
||||
mAnimatingOutSurfaceContainer.setTranslationY(0);
|
||||
|
||||
final int[] activityViewLocation =
|
||||
mExpandedBubble.getExpandedView().getActivityViewLocationOnScreen();
|
||||
final int[] surfaceViewLocation = mAnimatingOutSurfaceView.getLocationOnScreen();
|
||||
|
||||
// Translate the surface to overlap the real ActivityView.
|
||||
mAnimatingOutSurfaceContainer.setTranslationY(
|
||||
activityViewLocation[1] - surfaceViewLocation[1]);
|
||||
|
||||
// Set the width/height of the SurfaceView to match the snapshot.
|
||||
mAnimatingOutSurfaceView.getLayoutParams().width =
|
||||
mAnimatingOutBubbleBuffer.getGraphicBuffer().getWidth();
|
||||
mAnimatingOutSurfaceView.getLayoutParams().height =
|
||||
mAnimatingOutBubbleBuffer.getGraphicBuffer().getHeight();
|
||||
mAnimatingOutSurfaceView.requestLayout();
|
||||
|
||||
// Post to wait for layout.
|
||||
post(() -> {
|
||||
// The buffer might have been destroyed if the user is mashing on bubbles, that's okay.
|
||||
if (mAnimatingOutBubbleBuffer.getGraphicBuffer().isDestroyed()) {
|
||||
onComplete.accept(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mIsExpanded) {
|
||||
onComplete.accept(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Attach the buffer! We're now displaying the snapshot.
|
||||
mAnimatingOutSurfaceView.getHolder().getSurface().attachAndQueueBufferWithColorSpace(
|
||||
mAnimatingOutBubbleBuffer.getGraphicBuffer(),
|
||||
mAnimatingOutBubbleBuffer.getColorSpace());
|
||||
|
||||
mSurfaceSynchronizer.syncSurfaceAndRun(() -> post(() -> onComplete.accept(true)));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the buffer containing the screenshot of the animating-out bubble, if it exists and
|
||||
* isn't yet destroyed.
|
||||
*/
|
||||
private void releaseAnimatingOutBubbleBuffer() {
|
||||
if (mAnimatingOutBubbleBuffer != null
|
||||
&& !mAnimatingOutBubbleBuffer.getGraphicBuffer().isDestroyed()) {
|
||||
mAnimatingOutBubbleBuffer.getGraphicBuffer().destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2242,19 +2524,10 @@ public class BubbleStackView extends FrameLayout
|
||||
}
|
||||
|
||||
mExpandedViewContainer.setVisibility(mIsExpanded ? VISIBLE : GONE);
|
||||
if (mIsExpanded) {
|
||||
final float y = getExpandedViewY();
|
||||
if (!mExpandedViewYAnim.isRunning()) {
|
||||
// We're not animating so set the value
|
||||
mExpandedViewContainer.setTranslationY(y);
|
||||
if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
|
||||
mExpandedBubble.getExpandedView().updateView();
|
||||
}
|
||||
} else {
|
||||
// We are animating so update the value; there is an end listener on the animator
|
||||
// that will ensure expandedeView.updateView gets called.
|
||||
mExpandedViewYAnim.animateToFinalPosition(y);
|
||||
}
|
||||
if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
|
||||
mExpandedViewContainer.setTranslationY(getExpandedViewY());
|
||||
mExpandedBubble.getExpandedView().updateView(
|
||||
mExpandedViewContainer.getLocationOnScreen());
|
||||
}
|
||||
|
||||
mStackOnLeftOrWillBe = mStackAnimationController.isStackOnLeftSide();
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.systemui.bubbles.animation;
|
||||
|
||||
import android.graphics.Matrix;
|
||||
|
||||
import androidx.dynamicanimation.animation.DynamicAnimation;
|
||||
import androidx.dynamicanimation.animation.FloatPropertyCompat;
|
||||
|
||||
/**
|
||||
* Matrix whose scale properties can be animated using physics animations, via the {@link #SCALE_X}
|
||||
* and {@link #SCALE_Y} FloatProperties.
|
||||
*
|
||||
* This is useful when you need to perform a scale animation with a pivot point, since pivot points
|
||||
* are not supported by standard View scale operations but are supported by matrices.
|
||||
*
|
||||
* NOTE: DynamicAnimation assumes that all custom properties are denominated in pixels, and thus
|
||||
* considers 1 to be the smallest user-visible change for custom properties. This means that if you
|
||||
* animate {@link #SCALE_X} and {@link #SCALE_Y} to 3f, for example, the animation would have only
|
||||
* three frames.
|
||||
*
|
||||
* To work around this, whenever animating to a desired scale value, animate to the value returned
|
||||
* by {@link #getAnimatableValueForScaleFactor} instead. The SCALE_X and SCALE_Y properties will
|
||||
* convert that (larger) value into the appropriate scale factor when scaling the matrix.
|
||||
*/
|
||||
public class AnimatableScaleMatrix extends Matrix {
|
||||
|
||||
/**
|
||||
* The X value of the scale.
|
||||
*
|
||||
* NOTE: This must be set or animated to the value returned by
|
||||
* {@link #getAnimatableValueForScaleFactor}, not the desired scale factor itself.
|
||||
*/
|
||||
public static final FloatPropertyCompat<AnimatableScaleMatrix> SCALE_X =
|
||||
new FloatPropertyCompat<AnimatableScaleMatrix>("matrixScaleX") {
|
||||
@Override
|
||||
public float getValue(AnimatableScaleMatrix object) {
|
||||
return getAnimatableValueForScaleFactor(object.mScaleX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(AnimatableScaleMatrix object, float value) {
|
||||
object.setScaleX(value * DynamicAnimation.MIN_VISIBLE_CHANGE_SCALE);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The Y value of the scale.
|
||||
*
|
||||
* NOTE: This must be set or animated to the value returned by
|
||||
* {@link #getAnimatableValueForScaleFactor}, not the desired scale factor itself.
|
||||
*/
|
||||
public static final FloatPropertyCompat<AnimatableScaleMatrix> SCALE_Y =
|
||||
new FloatPropertyCompat<AnimatableScaleMatrix>("matrixScaleY") {
|
||||
@Override
|
||||
public float getValue(AnimatableScaleMatrix object) {
|
||||
return getAnimatableValueForScaleFactor(object.mScaleY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(AnimatableScaleMatrix object, float value) {
|
||||
object.setScaleY(value * DynamicAnimation.MIN_VISIBLE_CHANGE_SCALE);
|
||||
}
|
||||
};
|
||||
|
||||
private float mScaleX = 1f;
|
||||
private float mScaleY = 1f;
|
||||
|
||||
private float mPivotX = 0f;
|
||||
private float mPivotY = 0f;
|
||||
|
||||
/**
|
||||
* Return the value to animate SCALE_X or SCALE_Y to in order to achieve the desired scale
|
||||
* factor.
|
||||
*/
|
||||
public static float getAnimatableValueForScaleFactor(float scale) {
|
||||
return scale * (1f / DynamicAnimation.MIN_VISIBLE_CHANGE_SCALE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setScale(float sx, float sy, float px, float py) {
|
||||
mScaleX = sx;
|
||||
mScaleY = sy;
|
||||
mPivotX = px;
|
||||
mPivotY = py;
|
||||
super.setScale(mScaleX, mScaleY, mPivotX, mPivotY);
|
||||
}
|
||||
|
||||
public void setScaleX(float scaleX) {
|
||||
mScaleX = scaleX;
|
||||
super.setScale(mScaleX, mScaleY, mPivotX, mPivotY);
|
||||
}
|
||||
|
||||
public void setScaleY(float scaleY) {
|
||||
mScaleY = scaleY;
|
||||
super.setScale(mScaleX, mScaleY, mPivotX, mPivotY);
|
||||
}
|
||||
|
||||
public void setPivotX(float pivotX) {
|
||||
mPivotX = pivotX;
|
||||
super.setScale(mScaleX, mScaleY, mPivotX, mPivotY);
|
||||
}
|
||||
|
||||
public void setPivotY(float pivotY) {
|
||||
mPivotY = pivotY;
|
||||
super.setScale(mScaleX, mScaleY, mPivotX, mPivotY);
|
||||
}
|
||||
|
||||
public float getScaleX() {
|
||||
return mScaleX;
|
||||
}
|
||||
|
||||
public float getScaleY() {
|
||||
return mScaleY;
|
||||
}
|
||||
|
||||
public float getPivotX() {
|
||||
return mPivotX;
|
||||
}
|
||||
|
||||
public float getPivotY() {
|
||||
return mPivotY;
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,7 @@ public class ExpandedAnimationController
|
||||
private static final int ANIMATE_TRANSLATION_FACTOR = 4;
|
||||
|
||||
/** Duration of the expand/collapse target path animation. */
|
||||
private static final int EXPAND_COLLAPSE_TARGET_ANIM_DURATION = 175;
|
||||
public static final int EXPAND_COLLAPSE_TARGET_ANIM_DURATION = 175;
|
||||
|
||||
/** Stiffness for the expand/collapse path-following animation. */
|
||||
private static final int EXPAND_COLLAPSE_ANIM_STIFFNESS = 1000;
|
||||
|
||||
@@ -425,7 +425,8 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
BubbleStackView stackView = mBubbleController.getStackView();
|
||||
mBubbleData.setExpanded(true);
|
||||
assertTrue(mBubbleController.isStackExpanded());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
|
||||
verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
|
||||
true, mRow2.getEntry().getKey());
|
||||
|
||||
assertTrue(mSysUiStateBubblesExpanded);
|
||||
|
||||
@@ -443,9 +444,11 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
mRow.getEntry()));
|
||||
|
||||
// collapse for previous bubble
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
|
||||
verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
|
||||
false, mRow2.getEntry().getKey());
|
||||
// expand for selected bubble
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
|
||||
verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
|
||||
true, mRow.getEntry().getKey());
|
||||
|
||||
// Collapse
|
||||
mBubbleController.collapseStack();
|
||||
|
||||
@@ -382,7 +382,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
BubbleStackView stackView = mBubbleController.getStackView();
|
||||
mBubbleData.setExpanded(true);
|
||||
assertTrue(mBubbleController.isStackExpanded());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
|
||||
verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
|
||||
true, mRow.getEntry().getKey());
|
||||
|
||||
// Last added is the one that is expanded
|
||||
assertEquals(mRow2.getEntry(), mBubbleData.getSelectedBubble().getEntry());
|
||||
@@ -397,9 +398,11 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
||||
mRow.getEntry()));
|
||||
|
||||
// collapse for previous bubble
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
|
||||
verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
|
||||
false, mRow2.getEntry().getKey());
|
||||
// expand for selected bubble
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
|
||||
verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
|
||||
true, mRow.getEntry().getKey());
|
||||
|
||||
// Collapse
|
||||
mBubbleController.collapseStack();
|
||||
|
||||
Reference in New Issue
Block a user