Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ebc87475 authored by Josh Tsuji's avatar Josh Tsuji Committed by Android (Google) Code Review
Browse files

Merge "Adjust the flyout sizing and appearance to match the design spec." into qt-dev

parents 4a5ddd0a 36b1b2ce
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -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" />
@@ -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
+22 −11
Original line number Diff line number Diff line
@@ -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
+9 −5
Original line number Diff line number Diff line
@@ -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 -->
+134 −22
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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 =
@@ -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));

@@ -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);
@@ -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;
        }

@@ -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);
        }
    }
@@ -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);
@@ -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);
+5 −4
Original line number Diff line number Diff line
@@ -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;
@@ -381,7 +385,6 @@ public class StackAnimationController extends
        if (insets != null) {
            allowableRegion.left =
                    -mBubbleOffscreen
                            - mBubblePadding
                            + Math.max(
                            insets.getSystemWindowInsetLeft(),
                            insets.getDisplayCutout() != null
@@ -391,7 +394,6 @@ public class StackAnimationController extends
                    mLayout.getWidth()
                            - mIndividualBubbleSize
                            + mBubbleOffscreen
                            - mBubblePadding
                            - Math.max(
                            insets.getSystemWindowInsetRight(),
                            insets.getDisplayCutout() != null
@@ -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))