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

Commit 238f122f authored by Mady Mellor's avatar Mady Mellor
Browse files

Flexible maximum number of bubbles to show

* adjust the default spacing so that its small enough that 5 bubbles
  can show on crosshatch (5 is the default)
* Add max bubbles to BubblePositioner, replace the other usages

Test: atest BubbleDataTest
Test: manual - have 5 bubbles
             - adjust screen size to largest
             - open the stack
             => notice that the number of bubbles have changed and
               they all fit on the screen without overlap
             - repeat & check the different densities
Bug: 187715444
Change-Id: I4794ed89541eeb573c367748f980cf7ffe45d3f3
parent 5f00d564
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -102,7 +102,7 @@
    <!-- Padding between status bar and bubbles when displayed in expanded state -->
    <dimen name="bubble_padding_top">16dp</dimen>
    <!-- Space between bubbles when expanded. -->
    <dimen name="bubble_spacing">8dp</dimen>
    <dimen name="bubble_spacing">3dp</dimen>
    <!-- Size of the bubble. -->
    <dimen name="bubble_size">60dp</dimen>
    <!-- Size of the badge shown on the bubble. -->
+1 −0
Original line number Diff line number Diff line
@@ -710,6 +710,7 @@ public class BubbleController {
                    || !newConfig.windowConfiguration.getBounds().equals(mScreenBounds)) {
                mDensityDpi = newConfig.densityDpi;
                mScreenBounds.set(newConfig.windowConfiguration.getBounds());
                mBubbleData.onMaxBubblesChanged();
                mBubbleIconFactory = new BubbleIconFactory(mContext);
                mStackView.onDisplaySizeChanged();
            }
+26 −4
Original line number Diff line number Diff line
@@ -141,9 +141,11 @@ public class BubbleData {
    private final BubbleOverflow mOverflow;
    private boolean mShowingOverflow;
    private boolean mExpanded;
    private final int mMaxBubbles;
    private int mMaxBubbles;
    private int mMaxOverflowBubbles;

    private boolean mNeedsTrimming;

    // State tracked during an operation -- keeps track of what listener events to dispatch.
    private Update mStateChange;

@@ -180,7 +182,7 @@ public class BubbleData {
        mOverflowBubbles = new ArrayList<>();
        mPendingBubbles = new HashMap<>();
        mStateChange = new Update(mBubbles, mOverflowBubbles);
        mMaxBubbles = mContext.getResources().getInteger(R.integer.bubbles_max_rendered);
        mMaxBubbles = mPositioner.getMaxBubbles();
        mMaxOverflowBubbles = mContext.getResources().getInteger(R.integer.bubbles_max_overflow);
    }

@@ -194,6 +196,16 @@ public class BubbleData {
        mCancelledListener = listener;
    }

    public void onMaxBubblesChanged() {
        mMaxBubbles = mPositioner.getMaxBubbles();
        if (!mExpanded) {
            trim();
            dispatchPendingChanges();
        } else {
            mNeedsTrimming = true;
        }
    }

    public boolean hasBubbles() {
        return !mBubbles.isEmpty();
    }
@@ -455,13 +467,19 @@ public class BubbleData {

    private void trim() {
        if (mBubbles.size() > mMaxBubbles) {
            int numtoRemove = mBubbles.size() - mMaxBubbles;
            ArrayList<Bubble> toRemove = new ArrayList<>();
            mBubbles.stream()
                    // sort oldest first (ascending lastActivity)
                    .sorted(Comparator.comparingLong(Bubble::getLastActivity))
                    // skip the selected bubble
                    .filter((b) -> !b.equals(mSelectedBubble))
                    .findFirst()
                    .ifPresent((b) -> doRemove(b.getKey(), Bubbles.DISMISS_AGED));
                    .forEachOrdered((b) -> {
                        if (toRemove.size() < numtoRemove) {
                            toRemove.add(b);
                        }
                    });
            toRemove.forEach((b) -> doRemove(b.getKey(), Bubbles.DISMISS_AGED));
        }
    }

@@ -770,6 +788,10 @@ public class BubbleData {
                }
            }
        }
        if (mNeedsTrimming) {
            mNeedsTrimming = false;
            trim();
        }
        mExpanded = shouldExpand;
        mStateChange.expanded = shouldExpand;
        mStateChange.expandedChanged = true;
