diff --git a/libs/WindowManager/Shell/res/drawable/bubble_manage_btn_bg.xml b/libs/WindowManager/Shell/res/drawable/bubble_manage_btn_bg.xml index 8710fb8ac69b2..96d2d7c954d83 100644 --- a/libs/WindowManager/Shell/res/drawable/bubble_manage_btn_bg.xml +++ b/libs/WindowManager/Shell/res/drawable/bubble_manage_btn_bg.xml @@ -18,7 +18,7 @@ diff --git a/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml b/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml index b333e33a7a5f2..7658fca588221 100644 --- a/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml +++ b/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml @@ -20,9 +20,10 @@ android:id="@+id/settings_button" android:layout_gravity="start" android:layout_width="wrap_content" - android:layout_height="40dp" - android:layout_marginTop="8dp" - android:layout_marginBottom="8dp" + android:layout_height="@dimen/bubble_manage_button_height" + android:layout_marginStart="@dimen/bubble_manage_button_margin" + android:layout_marginTop="@dimen/bubble_manage_button_margin" + android:layout_marginBottom="@dimen/bubble_manage_button_margin" android:focusable="true" android:text="@string/manage_bubbles_text" android:textSize="@*android:dimen/text_size_body_2_material" diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index 07bb890879419..7da31aa7d03a0 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -100,6 +100,8 @@ 8dp 6dp + + 200dp 16dp @@ -149,7 +151,11 @@ 16dp - 56dp + 36dp + + 68dp + + 16dp 60dp diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java index a02fa9b18e49e..252b588ec63f9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java @@ -735,6 +735,10 @@ public class BubbleExpandedView extends LinearLayout { mManageButton.getBoundsOnScreen(rect); } + public int getManageButtonMargin() { + return ((LinearLayout.LayoutParams) mManageButton.getLayoutParams()).getMarginStart(); + } + /** * Cleans up anything related to the task and {@code TaskView}. If this view should be reused * after this method is called, then diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java index 35a4f33ecf723..9374da4c4faba 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java @@ -56,9 +56,6 @@ import com.android.wm.shell.common.TriangleShape; * transform into the 'new' dot, which is used during flyout dismiss animations/gestures. */ 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; @@ -68,6 +65,8 @@ public class BubbleFlyoutView extends FrameLayout { // Whether the flyout view should show a pointer to the bubble. private static final boolean SHOW_POINTER = false; + private BubblePositioner mPositioner; + private final int mFlyoutPadding; private final int mFlyoutSpaceFromBubble; private final int mPointerSize; @@ -156,10 +155,11 @@ public class BubbleFlyoutView extends FrameLayout { /** Callback to run when the flyout is hidden. */ @Nullable private Runnable mOnHide; - public BubbleFlyoutView(Context context) { + public BubbleFlyoutView(Context context, BubblePositioner positioner) { super(context); - LayoutInflater.from(context).inflate(R.layout.bubble_flyout, this, true); + mPositioner = positioner; + LayoutInflater.from(context).inflate(R.layout.bubble_flyout, this, true); mFlyoutTextContainer = findViewById(R.id.bubble_flyout_text_container); mSenderText = findViewById(R.id.bubble_flyout_name); mSenderAvatar = findViewById(R.id.bubble_flyout_avatar); @@ -230,11 +230,11 @@ public class BubbleFlyoutView extends FrameLayout { /* * Fade animation for consecutive flyouts. */ - void animateUpdate(Bubble.FlyoutMessage flyoutMessage, float parentWidth, PointF stackPos, + void animateUpdate(Bubble.FlyoutMessage flyoutMessage, PointF stackPos, boolean hideDot, Runnable onHide) { mOnHide = onHide; final Runnable afterFadeOut = () -> { - updateFlyoutMessage(flyoutMessage, parentWidth); + updateFlyoutMessage(flyoutMessage); // Wait for TextViews to layout with updated height. post(() -> { fade(true /* in */, stackPos, hideDot, () -> {} /* after */); @@ -266,7 +266,7 @@ public class BubbleFlyoutView extends FrameLayout { .withEndAction(afterFade); } - private void updateFlyoutMessage(Bubble.FlyoutMessage flyoutMessage, float parentWidth) { + private void updateFlyoutMessage(Bubble.FlyoutMessage flyoutMessage) { final Drawable senderAvatar = flyoutMessage.senderAvatar; if (senderAvatar != null && flyoutMessage.isGroupChat) { mSenderAvatar.setVisibility(VISIBLE); @@ -278,8 +278,7 @@ public class BubbleFlyoutView extends FrameLayout { mSenderText.setTranslationX(0); } - final int maxTextViewWidth = - (int) (parentWidth * FLYOUT_MAX_WIDTH_PERCENT) - mFlyoutPadding * 2; + final int maxTextViewWidth = (int) mPositioner.getMaxFlyoutSize() - mFlyoutPadding * 2; // Name visibility if (!TextUtils.isEmpty(flyoutMessage.senderName)) { @@ -328,22 +327,20 @@ public class BubbleFlyoutView extends FrameLayout { void setupFlyoutStartingAsDot( Bubble.FlyoutMessage flyoutMessage, PointF stackPos, - float parentWidth, boolean arrowPointingLeft, int dotColor, @Nullable Runnable onLayoutComplete, @Nullable Runnable onHide, float[] dotCenter, - boolean hideDot, - BubblePositioner positioner) { + boolean hideDot) { - mBubbleSize = positioner.getBubbleSize(); + mBubbleSize = mPositioner.getBubbleSize(); mOriginalDotSize = SIZE_PERCENTAGE * mBubbleSize; mNewDotRadius = (DOT_SCALE * mOriginalDotSize) / 2f; mNewDotSize = mNewDotRadius * 2f; - updateFlyoutMessage(flyoutMessage, parentWidth); + updateFlyoutMessage(flyoutMessage); mArrowPointingLeft = arrowPointingLeft; mDotColor = dotColor; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java index 0a856a8231a05..df804ec174d38 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java @@ -61,10 +61,16 @@ public class BubblePositioner { public static final int NUM_VISIBLE_WHEN_RESTING = 2; /** Indicates a bubble's height should be the maximum available space. **/ public static final int MAX_HEIGHT = -1; + /** The max percent of screen width to use for the flyout on large screens. */ + public static final float FLYOUT_MAX_WIDTH_PERCENT_LARGE_SCREEN = 0.3f; + /** The max percent of screen width to use for the flyout on phone. */ + public static final float FLYOUT_MAX_WIDTH_PERCENT = 0.6f; + private Context mContext; private WindowManager mWindowManager; private Rect mPositionRect; + private Rect mScreenRect; private @Surface.Rotation int mRotation = Surface.ROTATION_0; private Insets mInsets; private int mDefaultMaxBubbles; @@ -77,10 +83,10 @@ public class BubblePositioner { private int mPointerMargin; private int mPointerWidth; private int mPointerHeight; - private int mPointerOverlap; private int mManageButtonHeight; private int mExpandedViewMinHeight; private int mOverflowHeight; + private int mMinimumFlyoutWidthLargeScreen; private PointF mPinLocation; private PointF mRestingStackPosition; @@ -149,6 +155,7 @@ public class BubblePositioner { mRotation = rotation; mInsets = insets; + mScreenRect = new Rect(bounds); mPositionRect = new Rect(bounds); mPositionRect.left += mInsets.left; mPositionRect.top += mInsets.top; @@ -166,10 +173,11 @@ public class BubblePositioner { mPointerWidth = res.getDimensionPixelSize(R.dimen.bubble_pointer_width); mPointerHeight = res.getDimensionPixelSize(R.dimen.bubble_pointer_height); mPointerMargin = res.getDimensionPixelSize(R.dimen.bubble_pointer_margin); - mPointerOverlap = res.getDimensionPixelSize(R.dimen.bubble_pointer_overlap); - mManageButtonHeight = res.getDimensionPixelSize(R.dimen.bubble_manage_button_height); + mManageButtonHeight = res.getDimensionPixelSize(R.dimen.bubble_manage_button_total_height); mExpandedViewMinHeight = res.getDimensionPixelSize(R.dimen.bubble_expanded_default_height); mOverflowHeight = res.getDimensionPixelSize(R.dimen.bubble_overflow_height); + mMinimumFlyoutWidthLargeScreen = res.getDimensionPixelSize( + R.dimen.bubbles_flyout_min_width_large_screen); mMaxBubbles = calculateMaxBubbles(); @@ -425,6 +433,17 @@ public class BubblePositioner { return rowStart + positionInBar; } + /** + * @return the width of the bubble flyout (message originating from the bubble). + */ + public float getMaxFlyoutSize() { + if (isLargeScreen()) { + return Math.max(mScreenRect.width() * FLYOUT_MAX_WIDTH_PERCENT_LARGE_SCREEN, + mMinimumFlyoutWidthLargeScreen); + } + return mScreenRect.width() * FLYOUT_MAX_WIDTH_PERCENT; + } + /** * Sets the stack's most recent position along the edge of the screen. This is saved when the * last bubble is removed, so that the stack can be restored in its previous position. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java index 126d7358925ef..8f2df4ab39722 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java @@ -1186,7 +1186,7 @@ public class BubbleStackView extends FrameLayout if (mFlyout != null) { removeView(mFlyout); } - mFlyout = new BubbleFlyoutView(getContext()); + mFlyout = new BubbleFlyoutView(getContext(), mPositioner); mFlyout.setVisibility(GONE); mFlyout.setOnClickListener(mFlyoutClickListener); mFlyout.setOnTouchListener(mFlyoutTouchListener); @@ -2423,20 +2423,19 @@ public class BubbleStackView extends FrameLayout if (mFlyout.getVisibility() == View.VISIBLE) { - mFlyout.animateUpdate(bubble.getFlyoutMessage(), getWidth(), + mFlyout.animateUpdate(bubble.getFlyoutMessage(), mStackAnimationController.getStackPosition(), !bubble.showDot(), mAfterFlyoutHidden /* onHide */); } else { mFlyout.setVisibility(INVISIBLE); mFlyout.setupFlyoutStartingAsDot(bubble.getFlyoutMessage(), - mStackAnimationController.getStackPosition(), getWidth(), + mStackAnimationController.getStackPosition(), mStackAnimationController.isStackOnLeftSide(), bubble.getIconView().getDotColor() /* dotColor */, expandFlyoutAfterDelay /* onLayoutComplete */, mAfterFlyoutHidden /* onHide */, bubble.getIconView().getDotCenter(), - !bubble.showDot(), - mPositioner); + !bubble.showDot()); } mFlyout.bringToFront(); }); @@ -2548,7 +2547,6 @@ public class BubbleStackView extends FrameLayout R.string.bubbles_app_settings, bubble.getAppName())); } - mExpandedBubble.getExpandedView().getManageButtonBoundsOnScreen(mTempRect); if (mExpandedBubble.getExpandedView().getTaskView() != null) { mExpandedBubble.getExpandedView().getTaskView().setObscuredTouchRect(mShowingManage ? new Rect(0, 0, getWidth(), getHeight()) @@ -2560,7 +2558,11 @@ public class BubbleStackView extends FrameLayout // When the menu is open, it should be at these coordinates. The menu pops out to the right // in LTR and to the left in RTL. - final float targetX = isLtr ? mTempRect.left : mTempRect.right - mManageMenu.getWidth(); + mExpandedBubble.getExpandedView().getManageButtonBoundsOnScreen(mTempRect); + final float margin = mExpandedBubble.getExpandedView().getManageButtonMargin(); + final float targetX = isLtr + ? mTempRect.left - margin + : mTempRect.right + margin - mManageMenu.getWidth(); final float targetY = mTempRect.bottom - mManageMenu.getHeight(); final float xOffsetForAnimation = (isLtr ? 1 : -1) * mManageMenu.getWidth() / 4f; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleFlyoutViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleFlyoutViewTest.java index 6644eaf28a62b..5c1bcb9753a4f 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleFlyoutViewTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleFlyoutViewTest.java @@ -63,7 +63,7 @@ public class BubbleFlyoutViewTest extends ShellTestCase { mFlyoutMessage.senderName = "Josh"; mFlyoutMessage.message = "Hello"; - mFlyout = new BubbleFlyoutView(getContext()); + mFlyout = new BubbleFlyoutView(getContext(), mPositioner); mFlyoutText = mFlyout.findViewById(R.id.bubble_flyout_text); mSenderName = mFlyout.findViewById(R.id.bubble_flyout_name); @@ -75,9 +75,8 @@ public class BubbleFlyoutViewTest extends ShellTestCase { public void testShowFlyout_isVisible() { mFlyout.setupFlyoutStartingAsDot( mFlyoutMessage, - new PointF(100, 100), 500, true, Color.WHITE, null, null, mDotCenter, - false, - mPositioner); + new PointF(100, 100), true, Color.WHITE, null, null, mDotCenter, + false); mFlyout.setVisibility(View.VISIBLE); assertEquals("Hello", mFlyoutText.getText()); @@ -89,9 +88,8 @@ public class BubbleFlyoutViewTest extends ShellTestCase { public void testFlyoutHide_runsCallback() { Runnable after = mock(Runnable.class); mFlyout.setupFlyoutStartingAsDot(mFlyoutMessage, - new PointF(100, 100), 500, true, Color.WHITE, null, after, mDotCenter, - false, - mPositioner); + new PointF(100, 100), true, Color.WHITE, null, after, mDotCenter, + false); mFlyout.hideFlyout(); verify(after).run(); @@ -100,9 +98,8 @@ public class BubbleFlyoutViewTest extends ShellTestCase { @Test public void testSetCollapsePercent() { mFlyout.setupFlyoutStartingAsDot(mFlyoutMessage, - new PointF(100, 100), 500, true, Color.WHITE, null, null, mDotCenter, - false, - mPositioner); + new PointF(100, 100), true, Color.WHITE, null, null, mDotCenter, + false); mFlyout.setVisibility(View.VISIBLE); mFlyout.setCollapsePercent(1f);