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

Commit 0a7f7818 authored by Mady Mellor's avatar Mady Mellor
Browse files

Inset the bubble bar expanded view instead of drawing our own header

* Use new method on TaskView to inset the app content when showing
  in bubble bar
* Update the visuals of the handle in the bubble bar expanded view to
  show three dots instead of a bar
* Make the header area a bit smaller (40 -> 32dp)
* Use a touch delegate to extend the touch area of the three dots
  past the top of the expanded view so that it's a 48dp height touch
  target.

Test: manual - enable bubble bar, get a bubble, expand it
             => observe the appearance of the header, should be 3 dots
                centered in the bar)
             => ensure that tapping slightly above the top edge of
                the expanded view triggers the menu
Bug: 279814257
Bug: 284205099
Change-Id: I2e918b1404d91b60c78e513ed0bf6d026109eb45
parent 34749149
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -228,12 +228,12 @@
    <dimen name="bubble_user_education_stack_padding">16dp</dimen>
    <!-- Size of the bubble bar (height), should match transient_taskbar_size in Launcher. -->
    <dimen name="bubblebar_size">72dp</dimen>
    <!-- The size of the drag handle / menu shown along with a bubble bar expanded view. -->
    <dimen name="bubble_bar_expanded_view_handle_size">40dp</dimen>
    <!-- The width of the drag handle shown along with a bubble bar expanded view. -->
    <dimen name="bubble_bar_expanded_view_handle_width">128dp</dimen>
    <!-- The height of the drag handle shown along with a bubble bar expanded view. -->
    <dimen name="bubble_bar_expanded_view_handle_height">4dp</dimen>
    <!-- The size of the caption bar inset at the top of bubble bar expanded view. -->
    <dimen name="bubble_bar_expanded_view_caption_height">32dp</dimen>
    <!-- The height of the dots shown for the caption menu in the bubble bar expanded view.. -->
    <dimen name="bubble_bar_expanded_view_caption_dot_size">4dp</dimen>
    <!-- The spacing between the dots for the caption menu in the bubble bar expanded view.. -->
    <dimen name="bubble_bar_expanded_view_caption_dot_spacing">4dp</dimen>
    <!-- Minimum width of the bubble bar manage menu. -->
    <dimen name="bubble_bar_manage_menu_min_width">200dp</dimen>
    <!-- Size of the dismiss icon in the bubble bar manage menu. -->
+7 −1
Original line number Diff line number Diff line
@@ -25,6 +25,8 @@ import android.graphics.PointF;
import android.util.Log;
import android.widget.FrameLayout;

import androidx.annotation.Nullable;

import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.animation.PhysicsAnimator;
import com.android.wm.shell.bubbles.BubbleOverflow;
@@ -111,7 +113,8 @@ public class BubbleBarAnimationHelper {
    /**
     * Animates the provided bubble's expanded view to the expanded state.
     */
    public void animateExpansion(BubbleViewProvider expandedBubble) {
    public void animateExpansion(BubbleViewProvider expandedBubble,
            @Nullable Runnable afterAnimation) {
        mExpandedBubble = expandedBubble;
        if (mExpandedBubble == null) {
            return;
@@ -160,6 +163,9 @@ public class BubbleBarAnimationHelper {
                    bev.setAnimationMatrix(null);
                    updateExpandedView();
                    bev.setSurfaceZOrderedOnTop(false);
                    if (afterAnimation != null) {
                        afterAnimation.run();
                    }
                })
                .start();
    }
+33 −38
Original line number Diff line number Diff line
@@ -16,12 +16,12 @@

package com.android.wm.shell.bubbles.bar;

import android.annotation.ColorInt;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Insets;
import android.graphics.Outline;
import android.graphics.Rect;
import android.util.AttributeSet;
@@ -63,7 +63,8 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
    private @Nullable TaskView mTaskView;
    private @Nullable BubbleOverflowContainerView mOverflowView;

    private int mHandleHeight;
    private int mCaptionHeight;

    private int mBackgroundColor;
    private float mCornerRadius = 0f;

@@ -97,8 +98,8 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
        super.onFinishInflate();
        Context context = getContext();
        setElevation(getResources().getDimensionPixelSize(R.dimen.bubble_elevation));
        mHandleHeight = context.getResources().getDimensionPixelSize(
                R.dimen.bubble_bar_expanded_view_handle_size);
        mCaptionHeight = context.getResources().getDimensionPixelSize(
                R.dimen.bubble_bar_expanded_view_caption_height);
        addView(mHandleView);
        applyThemeAttrs();
        setClipToOutline(true);
@@ -136,6 +137,9 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
            addView(mTaskView);
            mTaskView.setEnableSurfaceClipping(true);
            mTaskView.setCornerRadius(mCornerRadius);

            // Handle view needs to draw on top of task view.
            bringChildToFront(mHandleView);
        }
        mMenuViewController = new BubbleBarMenuViewController(mContext, this);
        mMenuViewController.setListener(new BubbleBarMenuViewController.Listener() {
@@ -169,6 +173,10 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
        });
    }

    public BubbleBarHandleView getHandleView() {
        return mHandleView;
    }

    // TODO (b/275087636): call this when theme/config changes
    /** Updates the view based on the current theme. */
    public void applyThemeAttrs() {
@@ -183,12 +191,12 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView

        ta.recycle();

        mHandleHeight = getResources().getDimensionPixelSize(
                R.dimen.bubble_bar_expanded_view_handle_size);
        mCaptionHeight = getResources().getDimensionPixelSize(
                R.dimen.bubble_bar_expanded_view_caption_height);

        if (mTaskView != null) {
            mTaskView.setCornerRadius(mCornerRadius);
            updateHandleAndBackgroundColor(true /* animated */);
            updateHandleColor(true /* animated */);
        }
    }

