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

Commit 9be72792 authored by Julia Reynolds's avatar Julia Reynolds Committed by Automerger Merge Worker
Browse files

Merge "Increase vertical overlap between notification shelf and lock icon"...

Merge "Increase vertical overlap between notification shelf and lock icon" into tm-dev am: d2576a75

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/18443476



Change-Id: I053b97f88fedc98ade4cd6959d77fad9560aa4af
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 9e43e56e d2576a75
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -386,7 +386,7 @@

    <dimen name="split_shade_notifications_scrim_margin_bottom">0dp</dimen>

    <dimen name="shelf_and_lock_icon_overlap">5dp</dimen>
    <dimen name="shelf_and_lock_icon_overlap">@dimen/notification_shelf_height</dimen>

    <dimen name="notification_panel_margin_horizontal">0dp</dimen>

+88 −20
Original line number Diff line number Diff line
@@ -39,7 +39,11 @@ private const val TAG = "NotifStackSizeCalc"
private val DEBUG = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG)
private val SPEW = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.VERBOSE)

/** Calculates number of notifications to display and the height of the notification stack. */
/**
 * Calculates number of notifications to display and the height of the notification stack.
 * "Notifications" refers to any ExpandableView that we show on lockscreen, which can include the
 * media player.
 */
@SysUISingleton
class NotificationStackSizeCalculator
@Inject
@@ -65,21 +69,60 @@ constructor(
    }

    /**
     * Given the [totalAvailableSpace] constraint, calculates how many notification to show.
     *
     * This number is only valid in keyguard.
     * Returns whether notifications and (shelf if visible) can fit in total space available.
     * [spaceForShelf] is extra vertical space allowed for the shelf to overlap the lock icon.
     */
    private fun canStackFitInSpace(
        stackHeight: StackHeight,
        spaceForNotifications: Float,
        spaceForShelf: Float,
    ): Boolean {

        val (notificationsHeight, shelfHeightWithSpaceBefore) = stackHeight
        var canFit: Boolean

        if (shelfHeightWithSpaceBefore == 0f) {
            canFit = notificationsHeight <= spaceForNotifications
            log {
                "canStackFitInSpace[$canFit] = notificationsHeight[$notificationsHeight]" +
                    " <= spaceForNotifications[$spaceForNotifications]"
            }
        } else {
            canFit =
                (notificationsHeight + shelfHeightWithSpaceBefore) <=
                    (spaceForNotifications + spaceForShelf)
            log {
                "canStackFitInSpace[$canFit] = (notificationsHeight[$notificationsHeight]" +
                    " + shelfHeightWithSpaceBefore[$shelfHeightWithSpaceBefore])" +
                    " <= (spaceForNotifications[$spaceForNotifications] " +
                    " + spaceForShelf[$spaceForShelf])"
            }
        }
        return canFit
    }

    /**
     * Given the [spaceForNotifications] and [spaceForShelf] constraints, calculate how many
     * notifications to show. This number is only valid in keyguard.
     *
     * @param totalAvailableSpace space for notifications. This includes the space for the shelf.
     */
    fun computeMaxKeyguardNotifications(
        stack: NotificationStackScrollLayout,
        totalAvailableSpace: Float,
        spaceForNotifications: Float,
        spaceForShelf: Float,
        shelfIntrinsicHeight: Float
    ): Int {
        log { "\n" }
        val stackHeightSequence = computeHeightPerNotificationLimit(stack, shelfIntrinsicHeight)

        var maxNotifications =
            stackHeightSequence.lastIndexWhile { stackHeight -> stackHeight <= totalAvailableSpace }
            stackHeightSequence.lastIndexWhile { heightResult ->
                canStackFitInSpace(
                    heightResult,
                    spaceForNotifications = spaceForNotifications,
                    spaceForShelf = spaceForShelf)
            }

        if (onLockscreen()) {
            maxNotifications = min(maxKeyguardNotifications, maxNotifications)
@@ -90,7 +133,8 @@ constructor(
        log {
            val sequence = if (SPEW) " stackHeightSequence=${stackHeightSequence.toList()}" else ""
            "computeMaxKeyguardNotifications(" +
                "availableSpace=$totalAvailableSpace" +
                " spaceForNotifications=$spaceForNotifications" +
                " spaceForShelf=$spaceForShelf" +
                " shelfHeight=$shelfIntrinsicHeight) -> $maxNotifications$sequence"
        }
        return maxNotifications
@@ -112,33 +156,51 @@ constructor(
        maxNotifications: Int,
        shelfIntrinsicHeight: Float
    ): Float {
        log { "\n" }
        val heightPerMaxNotifications =
            computeHeightPerNotificationLimit(stack, shelfIntrinsicHeight)
        val height =

        val (notificationsHeight, shelfHeightWithSpaceBefore) =
            heightPerMaxNotifications.elementAtOrElse(maxNotifications) {
                heightPerMaxNotifications.last() // Height with all notifications visible.
            }
        log { "computeHeight(maxNotifications=$maxNotifications) -> $height" }
        return height
        log {
            "computeHeight(maxNotifications=$maxNotifications," +
                "shelfIntrinsicHeight=$shelfIntrinsicHeight) -> " +
                "${notificationsHeight + shelfHeightWithSpaceBefore}" +
                " = ($notificationsHeight + $shelfHeightWithSpaceBefore)"
        }
        return notificationsHeight + shelfHeightWithSpaceBefore
    }

    /** The ith result in the sequence is the height with ith max notifications. */
    private data class StackHeight(
        // Float height with ith max notifications (not including shelf)
        val notificationsHeight: Float,

        // Float height of shelf (0 if shelf is not showing), and space before the shelf that
        // changes during the lockscreen <=> full shade transition.
        val shelfHeightWithSpaceBefore: Float
    )

    private fun computeHeightPerNotificationLimit(
        stack: NotificationStackScrollLayout,
        shelfIntrinsicHeight: Float
    ): Sequence<Float> = sequence {
        shelfHeight: Float
    ): Sequence<StackHeight> = sequence {
        log { "computeHeightPerNotificationLimit" }

        val children = stack.showableChildren().toList()
        var height = 0f
        var notifications = 0f
        var previous: ExpandableView? = null
        val onLockscreen = onLockscreen()

        yield(dividerHeight + shelfIntrinsicHeight) // Only shelf.
        // Only shelf. This should never happen, since we allow 1 view minimum (EmptyViewState).
        yield(StackHeight(notificationsHeight = 0f, shelfHeightWithSpaceBefore = shelfHeight))

        children.forEachIndexed { i, currentNotification ->
            height += spaceNeeded(currentNotification, i, previous, stack, onLockscreen)
            notifications += spaceNeeded(currentNotification, i, previous, stack, onLockscreen)
            previous = currentNotification

            val shelfHeight =
            val shelfWithSpaceBefore =
                if (i == children.lastIndex) {
                    0f // No shelf needed.
                } else {
@@ -149,10 +211,16 @@ constructor(
                            previous = currentNotification,
                            current = children[firstViewInShelfIndex],
                            currentIndex = firstViewInShelfIndex)
                    spaceBeforeShelf + shelfIntrinsicHeight
                    spaceBeforeShelf + shelfHeight
                }

            yield(height + shelfHeight)
            log {
                "i=$i notificationsHeight=$notifications " +
                    "shelfHeightWithSpaceBefore=$shelfWithSpaceBefore"
            }
            yield(
                StackHeight(
                    notificationsHeight = notifications,
                    shelfHeightWithSpaceBefore = shelfWithSpaceBefore))
        }
    }

+59 −36
Original line number Diff line number Diff line
@@ -1520,50 +1520,77 @@ public class NotificationPanelViewController extends PanelViewController {
        return (mQs != null ? mQs.getHeader().getHeight() : 0) + mQsPeekHeight;
    }

    /**
     * @return Space available to show notifications on lockscreen.
     */
    @VisibleForTesting
    float getSpaceForLockscreenNotifications() {
        float staticTopPadding = mClockPositionAlgorithm.getLockscreenMinStackScrollerPadding()
                // getMinStackScrollerPadding is from the top of the screen,
                // but we need it from the top of the NSSL.
                - mNotificationStackScrollLayoutController.getTop();

        // Space between bottom of notifications and top of lock icon or udfps background.
        float lockIconPadding = mLockIconViewController.getTop();
        if (mLockIconViewController.getTop() != 0) {
    /** Returns space between top of lock icon and bottom of NotificationStackScrollLayout. */
    private float getLockIconPadding() {
        float lockIconPadding = 0f;
        if (mLockIconViewController.getTop() != 0f) {
            lockIconPadding = mNotificationStackScrollLayoutController.getBottom()
                    - mLockIconViewController.getTop()
                    - mShelfAndLockIconOverlap;
                    - mLockIconViewController.getTop();
        }
        return lockIconPadding;
    }

    /** Returns space available to show notifications on lockscreen. */
    @VisibleForTesting
    float getVerticalSpaceForLockscreenNotifications() {
        final float lockIconPadding = getLockIconPadding();

        float bottomPadding = Math.max(lockIconPadding,
                Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding));

        mKeyguardNotificationBottomPadding = bottomPadding;

        float staticTopPadding = mClockPositionAlgorithm.getLockscreenMinStackScrollerPadding()
                // getMinStackScrollerPadding is from the top of the screen,
                // but we need it from the top of the NSSL.
                - mNotificationStackScrollLayoutController.getTop();
        mKeyguardNotificationTopPadding = staticTopPadding;

        // To debug the available space, enable debug lines in this class. If you change how the
        // available space is calculated, please also update those lines.
        float availableSpace =
        final float verticalSpace =
                mNotificationStackScrollLayoutController.getHeight()
                        - staticTopPadding
                        - bottomPadding;

        if (SPEW_LOGCAT) {
            Log.d(TAG, "getSpaceForLockscreenNotifications()"
                    + " availableSpace=" + availableSpace
                    + " NSSL.height=" + mNotificationStackScrollLayoutController.getHeight()
                    + " NSSL.top=" + mNotificationStackScrollLayoutController.getTop()
                    + " staticTopPadding=" + staticTopPadding
                    + " bottomPadding=" + bottomPadding
                    + " lockIconPadding=" + lockIconPadding
                    + " mIndicationBottomPadding=" + mIndicationBottomPadding
                    + " mAmbientIndicationBottomPadding=" + mAmbientIndicationBottomPadding
            Log.i(TAG, "\n");
            Log.i(TAG, "staticTopPadding[" + staticTopPadding
                    + "] = Clock.padding["
                    + mClockPositionAlgorithm.getLockscreenMinStackScrollerPadding()
                    + "] - NSSLC.top[" + mNotificationStackScrollLayoutController.getTop()
                    + "]"
            );
            Log.i(TAG, "bottomPadding[" + bottomPadding
                    + "] = max(ambientIndicationBottomPadding[" + mAmbientIndicationBottomPadding
                    + "], mIndicationBottomPadding[" + mIndicationBottomPadding
                    + "], lockIconPadding[" + lockIconPadding
                    + "])"
            );
            Log.i(TAG, "verticalSpaceForNotifications[" + verticalSpace
                    + "] = NSSL.height[" + mNotificationStackScrollLayoutController.getHeight()
                    + "] - staticTopPadding[" + staticTopPadding
                    + "] - bottomPadding[" + bottomPadding
                    + "]"
            );
        }
        return availableSpace;
        return verticalSpace;
    }

    /** Returns extra space available to show the shelf on lockscreen */
    @VisibleForTesting
    float getVerticalSpaceForLockscreenShelf() {
        final float lockIconPadding = getLockIconPadding();

        final float noShelfOverlapBottomPadding =
                Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding);

        final float extraSpaceForShelf = lockIconPadding - noShelfOverlapBottomPadding;

        if (extraSpaceForShelf > 0f) {
            return Math.min(mNotificationShelfController.getIntrinsicHeight(),
                    extraSpaceForShelf);
        }
        return 0f;
    }

    /**
@@ -1579,16 +1606,12 @@ public class NotificationPanelViewController extends PanelViewController {
            }
            return mMaxAllowedKeyguardNotifications;
        }

        final float shelfIntrinsicHeight =
                mNotificationShelfController.getVisibility() == View.GONE
                        ? 0
                        : mNotificationShelfController.getIntrinsicHeight();

        return mNotificationStackSizeCalculator.computeMaxKeyguardNotifications(
                mNotificationStackScrollLayoutController.getView(),
                getSpaceForLockscreenNotifications(),
                shelfIntrinsicHeight);
                getVerticalSpaceForLockscreenNotifications(),
                getVerticalSpaceForLockscreenShelf(),
                mNotificationShelfController.getIntrinsicHeight()
        );
    }

    private void updateClock() {
@@ -3812,7 +3835,7 @@ public class NotificationPanelViewController extends PanelViewController {
    public void setAmbientIndicationTop(int ambientIndicationTop, boolean ambientTextVisible) {
        int ambientIndicationBottomPadding = 0;
        if (ambientTextVisible) {
            int stackBottom = mNotificationStackScrollLayoutController.getView().getBottom();
            int stackBottom = mNotificationStackScrollLayoutController.getBottom();
            ambientIndicationBottomPadding = stackBottom - ambientIndicationTop;
        }
        if (mAmbientIndicationBottomPadding != ambientIndicationBottomPadding) {
+58 −30
Original line number Diff line number Diff line
@@ -46,7 +46,8 @@ import org.mockito.MockitoAnnotations
class NotificationStackSizeCalculatorTest : SysuiTestCase() {

    @Mock private lateinit var sysuiStatusBarStateController: SysuiStatusBarStateController
    @Mock private lateinit var lockscreenShadeTransitionController: LockscreenShadeTransitionController
    @Mock
    private lateinit var lockscreenShadeTransitionController: LockscreenShadeTransitionController
    @Mock private lateinit var stackLayout: NotificationStackScrollLayout

    private val testableResources = mContext.orCreateTestableResources
@@ -74,7 +75,8 @@ class NotificationStackSizeCalculatorTest : SysuiTestCase() {
        val rows = listOf(createMockRow(height = rowHeight))

        val maxNotifications =
            computeMaxKeyguardNotifications(rows, availableSpace = 0f, shelfHeight = 0f)
            computeMaxKeyguardNotifications(
                rows, spaceForNotifications = 0f, spaceForShelf = 0f, shelfHeight = 0f)

        assertThat(maxNotifications).isEqualTo(0)
    }
@@ -84,7 +86,12 @@ class NotificationStackSizeCalculatorTest : SysuiTestCase() {
        val numberOfRows = 30
        val rows = createLockscreenRows(numberOfRows)

        val maxNotifications = computeMaxKeyguardNotifications(rows, Float.MAX_VALUE)
        val maxNotifications =
            computeMaxKeyguardNotifications(
                rows,
                spaceForNotifications = Float.MAX_VALUE,
                spaceForShelf = Float.MAX_VALUE,
                shelfHeight)

        assertThat(maxNotifications).isEqualTo(numberOfRows)
    }
@@ -93,11 +100,12 @@ class NotificationStackSizeCalculatorTest : SysuiTestCase() {
    fun computeMaxKeyguardNotifications_spaceForOneAndShelf_returnsOne() {
        setGapHeight(gapHeight)
        val shelfHeight = rowHeight / 2 // Shelf absence won't leave room for another row.
        val availableSpace =
            listOf(rowHeight + dividerHeight, gapHeight + dividerHeight + shelfHeight).sum()
        val spaceForNotifications = rowHeight + dividerHeight
        val spaceForShelf = gapHeight + dividerHeight + shelfHeight
        val rows = listOf(createMockRow(rowHeight), createMockRow(rowHeight))

        val maxNotifications = computeMaxKeyguardNotifications(rows, availableSpace, shelfHeight)
        val maxNotifications =
            computeMaxKeyguardNotifications(rows, spaceForNotifications, spaceForShelf, shelfHeight)

        assertThat(maxNotifications).isEqualTo(1)
    }
@@ -106,16 +114,19 @@ class NotificationStackSizeCalculatorTest : SysuiTestCase() {
    fun computeMaxKeyguardNotifications_spaceForTwo_returnsTwo() {
        setGapHeight(gapHeight)
        val shelfHeight = shelfHeight + dividerHeight
        val availableSpace =
        val spaceForNotifications =
            listOf(
                    rowHeight + dividerHeight,
                    gapHeight + rowHeight + dividerHeight,
                    gapHeight + dividerHeight + shelfHeight)
                )
                .sum()
        val spaceForShelf = gapHeight + dividerHeight + shelfHeight
        val rows =
            listOf(createMockRow(rowHeight), createMockRow(rowHeight), createMockRow(rowHeight))

        val maxNotifications = computeMaxKeyguardNotifications(rows, availableSpace, shelfHeight)
        val maxNotifications =
            computeMaxKeyguardNotifications(
                rows, spaceForNotifications + 1, spaceForShelf, shelfHeight)

        assertThat(maxNotifications).isEqualTo(2)
    }
@@ -124,19 +135,25 @@ class NotificationStackSizeCalculatorTest : SysuiTestCase() {
    fun computeHeight_gapBeforeShelf_returnsSpaceUsed() {
        // Each row in separate section.
        setGapHeight(gapHeight)
        val spaceUsed =
            listOf(rowHeight,

        val spaceForNotifications =
            listOf(
                    rowHeight,
                    dividerHeight + gapHeight + rowHeight,
                    dividerHeight + gapHeight + shelfHeight)
                )
                .sum()
        val availableSpace = spaceUsed + 1;

        val spaceForShelf = dividerHeight + gapHeight + shelfHeight
        val spaceUsed = spaceForNotifications + spaceForShelf
        val rows =
            listOf(createMockRow(rowHeight), createMockRow(rowHeight), createMockRow(rowHeight))

        val maxNotifications = computeMaxKeyguardNotifications(rows, availableSpace, shelfHeight)
        val maxNotifications =
            computeMaxKeyguardNotifications(rows, spaceForNotifications, spaceForShelf, shelfHeight)
        assertThat(maxNotifications).isEqualTo(2)

        val height = sizeCalculator.computeHeight(stackLayout, maxNotifications, this.shelfHeight)
        val height =
            sizeCalculator.computeHeight(stackLayout, maxNotifications, this.shelfHeight)
        assertThat(height).isEqualTo(spaceUsed)
    }

@@ -145,19 +162,19 @@ class NotificationStackSizeCalculatorTest : SysuiTestCase() {
        // Both rows are in the same section.
        setGapHeight(0f)

        val rowHeight = rowHeight
        val shelfHeight = shelfHeight
        val spaceUsed =
            listOf(rowHeight,
                    dividerHeight + shelfHeight)
                .sum()
        val availableSpace = spaceUsed + 1
        val spaceForNotifications = rowHeight
        val spaceForShelf = dividerHeight + shelfHeight
        val spaceUsed = spaceForNotifications + spaceForShelf
        val rows = listOf(createMockRow(rowHeight), createMockRow(rowHeight))

        val maxNotifications = computeMaxKeyguardNotifications(rows, availableSpace, shelfHeight)
        // test that we only use space required
        val maxNotifications =
            computeMaxKeyguardNotifications(
                rows, spaceForNotifications + 1, spaceForShelf, shelfHeight)
        assertThat(maxNotifications).isEqualTo(1)

        val height = sizeCalculator.computeHeight(stackLayout, maxNotifications, this.shelfHeight)
        val height =
            sizeCalculator.computeHeight(stackLayout, maxNotifications, this.shelfHeight)
        assertThat(height).isEqualTo(spaceUsed)
    }

@@ -191,8 +208,13 @@ class NotificationStackSizeCalculatorTest : SysuiTestCase() {
        whenever(expandableView.getMinHeight(any())).thenReturn(5)
        whenever(expandableView.intrinsicHeight).thenReturn(10)

        val space = sizeCalculator.spaceNeeded(expandableView, visibleIndex = 0,
                previousView = null, stack = stackLayout, onLockscreen = true)
        val space =
            sizeCalculator.spaceNeeded(
                expandableView,
                visibleIndex = 0,
                previousView = null,
                stack = stackLayout,
                onLockscreen = true)
        assertThat(space).isEqualTo(5)
    }

@@ -205,19 +227,25 @@ class NotificationStackSizeCalculatorTest : SysuiTestCase() {
        whenever(expandableView.getMinHeight(any())).thenReturn(5)
        whenever(expandableView.intrinsicHeight).thenReturn(10)

        val space = sizeCalculator.spaceNeeded(expandableView, visibleIndex = 0,
                previousView = null, stack = stackLayout, onLockscreen = false)
        val space =
            sizeCalculator.spaceNeeded(
                expandableView,
                visibleIndex = 0,
                previousView = null,
                stack = stackLayout,
                onLockscreen = false)
        assertThat(space).isEqualTo(10)
    }

    private fun computeMaxKeyguardNotifications(
        rows: List<ExpandableView>,
        availableSpace: Float,
        spaceForNotifications: Float,
        spaceForShelf: Float,
        shelfHeight: Float = this.shelfHeight
    ): Int {
        setupChildren(rows)
        return sizeCalculator.computeMaxKeyguardNotifications(
            stackLayout, availableSpace, shelfHeight)
            stackLayout, spaceForNotifications, spaceForShelf, shelfHeight)
    }

    private fun setupChildren(children: List<ExpandableView>) {
+93 −16

File changed.

Preview size limit exceeded, changes collapsed.