Loading packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java +63 −29 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ package com.android.systemui.bubbles; import static android.graphics.Paint.ANTI_ALIAS_FLAG; import static android.graphics.Paint.FILTER_BITMAP_FLAG; import static com.android.systemui.Interpolators.ALPHA_IN; import static com.android.systemui.Interpolators.ALPHA_OUT; import android.animation.ArgbEvaluator; import android.content.Context; Loading Loading @@ -56,6 +58,11 @@ public class BubbleFlyoutView extends FrameLayout { /** Max width of the flyout, in terms of percent of the screen width. */ private static final float FLYOUT_MAX_WIDTH_PERCENT = .6f; /** Translation Y of fade animation. */ private static final float FLYOUT_FADE_Y = 40f; private static final long FLYOUT_FADE_DURATION = 200L; private final int mFlyoutPadding; private final int mFlyoutSpaceFromBubble; private final int mPointerSize; Loading Loading @@ -104,6 +111,9 @@ public class BubbleFlyoutView extends FrameLayout { /** The bounds of the flyout background, kept up to date as it transitions to the 'new' dot. */ private final RectF mBgRect = new RectF(); /** The y position of the flyout, relative to the top of the screen. */ private float mFlyoutY = 0f; /** * Percent progress in the transition from flyout to 'new' dot. These two values are the inverse * of each other (if we're 40% transitioned to the dot, we're 60% flyout), but it makes the code Loading Loading @@ -221,18 +231,33 @@ public class BubbleFlyoutView extends FrameLayout { mSenderText.setTextSize(TypedValue.COMPLEX_UNIT_PX, newFontSize); } /** Configures the flyout, collapsed into to dot form. */ void setupFlyoutStartingAsDot( Bubble.FlyoutMessage flyoutMessage, PointF stackPos, float parentWidth, boolean arrowPointingLeft, int dotColor, @Nullable Runnable onLayoutComplete, @Nullable Runnable onHide, float[] dotCenter, boolean hideDot) { /* * Fade animation for consecutive flyouts. */ void animateUpdate(Bubble.FlyoutMessage flyoutMessage, float parentWidth, float stackY) { fade(false /* in */); updateFlyoutMessage(flyoutMessage, parentWidth); // Wait for TextViews to layout with updated height. post(() -> { mFlyoutY = stackY + (mBubbleSize - mFlyoutTextContainer.getHeight()) / 2f; fade(true /* in */); }); } private void fade(boolean in) { setAlpha(in ? 0f : 1f); setTranslationY(in ? mFlyoutY : mFlyoutY + FLYOUT_FADE_Y); animate() .alpha(in ? 1f : 0f) .setDuration(FLYOUT_FADE_DURATION) .setInterpolator(in ? ALPHA_IN : ALPHA_OUT); animate() .translationY(in ? mFlyoutY : mFlyoutY - FLYOUT_FADE_Y) .setDuration(FLYOUT_FADE_DURATION) .setInterpolator(in ? ALPHA_IN : ALPHA_OUT); } private void updateFlyoutMessage(Bubble.FlyoutMessage flyoutMessage, float parentWidth) { final Drawable senderAvatar = flyoutMessage.senderAvatar; if (senderAvatar != null && flyoutMessage.isGroupChat) { mSenderAvatar.setVisibility(VISIBLE); Loading @@ -256,6 +281,27 @@ public class BubbleFlyoutView extends FrameLayout { mSenderText.setVisibility(GONE); } // Set the flyout TextView's max width in terms of percent, and then subtract out the // padding so that the entire flyout view will be the desired width (rather than the // TextView being the desired width + extra padding). mMessageText.setMaxWidth(maxTextViewWidth); mMessageText.setText(flyoutMessage.message); } /** Configures the flyout, collapsed into dot form. */ void setupFlyoutStartingAsDot( Bubble.FlyoutMessage flyoutMessage, PointF stackPos, float parentWidth, boolean arrowPointingLeft, int dotColor, @Nullable Runnable onLayoutComplete, @Nullable Runnable onHide, float[] dotCenter, boolean hideDot) { updateFlyoutMessage(flyoutMessage, parentWidth); mArrowPointingLeft = arrowPointingLeft; mDotColor = dotColor; mOnHide = onHide; Loading @@ -263,24 +309,12 @@ public class BubbleFlyoutView extends FrameLayout { setCollapsePercent(1f); // Set the flyout TextView's max width in terms of percent, and then subtract out the // padding so that the entire flyout view will be the desired width (rather than the // TextView being the desired width + extra padding). mMessageText.setMaxWidth(maxTextViewWidth); mMessageText.setText(flyoutMessage.message); // Wait for the TextView to lay out so we know its line count. // Wait for TextViews to layout with updated height. post(() -> { float restingTranslationY; // Multi line flyouts get top-aligned to the bubble. if (mMessageText.getLineCount() > 1) { restingTranslationY = stackPos.y + mBubbleIconTopPadding; } else { // Single line flyouts are vertically centered with respect to the bubble. restingTranslationY = // Flyout is vertically centered with respect to the bubble. mFlyoutY = stackPos.y + (mBubbleSize - mFlyoutTextContainer.getHeight()) / 2f; } setTranslationY(restingTranslationY); setTranslationY(mFlyoutY); // Calculate the translation required to position the flyout next to the bubble stack, // with the desired padding. Loading @@ -300,7 +334,7 @@ public class BubbleFlyoutView extends FrameLayout { final float dotPositionY = stackPos.y + mDotCenter[1] - adjustmentForScaleAway; final float distanceFromFlyoutLeftToDotCenterX = mRestingTranslationX - dotPositionX; final float distanceFromLayoutTopToDotCenterY = restingTranslationY - dotPositionY; final float distanceFromLayoutTopToDotCenterY = mFlyoutY - dotPositionY; mTranslationXWhenDot = -distanceFromFlyoutLeftToDotCenterX; mTranslationYWhenDot = -distanceFromLayoutTopToDotCenterY; Loading packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +30 −23 Original line number Diff line number Diff line Loading @@ -2171,11 +2171,7 @@ public class BubbleStackView extends FrameLayout return getStatusBarHeight() + mBubbleSize + mBubblePaddingTop; } /** * Animates in the flyout for the given bubble, if available, and then hides it after some time. */ @VisibleForTesting void animateInFlyoutForBubble(Bubble bubble) { private boolean shouldShowFlyout(Bubble bubble) { Bubble.FlyoutMessage flyoutMessage = bubble.getFlyoutMessage(); final BadgedImageView bubbleView = bubble.getIconView(); if (flyoutMessage == null Loading @@ -2187,11 +2183,22 @@ public class BubbleStackView extends FrameLayout || mIsGestureInProgress || mBubbleToExpandAfterFlyoutCollapse != null || bubbleView == null) { if (bubbleView != null) { if (bubbleView != null && mFlyout.getVisibility() != VISIBLE) { bubbleView.removeDotSuppressionFlag(BadgedImageView.SuppressionFlag.FLYOUT_VISIBLE); } // Skip the message if none exists, we're expanded or animating expansion, or we're // about to expand a bubble from the previous tapped flyout, or if bubble view is null. return false; } return true; } /** * Animates in the flyout for the given bubble, if available, and then hides it after some time. */ @VisibleForTesting void animateInFlyoutForBubble(Bubble bubble) { if (!shouldShowFlyout(bubble)) { return; } Loading @@ -2209,25 +2216,22 @@ public class BubbleStackView extends FrameLayout } // Stop suppressing the dot now that the flyout has morphed into the dot. bubbleView.removeDotSuppressionFlag( bubble.getIconView().removeDotSuppressionFlag( BadgedImageView.SuppressionFlag.FLYOUT_VISIBLE); mFlyout.setVisibility(INVISIBLE); // Hide the stack after a delay, if needed. updateTemporarilyInvisibleAnimation(false /* hideImmediately */); }; mFlyout.setVisibility(INVISIBLE); // Suppress the dot when we are animating the flyout. bubbleView.addDotSuppressionFlag( bubble.getIconView().addDotSuppressionFlag( BadgedImageView.SuppressionFlag.FLYOUT_VISIBLE); // Start flyout expansion. Post in case layout isn't complete and getWidth returns 0. post(() -> { // An auto-expanding bubble could have been posted during the time it takes to // layout. if (isExpanded()) { if (isExpanded() || bubble.getIconView() == null) { return; } final Runnable expandFlyoutAfterDelay = () -> { Loading @@ -2244,11 +2248,13 @@ public class BubbleStackView extends FrameLayout mFlyout.postDelayed(mAnimateInFlyout, 200); }; if (bubble.getIconView() == null) { return; } mFlyout.setupFlyoutStartingAsDot(flyoutMessage, if (mFlyout.getVisibility() == View.VISIBLE) { mFlyout.animateUpdate(bubble.getFlyoutMessage(), getWidth(), mStackAnimationController.getStackPosition().y); } else { mFlyout.setVisibility(INVISIBLE); mFlyout.setupFlyoutStartingAsDot(bubble.getFlyoutMessage(), mStackAnimationController.getStackPosition(), getWidth(), mStackAnimationController.isStackOnLeftSide(), bubble.getIconView().getDotColor() /* dotColor */, Loading @@ -2256,6 +2262,7 @@ public class BubbleStackView extends FrameLayout mAfterFlyoutHidden, bubble.getIconView().getDotCenter(), !bubble.showDot()); } mFlyout.bringToFront(); }); mFlyout.removeCallbacks(mHideFlyout); Loading Loading
packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java +63 −29 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ package com.android.systemui.bubbles; import static android.graphics.Paint.ANTI_ALIAS_FLAG; import static android.graphics.Paint.FILTER_BITMAP_FLAG; import static com.android.systemui.Interpolators.ALPHA_IN; import static com.android.systemui.Interpolators.ALPHA_OUT; import android.animation.ArgbEvaluator; import android.content.Context; Loading Loading @@ -56,6 +58,11 @@ public class BubbleFlyoutView extends FrameLayout { /** Max width of the flyout, in terms of percent of the screen width. */ private static final float FLYOUT_MAX_WIDTH_PERCENT = .6f; /** Translation Y of fade animation. */ private static final float FLYOUT_FADE_Y = 40f; private static final long FLYOUT_FADE_DURATION = 200L; private final int mFlyoutPadding; private final int mFlyoutSpaceFromBubble; private final int mPointerSize; Loading Loading @@ -104,6 +111,9 @@ public class BubbleFlyoutView extends FrameLayout { /** The bounds of the flyout background, kept up to date as it transitions to the 'new' dot. */ private final RectF mBgRect = new RectF(); /** The y position of the flyout, relative to the top of the screen. */ private float mFlyoutY = 0f; /** * Percent progress in the transition from flyout to 'new' dot. These two values are the inverse * of each other (if we're 40% transitioned to the dot, we're 60% flyout), but it makes the code Loading Loading @@ -221,18 +231,33 @@ public class BubbleFlyoutView extends FrameLayout { mSenderText.setTextSize(TypedValue.COMPLEX_UNIT_PX, newFontSize); } /** Configures the flyout, collapsed into to dot form. */ void setupFlyoutStartingAsDot( Bubble.FlyoutMessage flyoutMessage, PointF stackPos, float parentWidth, boolean arrowPointingLeft, int dotColor, @Nullable Runnable onLayoutComplete, @Nullable Runnable onHide, float[] dotCenter, boolean hideDot) { /* * Fade animation for consecutive flyouts. */ void animateUpdate(Bubble.FlyoutMessage flyoutMessage, float parentWidth, float stackY) { fade(false /* in */); updateFlyoutMessage(flyoutMessage, parentWidth); // Wait for TextViews to layout with updated height. post(() -> { mFlyoutY = stackY + (mBubbleSize - mFlyoutTextContainer.getHeight()) / 2f; fade(true /* in */); }); } private void fade(boolean in) { setAlpha(in ? 0f : 1f); setTranslationY(in ? mFlyoutY : mFlyoutY + FLYOUT_FADE_Y); animate() .alpha(in ? 1f : 0f) .setDuration(FLYOUT_FADE_DURATION) .setInterpolator(in ? ALPHA_IN : ALPHA_OUT); animate() .translationY(in ? mFlyoutY : mFlyoutY - FLYOUT_FADE_Y) .setDuration(FLYOUT_FADE_DURATION) .setInterpolator(in ? ALPHA_IN : ALPHA_OUT); } private void updateFlyoutMessage(Bubble.FlyoutMessage flyoutMessage, float parentWidth) { final Drawable senderAvatar = flyoutMessage.senderAvatar; if (senderAvatar != null && flyoutMessage.isGroupChat) { mSenderAvatar.setVisibility(VISIBLE); Loading @@ -256,6 +281,27 @@ public class BubbleFlyoutView extends FrameLayout { mSenderText.setVisibility(GONE); } // Set the flyout TextView's max width in terms of percent, and then subtract out the // padding so that the entire flyout view will be the desired width (rather than the // TextView being the desired width + extra padding). mMessageText.setMaxWidth(maxTextViewWidth); mMessageText.setText(flyoutMessage.message); } /** Configures the flyout, collapsed into dot form. */ void setupFlyoutStartingAsDot( Bubble.FlyoutMessage flyoutMessage, PointF stackPos, float parentWidth, boolean arrowPointingLeft, int dotColor, @Nullable Runnable onLayoutComplete, @Nullable Runnable onHide, float[] dotCenter, boolean hideDot) { updateFlyoutMessage(flyoutMessage, parentWidth); mArrowPointingLeft = arrowPointingLeft; mDotColor = dotColor; mOnHide = onHide; Loading @@ -263,24 +309,12 @@ public class BubbleFlyoutView extends FrameLayout { setCollapsePercent(1f); // Set the flyout TextView's max width in terms of percent, and then subtract out the // padding so that the entire flyout view will be the desired width (rather than the // TextView being the desired width + extra padding). mMessageText.setMaxWidth(maxTextViewWidth); mMessageText.setText(flyoutMessage.message); // Wait for the TextView to lay out so we know its line count. // Wait for TextViews to layout with updated height. post(() -> { float restingTranslationY; // Multi line flyouts get top-aligned to the bubble. if (mMessageText.getLineCount() > 1) { restingTranslationY = stackPos.y + mBubbleIconTopPadding; } else { // Single line flyouts are vertically centered with respect to the bubble. restingTranslationY = // Flyout is vertically centered with respect to the bubble. mFlyoutY = stackPos.y + (mBubbleSize - mFlyoutTextContainer.getHeight()) / 2f; } setTranslationY(restingTranslationY); setTranslationY(mFlyoutY); // Calculate the translation required to position the flyout next to the bubble stack, // with the desired padding. Loading @@ -300,7 +334,7 @@ public class BubbleFlyoutView extends FrameLayout { final float dotPositionY = stackPos.y + mDotCenter[1] - adjustmentForScaleAway; final float distanceFromFlyoutLeftToDotCenterX = mRestingTranslationX - dotPositionX; final float distanceFromLayoutTopToDotCenterY = restingTranslationY - dotPositionY; final float distanceFromLayoutTopToDotCenterY = mFlyoutY - dotPositionY; mTranslationXWhenDot = -distanceFromFlyoutLeftToDotCenterX; mTranslationYWhenDot = -distanceFromLayoutTopToDotCenterY; Loading
packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +30 −23 Original line number Diff line number Diff line Loading @@ -2171,11 +2171,7 @@ public class BubbleStackView extends FrameLayout return getStatusBarHeight() + mBubbleSize + mBubblePaddingTop; } /** * Animates in the flyout for the given bubble, if available, and then hides it after some time. */ @VisibleForTesting void animateInFlyoutForBubble(Bubble bubble) { private boolean shouldShowFlyout(Bubble bubble) { Bubble.FlyoutMessage flyoutMessage = bubble.getFlyoutMessage(); final BadgedImageView bubbleView = bubble.getIconView(); if (flyoutMessage == null Loading @@ -2187,11 +2183,22 @@ public class BubbleStackView extends FrameLayout || mIsGestureInProgress || mBubbleToExpandAfterFlyoutCollapse != null || bubbleView == null) { if (bubbleView != null) { if (bubbleView != null && mFlyout.getVisibility() != VISIBLE) { bubbleView.removeDotSuppressionFlag(BadgedImageView.SuppressionFlag.FLYOUT_VISIBLE); } // Skip the message if none exists, we're expanded or animating expansion, or we're // about to expand a bubble from the previous tapped flyout, or if bubble view is null. return false; } return true; } /** * Animates in the flyout for the given bubble, if available, and then hides it after some time. */ @VisibleForTesting void animateInFlyoutForBubble(Bubble bubble) { if (!shouldShowFlyout(bubble)) { return; } Loading @@ -2209,25 +2216,22 @@ public class BubbleStackView extends FrameLayout } // Stop suppressing the dot now that the flyout has morphed into the dot. bubbleView.removeDotSuppressionFlag( bubble.getIconView().removeDotSuppressionFlag( BadgedImageView.SuppressionFlag.FLYOUT_VISIBLE); mFlyout.setVisibility(INVISIBLE); // Hide the stack after a delay, if needed. updateTemporarilyInvisibleAnimation(false /* hideImmediately */); }; mFlyout.setVisibility(INVISIBLE); // Suppress the dot when we are animating the flyout. bubbleView.addDotSuppressionFlag( bubble.getIconView().addDotSuppressionFlag( BadgedImageView.SuppressionFlag.FLYOUT_VISIBLE); // Start flyout expansion. Post in case layout isn't complete and getWidth returns 0. post(() -> { // An auto-expanding bubble could have been posted during the time it takes to // layout. if (isExpanded()) { if (isExpanded() || bubble.getIconView() == null) { return; } final Runnable expandFlyoutAfterDelay = () -> { Loading @@ -2244,11 +2248,13 @@ public class BubbleStackView extends FrameLayout mFlyout.postDelayed(mAnimateInFlyout, 200); }; if (bubble.getIconView() == null) { return; } mFlyout.setupFlyoutStartingAsDot(flyoutMessage, if (mFlyout.getVisibility() == View.VISIBLE) { mFlyout.animateUpdate(bubble.getFlyoutMessage(), getWidth(), mStackAnimationController.getStackPosition().y); } else { mFlyout.setVisibility(INVISIBLE); mFlyout.setupFlyoutStartingAsDot(bubble.getFlyoutMessage(), mStackAnimationController.getStackPosition(), getWidth(), mStackAnimationController.isStackOnLeftSide(), bubble.getIconView().getDotColor() /* dotColor */, Loading @@ -2256,6 +2262,7 @@ public class BubbleStackView extends FrameLayout mAfterFlyoutHidden, bubble.getIconView().getDotCenter(), !bubble.showDot()); } mFlyout.bringToFront(); }); mFlyout.removeCallbacks(mHideFlyout); Loading