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
This commit is contained in:
@@ -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. -->
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user