+36 −0
Original line number Diff line number Diff line
@@ -64,9 +64,12 @@ public class BubblePositioner {
    private Rect mPositionRect;
    private @Surface.Rotation int mRotation = Surface.ROTATION_0;
    private Insets mInsets;
    private int mDefaultMaxBubbles;
    private int mMaxBubbles;

    private int mBubbleSize;
    private int mBubbleBadgeSize;
    private int mSpacingBetweenBubbles;
    private int mExpandedViewLargeScreenWidth;
    private int mExpandedViewPadding;
    private int mPointerMargin;
@@ -149,17 +152,45 @@ 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);

        mExpandedViewLargeScreenWidth = res.getDimensionPixelSize(
                R.dimen.bubble_expanded_view_tablet_width);
        mExpandedViewPadding = res.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding);
        mPointerWidth = res.getDimensionPixelSize(R.dimen.bubble_pointer_width);
        mPointerHeight = res.getDimensionPixelSize(R.dimen.bubble_pointer_height);
        mPointerMargin = res.getDimensionPixelSize(R.dimen.bubble_pointer_margin);

        mMaxBubbles = calculateMaxBubbles();

        if (mShowingInTaskbar) {
            adjustForTaskbar();
        }
    }

    /**
     * @return the maximum number of bubbles that can fit on the screen when expanded. If the
     * screen size / screen density is too small to support the default maximum number, then
     * the number will be adjust to something lower to ensure everything is presented nicely.
     */
    private int calculateMaxBubbles() {
        // Use the shortest edge.
        // In portrait the bubbles should align with the expanded view so subtract its padding.
        // We always show the overflow so subtract one bubble size.
        int padding = showBubblesVertically() ? 0 : (mExpandedViewPadding * 2);
        int availableSpace = Math.min(mPositionRect.width(), mPositionRect.height())
                - padding
                - mBubbleSize;
        // Each of the bubbles have spacing because the overflow is at the end.
        int howManyFit = availableSpace / (mBubbleSize + mSpacingBetweenBubbles);
        if (howManyFit < mDefaultMaxBubbles) {
            // Not enough space for the default.
            return howManyFit;
        }
        return mDefaultMaxBubbles;
    }

    /**
     * Taskbar insets appear as navigationBar insets, however, unlike navigationBar this should
     * not inset bubbles UI as bubbles floats above the taskbar. This adjust the available space
@@ -229,6 +260,11 @@ public class BubblePositioner {
                : mBubbleSize;
    }

    /** The maximum number of bubbles that can be displayed comfortably on screen. */
    public int getMaxBubbles() {
        return mMaxBubbles;
    }

    /**
     * Calculates the left & right padding for the bubble expanded view.
     *
+2 −4
Original line number Diff line number Diff line
@@ -243,7 +243,6 @@ public class BubbleStackView extends FrameLayout

    @Nullable private RelativeStackPosition mRelativeStackPositionBeforeRotation;

    private int mMaxBubbles;
    private int mBubbleSize;
    private int mBubbleElevation;
    private int mBubbleTouchPadding;
@@ -764,7 +763,6 @@ public class BubbleStackView extends FrameLayout
        mBubbleData = data;

        Resources res = getResources();
        mMaxBubbles = res.getInteger(R.integer.bubbles_max_rendered);
        mBubbleSize = res.getDimensionPixelSize(R.dimen.bubble_size);
        mBubbleElevation = res.getDimensionPixelSize(R.dimen.bubble_elevation);
        mBubbleTouchPadding = res.getDimensionPixelSize(R.dimen.bubble_touch_padding);
@@ -2725,7 +2723,7 @@ public class BubbleStackView extends FrameLayout
    private void updateBubbleShadows(boolean showForAllBubbles) {
        int bubbleCount = getBubbleCount();
        for (int i = 0; i < bubbleCount; i++) {
            final float z = (mMaxBubbles * mBubbleElevation) - i;
            final float z = (mPositioner.getMaxBubbles() * mBubbleElevation) - i;
            BadgedImageView bv = (BadgedImageView) mBubbleContainer.getChildAt(i);
            boolean isDraggedOut = mMagnetizedObject != null
                    && mMagnetizedObject.getUnderlyingObject().equals(bv);
@@ -2759,7 +2757,7 @@ public class BubbleStackView extends FrameLayout
        for (int i = 0; i < bubbleCount; i++) {
            BadgedImageView bv = (BadgedImageView) mBubbleContainer.getChildAt(i);
            bv.setZ(i < NUM_VISIBLE_WHEN_RESTING
                    ? (mMaxBubbles * mBubbleElevation) - i
                    ? (mPositioner.getMaxBubbles() * mBubbleElevation) - i
                    : 0f);
        }
    }
Loading