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 d0b919cf6bbb7..a02fa9b18e49e 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 @@ -25,6 +25,7 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_EXPANDED_VIEW; import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES; import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.wm.shell.bubbles.BubblePositioner.MAX_HEIGHT; import android.annotation.NonNull; import android.annotation.SuppressLint; @@ -60,7 +61,6 @@ import android.widget.LinearLayout; import androidx.annotation.Nullable; import com.android.internal.policy.ScreenDecorationsUtils; -import com.android.launcher3.icons.IconNormalizer; import com.android.wm.shell.R; import com.android.wm.shell.TaskView; import com.android.wm.shell.common.AlphaOptimizedButton; @@ -77,7 +77,6 @@ public class BubbleExpandedView extends LinearLayout { // The triangle pointing to the expanded view private View mPointerView; - private int mPointerMargin; @Nullable private int[] mExpandedViewContainerLocation; private AlphaOptimizedButton mManageButton; @@ -102,9 +101,6 @@ public class BubbleExpandedView extends LinearLayout { */ private boolean mIsAlphaAnimating = false; - private int mMinHeight; - private int mOverflowHeight; - private int mManageButtonHeight; private int mPointerWidth; private int mPointerHeight; private float mPointerRadius; @@ -348,12 +344,8 @@ public class BubbleExpandedView extends LinearLayout { void updateDimensions() { Resources res = getResources(); - mMinHeight = res.getDimensionPixelSize(R.dimen.bubble_expanded_default_height); - mOverflowHeight = res.getDimensionPixelSize(R.dimen.bubble_overflow_height); - updateFontSize(); - mPointerMargin = res.getDimensionPixelSize(R.dimen.bubble_pointer_margin); mPointerWidth = res.getDimensionPixelSize(R.dimen.bubble_pointer_width); mPointerHeight = res.getDimensionPixelSize(R.dimen.bubble_pointer_height); mPointerRadius = getResources().getDimensionPixelSize(R.dimen.bubble_pointer_radius); @@ -369,7 +361,6 @@ public class BubbleExpandedView extends LinearLayout { updatePointerView(); } - mManageButtonHeight = res.getDimensionPixelSize(R.dimen.bubble_manage_button_height); if (mManageButton != null) { int visibility = mManageButton.getVisibility(); removeView(mManageButton); @@ -633,12 +624,11 @@ public class BubbleExpandedView extends LinearLayout { } if ((mBubble != null && mTaskView != null) || mIsOverflow) { - float desiredHeight = mIsOverflow - ? mPositioner.isLargeScreen() ? getMaxExpandedHeight() : mOverflowHeight - : mBubble.getDesiredHeight(mContext); - desiredHeight = Math.max(desiredHeight, mMinHeight); - float height = Math.min(desiredHeight, getMaxExpandedHeight()); - height = Math.max(height, mMinHeight); + float desiredHeight = mPositioner.getExpandedViewHeight(mBubble); + int maxHeight = mPositioner.getMaxExpandedViewHeight(mIsOverflow); + float height = desiredHeight == MAX_HEIGHT + ? maxHeight + : Math.min(desiredHeight, maxHeight); FrameLayout.LayoutParams lp = mIsOverflow ? (FrameLayout.LayoutParams) mOverflowView.getLayoutParams() : (FrameLayout.LayoutParams) mTaskView.getLayoutParams(); @@ -662,23 +652,6 @@ public class BubbleExpandedView extends LinearLayout { } } - private int getMaxExpandedHeight() { - int expandedContainerY = mExpandedViewContainerLocation != null - // Remove top insets back here because availableRect.height would account for that - ? mExpandedViewContainerLocation[1] - mPositioner.getInsets().top - : 0; - int settingsHeight = mIsOverflow ? 0 : mManageButtonHeight; - int pointerHeight = mPositioner.showBubblesVertically() - ? mPointerWidth - : (int) (mPointerHeight - mPointerOverlap + mPointerMargin); - return mPositioner.getAvailableRect().height() - - expandedContainerY - - getPaddingTop() - - getPaddingBottom() - - settingsHeight - - pointerHeight; - } - /** * Update appearance of the expanded view being displayed. * @@ -728,14 +701,11 @@ public class BubbleExpandedView extends LinearLayout { : mPointerHeight - mPointerOverlap; setPadding((int) paddingLeft, (int) paddingTop, (int) paddingRight, 0); - final float expandedViewY = mPositioner.getExpandedViewY(); - // TODO: I don't understand why it works but it does - why normalized in portrait - // & not in landscape? Am I missing ~2dp in the portrait expandedViewY calculation? - final float normalizedSize = IconNormalizer.getNormalizedCircleSize( - mPositioner.getBubbleSize()); - final float bubbleCenter = showVertically - ? bubblePosition + (mPositioner.getBubbleSize() / 2f) - expandedViewY - : bubblePosition + (normalizedSize / 2f) - mPointerWidth; + // Subtract the expandedViewY here because the pointer is placed within the expandedView. + float pointerPosition = mPositioner.getPointerPosition(bubblePosition); + final float bubbleCenter = mPositioner.showBubblesVertically() + ? pointerPosition - mPositioner.getExpandedViewY(mBubble, bubblePosition) + : pointerPosition; // Post because we need the width of the view post(() -> { float pointerY; 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 c600f56ba0c5a..0a856a8231a05 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 @@ -34,6 +34,7 @@ import android.view.WindowMetrics; import androidx.annotation.VisibleForTesting; +import com.android.launcher3.icons.IconNormalizer; import com.android.wm.shell.R; import java.lang.annotation.Retention; @@ -58,6 +59,8 @@ public class BubblePositioner { /** When the bubbles are collapsed in a stack only some of them are shown, this is how many. **/ 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; private Context mContext; private WindowManager mWindowManager; @@ -68,13 +71,16 @@ public class BubblePositioner { private int mMaxBubbles; private int mBubbleSize; - private int mBubbleBadgeSize; private int mSpacingBetweenBubbles; private int mExpandedViewLargeScreenWidth; private int mExpandedViewPadding; private int mPointerMargin; - private float mPointerWidth; - private float mPointerHeight; + private int mPointerWidth; + private int mPointerHeight; + private int mPointerOverlap; + private int mManageButtonHeight; + private int mExpandedViewMinHeight; + private int mOverflowHeight; private PointF mPinLocation; private PointF mRestingStackPosition; @@ -151,7 +157,6 @@ public class BubblePositioner { Resources res = mContext.getResources(); mBubbleSize = res.getDimensionPixelSize(R.dimen.bubble_size); - mBubbleBadgeSize = res.getDimensionPixelSize(R.dimen.bubble_badge_size); mSpacingBetweenBubbles = res.getDimensionPixelSize(R.dimen.bubble_spacing); mDefaultMaxBubbles = res.getInteger(R.integer.bubbles_max_rendered); @@ -161,6 +166,10 @@ 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); + mExpandedViewMinHeight = res.getDimensionPixelSize(R.dimen.bubble_expanded_default_height); + mOverflowHeight = res.getDimensionPixelSize(R.dimen.bubble_overflow_height); mMaxBubbles = calculateMaxBubbles(); @@ -296,8 +305,8 @@ public class BubblePositioner { return mPaddings; } - /** Calculates the y position of the expanded view when it is expanded. */ - public float getExpandedViewY() { + /** Gets the y position of the expanded view if it was top-aligned. */ + private float getExpandedViewYTopAligned() { final int top = getAvailableRect().top; if (showBubblesVertically()) { return top - mPointerWidth; @@ -306,6 +315,116 @@ public class BubblePositioner { } } + /** The maximum height the expanded view can be. */ + public int getMaxExpandedViewHeight(boolean isOverflow) { + int paddingTop = showBubblesVertically() + ? 0 + : mPointerHeight; + int settingsHeight = isOverflow ? 0 : mManageButtonHeight; + // Subtract pointer size because it's laid out in LinearLayout with the expanded view. + int pointerSize = showBubblesVertically() + ? mPointerWidth + : (mPointerHeight + mPointerMargin); + // Subtract top insets because availableRect.height would account for that + int expandedContainerY = (int) getExpandedViewYTopAligned() - getInsets().top; + return getAvailableRect().height() + - expandedContainerY + - paddingTop + - settingsHeight + - pointerSize; + } + + /** + * Determines the height for the bubble, ensuring a minimum height. If the height should be as + * big as available, returns {@link #MAX_HEIGHT}. + */ + public float getExpandedViewHeight(BubbleViewProvider bubble) { + boolean isOverflow = bubble == null || BubbleOverflow.KEY.equals(bubble.getKey()); + float desiredHeight = isOverflow + ? mOverflowHeight + : ((Bubble) bubble).getDesiredHeight(mContext); + int manageButtonHeight = isOverflow ? 0 : mManageButtonHeight; + desiredHeight = Math.max(manageButtonHeight + desiredHeight, mExpandedViewMinHeight); + if (desiredHeight > getMaxExpandedViewHeight(isOverflow)) { + return MAX_HEIGHT; + } + return desiredHeight; + } + + /** + * Gets the y position for the expanded view. This is the position on screen of the top + * horizontal line of the expanded view. + * + * @param bubble the bubble being positioned. + * @param bubblePosition the x position of the bubble if showing on top, the y position of the + * bubble if showing vertically. + * @return the y position for the expanded view. + */ + public float getExpandedViewY(BubbleViewProvider bubble, float bubblePosition) { + boolean isOverflow = bubble == null || BubbleOverflow.KEY.equals(bubble.getKey()); + float expandedViewHeight = getExpandedViewHeight(bubble); + float topAlignment = getExpandedViewYTopAligned(); + if (!showBubblesVertically() || expandedViewHeight == MAX_HEIGHT) { + // Top-align when bubbles are shown at the top or are max size. + return topAlignment; + } + // If we're here, we're showing vertically & developer has made height less than maximum. + int manageButtonHeight = isOverflow ? 0 : mManageButtonHeight; + float pointerPosition = getPointerPosition(bubblePosition); + float bottomIfCentered = pointerPosition + (expandedViewHeight / 2) + manageButtonHeight; + float topIfCentered = pointerPosition - (expandedViewHeight / 2); + if (topIfCentered > mPositionRect.top && mPositionRect.bottom > bottomIfCentered) { + // Center it + return pointerPosition - mPointerWidth - (expandedViewHeight / 2f); + } else if (topIfCentered <= mPositionRect.top) { + // Top align + return topAlignment; + } else { + // Bottom align + return mPositionRect.bottom - manageButtonHeight - expandedViewHeight - mPointerWidth; + } + } + + /** + * The position the pointer points to, the center of the bubble. + * + * @param bubblePosition the x position of the bubble if showing on top, the y position of the + * bubble if showing vertically. + * @return the position the tip of the pointer points to. The x position if showing on top, the + * y position if showing vertically. + */ + public float getPointerPosition(float bubblePosition) { + // TODO: I don't understand why it works but it does - why normalized in portrait + // & not in landscape? Am I missing ~2dp in the portrait expandedViewY calculation? + final float normalizedSize = IconNormalizer.getNormalizedCircleSize( + getBubbleSize()); + return showBubblesVertically() + ? bubblePosition + (getBubbleSize() / 2f) + : bubblePosition + (normalizedSize / 2f) - mPointerWidth; + } + + /** + * When bubbles are expanded in portrait, they display at the top of the screen in a horizontal + * row. When in landscape or on a large screen, they show at the left or right side in a + * vertical row. This method accounts for screen orientation and will return an x or y value + * for the position of the bubble in the row. + * + * @param index bubble index in the row. + * @param numberOfBubbles the number of bubbles (including the overflow) in the row. + * @return the y position of the bubble if showing vertically and the x position if showing + * horizontally. + */ + public float getBubbleXOrYForOrientation(int index, int numberOfBubbles) { + final float positionInBar = index * (mBubbleSize + mSpacingBetweenBubbles); + final float expandedStackSize = (numberOfBubbles * mBubbleSize) + + ((numberOfBubbles - 1) * mSpacingBetweenBubbles); + final float centerPosition = showBubblesVertically() + ? mPositionRect.centerY() + : mPositionRect.centerX(); + final float rowStart = centerPosition - (expandedStackSize / 2f); + return rowStart + positionInBar; + } + /** * 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 92e455ce4e3ac..2c6136b4f31e7 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 @@ -874,8 +874,10 @@ public class BubbleStackView extends FrameLayout mExpandedAnimationController.expandFromStack(() -> { afterExpandedViewAnimation(); } /* after */); + final float translationY = mPositioner.getExpandedViewY(mExpandedBubble, + getBubbleIndex(mExpandedBubble)); mExpandedViewContainer.setTranslationX(0f); - mExpandedViewContainer.setTranslationY(mPositioner.getExpandedViewY()); + mExpandedViewContainer.setTranslationY(translationY); mExpandedViewContainer.setAlpha(1f); } removeOnLayoutChangeListener(mOrientationChangedListener); @@ -1524,6 +1526,7 @@ public class BubbleStackView extends FrameLayout bubble.cleanupViews(); } updatePointerPosition(); + updateExpandedView(); logBubbleEvent(bubble, FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__DISMISSED); return; } @@ -1815,9 +1818,10 @@ public class BubbleStackView extends FrameLayout mTaskbarScrim.setVisibility(VISIBLE); mTaskbarScrim.animate().alpha(1f).start(); } - + final float translationY = mPositioner.getExpandedViewY(mExpandedBubble, + getBubbleIndex(mExpandedBubble)); mExpandedViewContainer.setTranslationX(0f); - mExpandedViewContainer.setTranslationY(mPositioner.getExpandedViewY()); + mExpandedViewContainer.setTranslationY(translationY); mExpandedViewContainer.setAlpha(1f); int index; @@ -1866,7 +1870,7 @@ public class BubbleStackView extends FrameLayout 1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT, 1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT, bubbleWillBeAt + mBubbleSize / 2f, - mPositioner.getExpandedViewY()); + translationY); } mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix); @@ -1970,7 +1974,7 @@ public class BubbleStackView extends FrameLayout mExpandedViewContainerMatrix.setScale( 1f, 1f, expandingFromBubbleAt + mBubbleSize / 2f, - mPositioner.getExpandedViewY()); + mPositioner.getExpandedViewY(mExpandedBubble, index)); } mExpandedViewAlphaAnimator.reverse(); @@ -2077,7 +2081,7 @@ public class BubbleStackView extends FrameLayout 1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT, 1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT, expandingFromBubbleDestination + mBubbleSize / 2f, - mPositioner.getExpandedViewY()); + mPositioner.getExpandedViewY(mExpandedBubble, expandingFromBubbleDestination)); } mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix); @@ -2698,7 +2702,9 @@ public class BubbleStackView extends FrameLayout mExpandedViewContainer.setVisibility(mIsExpanded ? VISIBLE : GONE); } if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) { - mExpandedViewContainer.setTranslationY(mPositioner.getExpandedViewY()); + mExpandedViewContainer.setTranslationY(mPositioner.getExpandedViewY(mExpandedBubble, + mExpandedAnimationController.getBubbleXOrYForOrientation( + getBubbleIndex(mExpandedBubble)))); mExpandedViewContainer.setTranslationX(0f); mExpandedBubble.getExpandedView().updateView( mExpandedViewContainer.getLocationOnScreen()); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java index df2b440c19df4..efe07fbf108df 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java @@ -83,12 +83,6 @@ public class ExpandedAnimationController private float mBubblePaddingTop; /** Size of each bubble. */ private float mBubbleSizePx; - /** Max number of bubbles shown in row above expanded view. */ - private int mBubblesMaxRendered; - /** Max amount of space to have between bubbles when expanded. */ - private int mBubblesMaxSpace; - /** Amount of space between the bubbles when expanded. */ - private float mSpaceBetweenBubbles; /** Whether the expand / collapse animation is running. */ private boolean mAnimatingExpand = false; @@ -211,8 +205,6 @@ public class ExpandedAnimationController mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top); mStackOffsetPx = res.getDimensionPixelSize(R.dimen.bubble_stack_offset); mBubbleSizePx = mPositioner.getBubbleSize(); - mBubblesMaxRendered = mPositioner.getMaxBubbles(); - mSpaceBetweenBubbles = res.getDimensionPixelSize(R.dimen.bubble_spacing); } /** @@ -628,14 +620,13 @@ public class ExpandedAnimationController } } - // TODO - could move to method on bubblePositioner if mSpaceBetweenBubbles gets moved /** * When bubbles are expanded in portrait, they display at the top of the screen in a horizontal * row. When in landscape or on a large screen, they show at the left or right side in a * vertical row. This method accounts for screen orientation and will return an x or y value * for the position of the bubble in the row. * - * @param index Bubble index in row. + * @param index bubble index in the row. * @return the y position of the bubble if showing vertically and the x position if showing * horizontally. */ @@ -643,15 +634,6 @@ public class ExpandedAnimationController if (mLayout == null) { return 0; } - final float positionInBar = index * (mBubbleSizePx + mSpaceBetweenBubbles); - Rect availableRect = mPositioner.getAvailableRect(); - final boolean isLandscape = mPositioner.showBubblesVertically(); - final float expandedStackSize = (mLayout.getChildCount() * mBubbleSizePx) - + ((mLayout.getChildCount() - 1) * mSpaceBetweenBubbles); - final float centerPosition = isLandscape - ? availableRect.centerY() - : availableRect.centerX(); - final float rowStart = centerPosition - (expandedStackSize / 2f); - return rowStart + positionInBar; + return mPositioner.getBubbleXOrYForOrientation(index, mLayout.getChildCount()); } }