Loading packages/SystemUI/res/drawable/bubble_flyout.xml +4 −3 Original line number Diff line number Diff line Loading @@ -14,7 +14,6 @@ ~ limitations under the License --> <layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <!-- TODO: Add the triangle pointing to the bubble stack. --> <item> <shape android:shape="rectangle"> <solid android:color="?android:attr/colorBackgroundFloating" /> Loading @@ -22,8 +21,10 @@ android:bottomLeftRadius="?android:attr/dialogCornerRadius" android:topLeftRadius="?android:attr/dialogCornerRadius" android:bottomRightRadius="?android:attr/dialogCornerRadius" android:topRightRadius="?android:attr/dialogCornerRadius" /> android:topRightRadius="?android:attr/dialogCornerRadius" /> <padding android:left="@dimen/bubble_flyout_pointer_size" android:right="@dimen/bubble_flyout_pointer_size" /> </shape> </item> </layer-list> No newline at end of file packages/SystemUI/res/layout/bubble_flyout.xml +22 −11 Original line number Diff line number Diff line Loading @@ -15,19 +15,30 @@ --> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="@dimen/bubble_flyout_pointer_size" android:paddingRight="@dimen/bubble_flyout_pointer_size"> <FrameLayout android:id="@+id/bubble_flyout" android:layout_height="wrap_content" android:layout_width="wrap_content" android:background="@drawable/bubble_flyout" android:padding="@dimen/bubble_flyout_padding" android:paddingLeft="@dimen/bubble_flyout_padding_x" android:paddingRight="@dimen/bubble_flyout_padding_x" android:paddingTop="@dimen/bubble_flyout_padding_y" android:paddingBottom="@dimen/bubble_flyout_padding_y" android:translationZ="@dimen/bubble_flyout_elevation"> <TextView android:id="@+id/bubble_flyout_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:fontFamily="@*android:string/config_bodyFontFamily" android:maxLines="2" android:maxWidth="@dimen/bubble_flyout_maxwidth" android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title" /> android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"/> </FrameLayout> </FrameLayout> No newline at end of file packages/SystemUI/res/values/dimens.xml +9 −5 Original line number Diff line number Diff line Loading @@ -1070,16 +1070,20 @@ <dimen name="bubble_elevation">1dp</dimen> <!-- How much the bubble flyout text container is elevated. --> <dimen name="bubble_flyout_elevation">4dp</dimen> <!-- How much padding is around the flyout text. --> <dimen name="bubble_flyout_padding">16dp</dimen> <!-- The maximum width of a bubble flyout. --> <dimen name="bubble_flyout_maxwidth">200dp</dimen> <!-- How much padding is around the left and right sides of the flyout text. --> <dimen name="bubble_flyout_padding_x">16dp</dimen> <!-- How much padding is around the top and bottom of the flyout text. --> <dimen name="bubble_flyout_padding_y">8dp</dimen> <!-- Size of the triangle that points from the flyout to the bubble stack. --> <dimen name="bubble_flyout_pointer_size">6dp</dimen> <!-- How much space to leave between the flyout (tip of the arrow) and the bubble stack. --> <dimen name="bubble_flyout_space_from_bubble">8dp</dimen> <!-- Padding around a collapsed bubble --> <dimen name="bubble_view_padding">0dp</dimen> <!-- Padding between bubbles when displayed in expanded state --> <dimen name="bubble_padding">8dp</dimen> <!-- Size of individual bubbles. --> <dimen name="individual_bubble_size">56dp</dimen> <dimen name="individual_bubble_size">52dp</dimen> <!-- How much to inset the icon in the circle --> <dimen name="bubble_icon_inset">16dp</dimen> <!-- Padding around the view displayed when the bubble is expanded --> Loading packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +134 −22 Original line number Diff line number Diff line Loading @@ -22,16 +22,21 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import android.annotation.NonNull; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.Outline; import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.LayerDrawable; import android.graphics.drawable.ShapeDrawable; import android.os.Bundle; import android.service.notification.StatusBarNotification; import android.util.Log; import android.util.StatsLog; import android.view.Choreographer; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; Loading @@ -56,6 +61,7 @@ import com.android.systemui.R; import com.android.systemui.bubbles.animation.ExpandedAnimationController; import com.android.systemui.bubbles.animation.PhysicsAnimationLayout; import com.android.systemui.bubbles.animation.StackAnimationController; import com.android.systemui.recents.TriangleShape; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import java.math.BigDecimal; Loading @@ -73,6 +79,9 @@ public class BubbleStackView extends FrameLayout { /** Duration of the flyout alpha animations. */ private static final int FLYOUT_ALPHA_ANIMATION_DURATION = 100; /** Max width of the flyout, in terms of percent of the screen width. */ private static final float FLYOUT_MAX_WIDTH_PERCENT = .6f; /** How long to wait, in milliseconds, before hiding the flyout. */ @VisibleForTesting static final int FLYOUT_HIDE_AFTER = 5000; Loading Loading @@ -126,13 +135,17 @@ public class BubbleStackView extends FrameLayout { private FrameLayout mExpandedViewContainer; private View mFlyout; private FrameLayout mFlyoutContainer; private FrameLayout mFlyout; private TextView mFlyoutText; private ShapeDrawable mLeftFlyoutTriangle; private ShapeDrawable mRightFlyoutTriangle; /** Spring animation for the flyout. */ private SpringAnimation mFlyoutSpring; /** Runnable that fades out the flyout and then sets it to GONE. */ private Runnable mHideFlyout = () -> mFlyout.animate().alpha(0f).withEndAction(() -> mFlyout.setVisibility(GONE)); () -> mFlyoutContainer.animate().alpha(0f).withEndAction( () -> mFlyoutContainer.setVisibility(GONE)); /** Layout change listener that moves the stack to the nearest valid position on rotation. */ private OnLayoutChangeListener mMoveStackToValidPositionOnLayoutListener; Loading @@ -146,6 +159,9 @@ public class BubbleStackView extends FrameLayout { private int mBubbleSize; private int mBubblePadding; private int mFlyoutPadding; private int mFlyoutSpaceFromBubble; private int mPointerSize; private int mExpandedAnimateXDistance; private int mExpandedAnimateYDistance; private int mStatusBarHeight; Loading Loading @@ -218,6 +234,9 @@ public class BubbleStackView extends FrameLayout { Resources res = getResources(); mBubbleSize = res.getDimensionPixelSize(R.dimen.individual_bubble_size); mBubblePadding = res.getDimensionPixelSize(R.dimen.bubble_padding); mFlyoutPadding = res.getDimensionPixelSize(R.dimen.bubble_flyout_padding_x); mFlyoutSpaceFromBubble = res.getDimensionPixelSize(R.dimen.bubble_flyout_space_from_bubble); mPointerSize = res.getDimensionPixelSize(R.dimen.bubble_flyout_pointer_size); mExpandedAnimateXDistance = res.getDimensionPixelSize(R.dimen.bubble_expanded_animate_x_distance); mExpandedAnimateYDistance = Loading @@ -244,7 +263,6 @@ public class BubbleStackView extends FrameLayout { getResources().getInteger(R.integer.bubbles_max_rendered)); mBubbleContainer.setController(mStackAnimationController); mBubbleContainer.setElevation(elevation); mBubbleContainer.setPadding(padding, 0, padding, 0); mBubbleContainer.setClipChildren(false); addView(mBubbleContainer, new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)); Loading @@ -254,16 +272,17 @@ public class BubbleStackView extends FrameLayout { mExpandedViewContainer.setClipChildren(false); addView(mExpandedViewContainer); mFlyout = mInflater.inflate(R.layout.bubble_flyout, this, false); mFlyout.setVisibility(GONE); mFlyout.animate() mFlyoutContainer = (FrameLayout) mInflater.inflate(R.layout.bubble_flyout, this, false); mFlyoutContainer.setVisibility(GONE); mFlyoutContainer.setClipToPadding(false); mFlyoutContainer.setClipChildren(false); mFlyoutContainer.animate() .setDuration(FLYOUT_ALPHA_ANIMATION_DURATION) .setInterpolator(new AccelerateDecelerateInterpolator()); addView(mFlyout); mFlyoutText = mFlyout.findViewById(R.id.bubble_flyout_text); mFlyoutSpring = new SpringAnimation(mFlyout, DynamicAnimation.TRANSLATION_X); mFlyout = mFlyoutContainer.findViewById(R.id.bubble_flyout); addView(mFlyoutContainer); setupFlyout(); mExpandedViewXAnim = new SpringAnimation(mExpandedViewContainer, DynamicAnimation.TRANSLATION_X); Loading Loading @@ -592,7 +611,7 @@ public class BubbleStackView extends FrameLayout { } // Outside parts of view we care about. return null; } else if (isIntersecting(mFlyout, x, y)) { } else if (mFlyoutContainer.getVisibility() == VISIBLE && isIntersecting(mFlyout, x, y)) { return mFlyout; } Loading Loading @@ -828,27 +847,52 @@ public class BubbleStackView extends FrameLayout { if (updateMessage != null && !isExpanded() && !mIsExpansionAnimating && !mIsDragging) { final PointF stackPos = mStackAnimationController.getStackPosition(); mFlyout.setAlpha(0f); mFlyout.setVisibility(VISIBLE); // 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). mFlyoutText.setMaxWidth( (int) (getWidth() * FLYOUT_MAX_WIDTH_PERCENT) - mFlyoutPadding * 2); mFlyoutContainer.setAlpha(0f); mFlyoutContainer.setVisibility(VISIBLE); mFlyoutText.setText(updateMessage); mFlyout.measure(WRAP_CONTENT, WRAP_CONTENT); post(() -> { final boolean onLeft = mStackAnimationController.isStackOnLeftSide(); if (onLeft) { mLeftFlyoutTriangle.setAlpha(255); mRightFlyoutTriangle.setAlpha(0); } else { mLeftFlyoutTriangle.setAlpha(0); mRightFlyoutTriangle.setAlpha(255); } mFlyoutContainer.post(() -> { // Multi line flyouts get top-aligned to the bubble. if (mFlyoutText.getLineCount() > 1) { mFlyoutContainer.setTranslationY(stackPos.y); } else { // Single line flyouts are vertically centered with respect to the bubble. mFlyoutContainer.setTranslationY( stackPos.y + (mBubbleSize - mFlyout.getHeight()) / 2f); } final float destinationX = onLeft ? stackPos.x + mBubbleSize + mBubblePadding : stackPos.x - mFlyout.getMeasuredWidth(); ? stackPos.x + mBubbleSize + mFlyoutSpaceFromBubble : stackPos.x - mFlyoutContainer.getWidth() - mFlyoutSpaceFromBubble; // Translate towards the stack slightly, then spring out from the stack. mFlyout.setTranslationX(destinationX + (onLeft ? -mBubblePadding : mBubblePadding)); mFlyout.setTranslationY(stackPos.y); mFlyoutContainer.setTranslationX( destinationX + (onLeft ? -mBubblePadding : mBubblePadding)); mFlyout.animate().alpha(1f); mFlyoutContainer.animate().alpha(1f); mFlyoutSpring.animateToFinalPosition(destinationX); mFlyout.removeCallbacks(mHideFlyout); mFlyout.postDelayed(mHideFlyout, FLYOUT_HIDE_AFTER); }); logBubbleEvent(bubble, StatsLog.BUBBLE_UICHANGED__ACTION__FLYOUT); } } Loading @@ -869,7 +913,7 @@ public class BubbleStackView extends FrameLayout { mBubbleContainer.getBoundsOnScreen(outRect); } if (mFlyout.getVisibility() == View.VISIBLE) { if (mFlyoutContainer.getVisibility() == View.VISIBLE) { final Rect flyoutBounds = new Rect(); mFlyout.getBoundsOnScreen(flyoutBounds); outRect.union(flyoutBounds); Loading Loading @@ -923,6 +967,74 @@ public class BubbleStackView extends FrameLayout { } } /** Sets up the flyout views and drawables. */ private void setupFlyout() { // Retrieve the styled floating background color. TypedArray ta = mContext.obtainStyledAttributes( new int[] {android.R.attr.colorBackgroundFloating}); final int floatingBackgroundColor = ta.getColor(0, Color.WHITE); ta.recycle(); // Retrieve the flyout background, which is currently a rounded white rectangle with a // shadow but no triangular arrow pointing anywhere. final LayerDrawable flyoutBackground = (LayerDrawable) mFlyout.getBackground(); // Create the triangle drawables and set their color. mLeftFlyoutTriangle = new ShapeDrawable(TriangleShape.createHorizontal( mPointerSize, mPointerSize, true /* isPointingLeft */)); mRightFlyoutTriangle = new ShapeDrawable(TriangleShape.createHorizontal( mPointerSize, mPointerSize, false /* isPointingLeft */)); mLeftFlyoutTriangle.getPaint().setColor(floatingBackgroundColor); mRightFlyoutTriangle.getPaint().setColor(floatingBackgroundColor); // Add both triangles to the drawable. We'll show and hide the appropriate ones when we show // the flyout. final int leftTriangleIndex = flyoutBackground.addLayer(mLeftFlyoutTriangle); flyoutBackground.setLayerSize(leftTriangleIndex, mPointerSize, mPointerSize); flyoutBackground.setLayerGravity(leftTriangleIndex, Gravity.LEFT | Gravity.CENTER_VERTICAL); flyoutBackground.setLayerInsetLeft(leftTriangleIndex, -mPointerSize); final int rightTriangleIndex = flyoutBackground.addLayer(mRightFlyoutTriangle); flyoutBackground.setLayerSize(rightTriangleIndex, mPointerSize, mPointerSize); flyoutBackground.setLayerGravity( rightTriangleIndex, Gravity.RIGHT | Gravity.CENTER_VERTICAL); flyoutBackground.setLayerInsetRight(rightTriangleIndex, -mPointerSize); // Append the appropriate triangle's outline to the view's outline so that the shadows look // correct. mFlyout.setOutlineProvider(new ViewOutlineProvider() { @Override public void getOutline(View view, Outline outline) { final boolean leftPointing = mStackAnimationController.isStackOnLeftSide(); // Get the outline from the appropriate triangle. final Outline triangleOutline = new Outline(); if (leftPointing) { mLeftFlyoutTriangle.getOutline(triangleOutline); } else { mRightFlyoutTriangle.getOutline(triangleOutline); } // Offset it to the correct position, since it has no intrinsic position since // that is maintained by the parent LayerDrawable. triangleOutline.offset( leftPointing ? -mPointerSize : mFlyout.getWidth(), mFlyout.getHeight() / 2 - mPointerSize / 2); // Merge the outlines. final Outline compoundOutline = new Outline(); flyoutBackground.getOutline(compoundOutline); compoundOutline.mPath.addPath(triangleOutline.mPath); outline.set(compoundOutline); } }); mFlyoutText = mFlyout.findViewById(R.id.bubble_flyout_text); mFlyoutSpring = new SpringAnimation(mFlyoutContainer, DynamicAnimation.TRANSLATION_X); } private void applyCurrentState() { Log.d(TAG, "applyCurrentState: mIsExpanded=" + mIsExpanded); mExpandedViewContainer.setVisibility(mIsExpanded ? VISIBLE : GONE); Loading packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java +5 −4 Original line number Diff line number Diff line Loading @@ -120,7 +120,11 @@ public class StackAnimationController extends private float mStackOffset; /** Diameter of the bubbles themselves. */ private int mIndividualBubbleSize; /** Size of spacing around the bubbles, separating it from the edge of the screen. */ /** * The amount of space to add between the bubbles and certain UI elements, such as the top of * the screen or the IME. This does not apply to the left/right sides of the screen since the * stack goes offscreen intentionally. */ private int mBubblePadding; /** How far offscreen the stack rests. */ private int mBubbleOffscreen; Loading Loading @@ -381,7 +385,6 @@ public class StackAnimationController extends if (insets != null) { allowableRegion.left = -mBubbleOffscreen - mBubblePadding + Math.max( insets.getSystemWindowInsetLeft(), insets.getDisplayCutout() != null Loading @@ -391,7 +394,6 @@ public class StackAnimationController extends mLayout.getWidth() - mIndividualBubbleSize + mBubbleOffscreen - mBubblePadding - Math.max( insets.getSystemWindowInsetRight(), insets.getDisplayCutout() != null Loading Loading @@ -521,7 +523,6 @@ public class StackAnimationController extends if (mLayout.getChildCount() > 0) { property.setValue(mLayout.getChildAt(0), value); if (mLayout.getChildCount() > 1) { animationForChildAtIndex(1) .property(property, value + getOffsetForChainedPropertyAnimation(property)) Loading Loading
packages/SystemUI/res/drawable/bubble_flyout.xml +4 −3 Original line number Diff line number Diff line Loading @@ -14,7 +14,6 @@ ~ limitations under the License --> <layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <!-- TODO: Add the triangle pointing to the bubble stack. --> <item> <shape android:shape="rectangle"> <solid android:color="?android:attr/colorBackgroundFloating" /> Loading @@ -22,8 +21,10 @@ android:bottomLeftRadius="?android:attr/dialogCornerRadius" android:topLeftRadius="?android:attr/dialogCornerRadius" android:bottomRightRadius="?android:attr/dialogCornerRadius" android:topRightRadius="?android:attr/dialogCornerRadius" /> android:topRightRadius="?android:attr/dialogCornerRadius" /> <padding android:left="@dimen/bubble_flyout_pointer_size" android:right="@dimen/bubble_flyout_pointer_size" /> </shape> </item> </layer-list> No newline at end of file
packages/SystemUI/res/layout/bubble_flyout.xml +22 −11 Original line number Diff line number Diff line Loading @@ -15,19 +15,30 @@ --> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="@dimen/bubble_flyout_pointer_size" android:paddingRight="@dimen/bubble_flyout_pointer_size"> <FrameLayout android:id="@+id/bubble_flyout" android:layout_height="wrap_content" android:layout_width="wrap_content" android:background="@drawable/bubble_flyout" android:padding="@dimen/bubble_flyout_padding" android:paddingLeft="@dimen/bubble_flyout_padding_x" android:paddingRight="@dimen/bubble_flyout_padding_x" android:paddingTop="@dimen/bubble_flyout_padding_y" android:paddingBottom="@dimen/bubble_flyout_padding_y" android:translationZ="@dimen/bubble_flyout_elevation"> <TextView android:id="@+id/bubble_flyout_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:fontFamily="@*android:string/config_bodyFontFamily" android:maxLines="2" android:maxWidth="@dimen/bubble_flyout_maxwidth" android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title" /> android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"/> </FrameLayout> </FrameLayout> No newline at end of file
packages/SystemUI/res/values/dimens.xml +9 −5 Original line number Diff line number Diff line Loading @@ -1070,16 +1070,20 @@ <dimen name="bubble_elevation">1dp</dimen> <!-- How much the bubble flyout text container is elevated. --> <dimen name="bubble_flyout_elevation">4dp</dimen> <!-- How much padding is around the flyout text. --> <dimen name="bubble_flyout_padding">16dp</dimen> <!-- The maximum width of a bubble flyout. --> <dimen name="bubble_flyout_maxwidth">200dp</dimen> <!-- How much padding is around the left and right sides of the flyout text. --> <dimen name="bubble_flyout_padding_x">16dp</dimen> <!-- How much padding is around the top and bottom of the flyout text. --> <dimen name="bubble_flyout_padding_y">8dp</dimen> <!-- Size of the triangle that points from the flyout to the bubble stack. --> <dimen name="bubble_flyout_pointer_size">6dp</dimen> <!-- How much space to leave between the flyout (tip of the arrow) and the bubble stack. --> <dimen name="bubble_flyout_space_from_bubble">8dp</dimen> <!-- Padding around a collapsed bubble --> <dimen name="bubble_view_padding">0dp</dimen> <!-- Padding between bubbles when displayed in expanded state --> <dimen name="bubble_padding">8dp</dimen> <!-- Size of individual bubbles. --> <dimen name="individual_bubble_size">56dp</dimen> <dimen name="individual_bubble_size">52dp</dimen> <!-- How much to inset the icon in the circle --> <dimen name="bubble_icon_inset">16dp</dimen> <!-- Padding around the view displayed when the bubble is expanded --> Loading
packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +134 −22 Original line number Diff line number Diff line Loading @@ -22,16 +22,21 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import android.annotation.NonNull; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.Outline; import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.LayerDrawable; import android.graphics.drawable.ShapeDrawable; import android.os.Bundle; import android.service.notification.StatusBarNotification; import android.util.Log; import android.util.StatsLog; import android.view.Choreographer; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; Loading @@ -56,6 +61,7 @@ import com.android.systemui.R; import com.android.systemui.bubbles.animation.ExpandedAnimationController; import com.android.systemui.bubbles.animation.PhysicsAnimationLayout; import com.android.systemui.bubbles.animation.StackAnimationController; import com.android.systemui.recents.TriangleShape; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import java.math.BigDecimal; Loading @@ -73,6 +79,9 @@ public class BubbleStackView extends FrameLayout { /** Duration of the flyout alpha animations. */ private static final int FLYOUT_ALPHA_ANIMATION_DURATION = 100; /** Max width of the flyout, in terms of percent of the screen width. */ private static final float FLYOUT_MAX_WIDTH_PERCENT = .6f; /** How long to wait, in milliseconds, before hiding the flyout. */ @VisibleForTesting static final int FLYOUT_HIDE_AFTER = 5000; Loading Loading @@ -126,13 +135,17 @@ public class BubbleStackView extends FrameLayout { private FrameLayout mExpandedViewContainer; private View mFlyout; private FrameLayout mFlyoutContainer; private FrameLayout mFlyout; private TextView mFlyoutText; private ShapeDrawable mLeftFlyoutTriangle; private ShapeDrawable mRightFlyoutTriangle; /** Spring animation for the flyout. */ private SpringAnimation mFlyoutSpring; /** Runnable that fades out the flyout and then sets it to GONE. */ private Runnable mHideFlyout = () -> mFlyout.animate().alpha(0f).withEndAction(() -> mFlyout.setVisibility(GONE)); () -> mFlyoutContainer.animate().alpha(0f).withEndAction( () -> mFlyoutContainer.setVisibility(GONE)); /** Layout change listener that moves the stack to the nearest valid position on rotation. */ private OnLayoutChangeListener mMoveStackToValidPositionOnLayoutListener; Loading @@ -146,6 +159,9 @@ public class BubbleStackView extends FrameLayout { private int mBubbleSize; private int mBubblePadding; private int mFlyoutPadding; private int mFlyoutSpaceFromBubble; private int mPointerSize; private int mExpandedAnimateXDistance; private int mExpandedAnimateYDistance; private int mStatusBarHeight; Loading Loading @@ -218,6 +234,9 @@ public class BubbleStackView extends FrameLayout { Resources res = getResources(); mBubbleSize = res.getDimensionPixelSize(R.dimen.individual_bubble_size); mBubblePadding = res.getDimensionPixelSize(R.dimen.bubble_padding); mFlyoutPadding = res.getDimensionPixelSize(R.dimen.bubble_flyout_padding_x); mFlyoutSpaceFromBubble = res.getDimensionPixelSize(R.dimen.bubble_flyout_space_from_bubble); mPointerSize = res.getDimensionPixelSize(R.dimen.bubble_flyout_pointer_size); mExpandedAnimateXDistance = res.getDimensionPixelSize(R.dimen.bubble_expanded_animate_x_distance); mExpandedAnimateYDistance = Loading @@ -244,7 +263,6 @@ public class BubbleStackView extends FrameLayout { getResources().getInteger(R.integer.bubbles_max_rendered)); mBubbleContainer.setController(mStackAnimationController); mBubbleContainer.setElevation(elevation); mBubbleContainer.setPadding(padding, 0, padding, 0); mBubbleContainer.setClipChildren(false); addView(mBubbleContainer, new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)); Loading @@ -254,16 +272,17 @@ public class BubbleStackView extends FrameLayout { mExpandedViewContainer.setClipChildren(false); addView(mExpandedViewContainer); mFlyout = mInflater.inflate(R.layout.bubble_flyout, this, false); mFlyout.setVisibility(GONE); mFlyout.animate() mFlyoutContainer = (FrameLayout) mInflater.inflate(R.layout.bubble_flyout, this, false); mFlyoutContainer.setVisibility(GONE); mFlyoutContainer.setClipToPadding(false); mFlyoutContainer.setClipChildren(false); mFlyoutContainer.animate() .setDuration(FLYOUT_ALPHA_ANIMATION_DURATION) .setInterpolator(new AccelerateDecelerateInterpolator()); addView(mFlyout); mFlyoutText = mFlyout.findViewById(R.id.bubble_flyout_text); mFlyoutSpring = new SpringAnimation(mFlyout, DynamicAnimation.TRANSLATION_X); mFlyout = mFlyoutContainer.findViewById(R.id.bubble_flyout); addView(mFlyoutContainer); setupFlyout(); mExpandedViewXAnim = new SpringAnimation(mExpandedViewContainer, DynamicAnimation.TRANSLATION_X); Loading Loading @@ -592,7 +611,7 @@ public class BubbleStackView extends FrameLayout { } // Outside parts of view we care about. return null; } else if (isIntersecting(mFlyout, x, y)) { } else if (mFlyoutContainer.getVisibility() == VISIBLE && isIntersecting(mFlyout, x, y)) { return mFlyout; } Loading Loading @@ -828,27 +847,52 @@ public class BubbleStackView extends FrameLayout { if (updateMessage != null && !isExpanded() && !mIsExpansionAnimating && !mIsDragging) { final PointF stackPos = mStackAnimationController.getStackPosition(); mFlyout.setAlpha(0f); mFlyout.setVisibility(VISIBLE); // 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). mFlyoutText.setMaxWidth( (int) (getWidth() * FLYOUT_MAX_WIDTH_PERCENT) - mFlyoutPadding * 2); mFlyoutContainer.setAlpha(0f); mFlyoutContainer.setVisibility(VISIBLE); mFlyoutText.setText(updateMessage); mFlyout.measure(WRAP_CONTENT, WRAP_CONTENT); post(() -> { final boolean onLeft = mStackAnimationController.isStackOnLeftSide(); if (onLeft) { mLeftFlyoutTriangle.setAlpha(255); mRightFlyoutTriangle.setAlpha(0); } else { mLeftFlyoutTriangle.setAlpha(0); mRightFlyoutTriangle.setAlpha(255); } mFlyoutContainer.post(() -> { // Multi line flyouts get top-aligned to the bubble. if (mFlyoutText.getLineCount() > 1) { mFlyoutContainer.setTranslationY(stackPos.y); } else { // Single line flyouts are vertically centered with respect to the bubble. mFlyoutContainer.setTranslationY( stackPos.y + (mBubbleSize - mFlyout.getHeight()) / 2f); } final float destinationX = onLeft ? stackPos.x + mBubbleSize + mBubblePadding : stackPos.x - mFlyout.getMeasuredWidth(); ? stackPos.x + mBubbleSize + mFlyoutSpaceFromBubble : stackPos.x - mFlyoutContainer.getWidth() - mFlyoutSpaceFromBubble; // Translate towards the stack slightly, then spring out from the stack. mFlyout.setTranslationX(destinationX + (onLeft ? -mBubblePadding : mBubblePadding)); mFlyout.setTranslationY(stackPos.y); mFlyoutContainer.setTranslationX( destinationX + (onLeft ? -mBubblePadding : mBubblePadding)); mFlyout.animate().alpha(1f); mFlyoutContainer.animate().alpha(1f); mFlyoutSpring.animateToFinalPosition(destinationX); mFlyout.removeCallbacks(mHideFlyout); mFlyout.postDelayed(mHideFlyout, FLYOUT_HIDE_AFTER); }); logBubbleEvent(bubble, StatsLog.BUBBLE_UICHANGED__ACTION__FLYOUT); } } Loading @@ -869,7 +913,7 @@ public class BubbleStackView extends FrameLayout { mBubbleContainer.getBoundsOnScreen(outRect); } if (mFlyout.getVisibility() == View.VISIBLE) { if (mFlyoutContainer.getVisibility() == View.VISIBLE) { final Rect flyoutBounds = new Rect(); mFlyout.getBoundsOnScreen(flyoutBounds); outRect.union(flyoutBounds); Loading Loading @@ -923,6 +967,74 @@ public class BubbleStackView extends FrameLayout { } } /** Sets up the flyout views and drawables. */ private void setupFlyout() { // Retrieve the styled floating background color. TypedArray ta = mContext.obtainStyledAttributes( new int[] {android.R.attr.colorBackgroundFloating}); final int floatingBackgroundColor = ta.getColor(0, Color.WHITE); ta.recycle(); // Retrieve the flyout background, which is currently a rounded white rectangle with a // shadow but no triangular arrow pointing anywhere. final LayerDrawable flyoutBackground = (LayerDrawable) mFlyout.getBackground(); // Create the triangle drawables and set their color. mLeftFlyoutTriangle = new ShapeDrawable(TriangleShape.createHorizontal( mPointerSize, mPointerSize, true /* isPointingLeft */)); mRightFlyoutTriangle = new ShapeDrawable(TriangleShape.createHorizontal( mPointerSize, mPointerSize, false /* isPointingLeft */)); mLeftFlyoutTriangle.getPaint().setColor(floatingBackgroundColor); mRightFlyoutTriangle.getPaint().setColor(floatingBackgroundColor); // Add both triangles to the drawable. We'll show and hide the appropriate ones when we show // the flyout. final int leftTriangleIndex = flyoutBackground.addLayer(mLeftFlyoutTriangle); flyoutBackground.setLayerSize(leftTriangleIndex, mPointerSize, mPointerSize); flyoutBackground.setLayerGravity(leftTriangleIndex, Gravity.LEFT | Gravity.CENTER_VERTICAL); flyoutBackground.setLayerInsetLeft(leftTriangleIndex, -mPointerSize); final int rightTriangleIndex = flyoutBackground.addLayer(mRightFlyoutTriangle); flyoutBackground.setLayerSize(rightTriangleIndex, mPointerSize, mPointerSize); flyoutBackground.setLayerGravity( rightTriangleIndex, Gravity.RIGHT | Gravity.CENTER_VERTICAL); flyoutBackground.setLayerInsetRight(rightTriangleIndex, -mPointerSize); // Append the appropriate triangle's outline to the view's outline so that the shadows look // correct. mFlyout.setOutlineProvider(new ViewOutlineProvider() { @Override public void getOutline(View view, Outline outline) { final boolean leftPointing = mStackAnimationController.isStackOnLeftSide(); // Get the outline from the appropriate triangle. final Outline triangleOutline = new Outline(); if (leftPointing) { mLeftFlyoutTriangle.getOutline(triangleOutline); } else { mRightFlyoutTriangle.getOutline(triangleOutline); } // Offset it to the correct position, since it has no intrinsic position since // that is maintained by the parent LayerDrawable. triangleOutline.offset( leftPointing ? -mPointerSize : mFlyout.getWidth(), mFlyout.getHeight() / 2 - mPointerSize / 2); // Merge the outlines. final Outline compoundOutline = new Outline(); flyoutBackground.getOutline(compoundOutline); compoundOutline.mPath.addPath(triangleOutline.mPath); outline.set(compoundOutline); } }); mFlyoutText = mFlyout.findViewById(R.id.bubble_flyout_text); mFlyoutSpring = new SpringAnimation(mFlyoutContainer, DynamicAnimation.TRANSLATION_X); } private void applyCurrentState() { Log.d(TAG, "applyCurrentState: mIsExpanded=" + mIsExpanded); mExpandedViewContainer.setVisibility(mIsExpanded ? VISIBLE : GONE); Loading
packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java +5 −4 Original line number Diff line number Diff line Loading @@ -120,7 +120,11 @@ public class StackAnimationController extends private float mStackOffset; /** Diameter of the bubbles themselves. */ private int mIndividualBubbleSize; /** Size of spacing around the bubbles, separating it from the edge of the screen. */ /** * The amount of space to add between the bubbles and certain UI elements, such as the top of * the screen or the IME. This does not apply to the left/right sides of the screen since the * stack goes offscreen intentionally. */ private int mBubblePadding; /** How far offscreen the stack rests. */ private int mBubbleOffscreen; Loading Loading @@ -381,7 +385,6 @@ public class StackAnimationController extends if (insets != null) { allowableRegion.left = -mBubbleOffscreen - mBubblePadding + Math.max( insets.getSystemWindowInsetLeft(), insets.getDisplayCutout() != null Loading @@ -391,7 +394,6 @@ public class StackAnimationController extends mLayout.getWidth() - mIndividualBubbleSize + mBubbleOffscreen - mBubblePadding - Math.max( insets.getSystemWindowInsetRight(), insets.getDisplayCutout() != null Loading Loading @@ -521,7 +523,6 @@ public class StackAnimationController extends if (mLayout.getChildCount() > 0) { property.setValue(mLayout.getChildAt(0), value); if (mLayout.getChildCount() > 1) { animationForChildAtIndex(1) .property(property, value + getOffsetForChainedPropertyAnimation(property)) Loading