@@ -196,13 +204,12 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        int menuViewHeight = Math.min(mHandleHeight, height);
        int menuViewHeight = Math.min(mCaptionHeight, height);
        measureChild(mHandleView, widthMeasureSpec, MeasureSpec.makeMeasureSpec(menuViewHeight,
                MeasureSpec.getMode(heightMeasureSpec)));

        if (mTaskView != null) {
            int taskViewHeight = height - menuViewHeight;
            measureChild(mTaskView, widthMeasureSpec, MeasureSpec.makeMeasureSpec(taskViewHeight,
            measureChild(mTaskView, widthMeasureSpec, MeasureSpec.makeMeasureSpec(height,
                    MeasureSpec.getMode(heightMeasureSpec)));
        }
    }
@@ -210,19 +217,20 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        // Drag handle above
        final int dragHandleBottom = t + mHandleView.getMeasuredHeight();
        mHandleView.layout(l, t, r, dragHandleBottom);
        final int captionBottom = t + mCaptionHeight;
        if (mTaskView != null) {
            mTaskView.layout(l, dragHandleBottom, r,
                    dragHandleBottom + mTaskView.getMeasuredHeight());
            mTaskView.layout(l, t, r,
                    t + mTaskView.getMeasuredHeight());
            mTaskView.setCaptionInsets(Insets.of(0, mCaptionHeight, 0, 0));
        }
        // Handle draws on top of task view in the caption area.
        mHandleView.layout(l, t, r, captionBottom);
    }

    @Override
    public void onTaskCreated() {
        setContentVisibility(true);
        updateHandleAndBackgroundColor(false /* animated */);
        updateHandleColor(false /* animated */);
    }

    @Override
@@ -298,33 +306,20 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
    }

    /**
     * Updates the background color to match with task view status/bg color, and sets handle color
     * to contrast with the background
     * Updates the handle color based on the task view status bar or background color; if those
     * are transparent it defaults to the background color pulled from system theme attributes.
     */
    private void updateHandleAndBackgroundColor(boolean animated) {
        if (mTaskView == null) return;
        final int color = getTaskViewColor();
        final boolean isRegionDark = Color.luminance(color) <= 0.5;
        mHandleView.updateHandleColor(isRegionDark, animated);
        setBackgroundColor(color);
    }

    /**
     * Retrieves task view status/nav bar color or background if available
     *
     * TODO (b/283075226): Update with color sampling when
     *                     RegionSamplingHelper or alternative is available
     */
    private @ColorInt int getTaskViewColor() {
        if (mTaskView == null || mTaskView.getTaskInfo() == null) return mBackgroundColor;
    private void updateHandleColor(boolean animated) {
        if (mTaskView == null || mTaskView.getTaskInfo() == null) return;
        int color = mBackgroundColor;
        ActivityManager.TaskDescription taskDescription = mTaskView.getTaskInfo().taskDescription;
        if (taskDescription.getStatusBarColor() != Color.TRANSPARENT) {
            return taskDescription.getStatusBarColor();
            color = taskDescription.getStatusBarColor();
        } else if (taskDescription.getBackgroundColor() != Color.TRANSPARENT) {
            return taskDescription.getBackgroundColor();
        } else {
            return mBackgroundColor;
            color = taskDescription.getBackgroundColor();
        }
        final boolean isRegionDark = Color.luminance(color) <= 0.5;
        mHandleView.updateHandleColor(isRegionDark, animated);
    }

    /**
+32 −15
Original line number Diff line number Diff line
@@ -21,7 +21,8 @@ import android.animation.ObjectAnimator;
import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Outline;
import android.graphics.Rect;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewOutlineProvider;
@@ -37,8 +38,12 @@ import com.android.wm.shell.R;
public class BubbleBarHandleView extends View {
    private static final long COLOR_CHANGE_DURATION = 120;

    private int mHandleWidth;
    private int mHandleHeight;
    // The handle view is currently rendered as 3 evenly spaced dots.
    private int mDotSize;
    private int mDotSpacing;
    // Path used to draw the dots
    private final Path mPath = new Path();

    private @ColorInt int mHandleLightColor;
    private @ColorInt int mHandleDarkColor;
    private @Nullable ObjectAnimator mColorChangeAnim;
@@ -58,11 +63,10 @@ public class BubbleBarHandleView extends View {
    public BubbleBarHandleView(Context context, AttributeSet attrs, int defStyleAttr,
            int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);

        mHandleWidth = getResources().getDimensionPixelSize(
                R.dimen.bubble_bar_expanded_view_handle_width);
        mHandleHeight = getResources().getDimensionPixelSize(
                R.dimen.bubble_bar_expanded_view_handle_height);
        mDotSize = getResources().getDimensionPixelSize(
                R.dimen.bubble_bar_expanded_view_caption_dot_size);
        mDotSpacing = getResources().getDimensionPixelSize(
                R.dimen.bubble_bar_expanded_view_caption_dot_spacing);
        mHandleLightColor = ContextCompat.getColor(getContext(),
                R.color.bubble_bar_expanded_view_handle_light);
        mHandleDarkColor = ContextCompat.getColor(getContext(),
@@ -74,13 +78,26 @@ public class BubbleBarHandleView extends View {
            public void getOutline(View view, Outline outline) {
                final int handleCenterX = view.getWidth() / 2;
                final int handleCenterY = view.getHeight() / 2;
                final float handleRadius = mHandleHeight / 2f;
                Rect handleBounds = new Rect(
                        handleCenterX - mHandleWidth / 2,
                        handleCenterY - mHandleHeight / 2,
                        handleCenterX + mHandleWidth / 2,
                        handleCenterY + mHandleHeight / 2);
                outline.setRoundRect(handleBounds, handleRadius);
                final int handleTotalWidth = mDotSize * 3 + mDotSpacing * 2;
                final int handleLeft = handleCenterX - handleTotalWidth / 2;
                final int handleTop = handleCenterY - mDotSize / 2;
                final int handleBottom = handleTop + mDotSize;
                RectF dot1 = new RectF(
                        handleLeft, handleTop,
                        handleLeft + mDotSize, handleBottom);
                RectF dot2 = new RectF(
                        dot1.right + mDotSpacing, handleTop,
                        dot1.right + mDotSpacing + mDotSize, handleBottom
                );
                RectF dot3 = new RectF(
                        dot2.right + mDotSpacing, handleTop,
                        dot2.right + mDotSpacing + mDotSize, handleBottom
                );
                mPath.reset();
                mPath.addOval(dot1, Path.Direction.CW);
                mPath.addOval(dot2, Path.Direction.CW);
                mPath.addOval(dot3, Path.Direction.CW);
                outline.setPath(mPath);
            }
        });
    }
+17 −1
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.content.Context;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.drawable.ColorDrawable;
import android.view.TouchDelegate;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
@@ -68,6 +69,10 @@ public class BubbleBarLayerView extends FrameLayout
    private final Region mTouchableRegion = new Region();
    private final Rect mTempRect = new Rect();

    // Used to ensure touch target size for the menu shown on a bubble expanded view
    private TouchDelegate mHandleTouchDelegate;
    private final Rect mHandleTouchBounds = new Rect();

    public BubbleBarLayerView(Context context, BubbleController controller) {
        super(context);
        mBubbleController = controller;
@@ -164,7 +169,17 @@ public class BubbleBarLayerView extends FrameLayout

        mIsExpanded = true;
        mBubbleController.getSysuiProxy().onStackExpandChanged(true);
        mAnimationHelper.animateExpansion(mExpandedBubble);
        mAnimationHelper.animateExpansion(mExpandedBubble, () -> {
            if (mExpandedView == null) return;
            // Touch delegate for the menu
            BubbleBarHandleView view = mExpandedView.getHandleView();
            view.getBoundsOnScreen(mHandleTouchBounds);
            mHandleTouchBounds.top -= mPositioner.getBubblePaddingTop();
            mHandleTouchDelegate = new TouchDelegate(mHandleTouchBounds,
                    mExpandedView.getHandleView());
            setTouchDelegate(mHandleTouchDelegate);
        });

        showScrim(true);
    }

@@ -175,6 +190,7 @@ public class BubbleBarLayerView extends FrameLayout
        mAnimationHelper.animateCollapse(() -> removeView(viewToRemove));
        mBubbleController.getSysuiProxy().onStackExpandChanged(false);
        mExpandedView = null;
        setTouchDelegate(null);
        showScrim(false);
    }