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

Commit 725aed7a authored by András Kurucz's avatar András Kurucz Committed by Android (Google) Code Review
Browse files

Merge "[Flexiglass] Position NotificationShelf by the placeholders" into main

parents 9e4984c7 90285d3d
Loading
Loading
Loading
Loading
+22 −3
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.SystemBarUtils;
import com.android.systemui.animation.ShadeInterpolation;
import com.android.systemui.res.R;
import com.android.systemui.scene.shared.flag.SceneContainerFlag;
import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
import com.android.systemui.statusbar.notification.ColorUpdateLogger;
import com.android.systemui.statusbar.notification.NotificationUtils;
@@ -93,6 +94,7 @@ public class NotificationShelf extends ActivatableNotificationView {
    private float mCornerAnimationDistance;
    private float mActualWidth = -1;
    private int mMaxIconsOnLockscreen;
    private int mNotificationScrimPadding;
    private boolean mCanModifyColorOfNotifications;
    private boolean mCanInteract;
    private NotificationStackScrollLayout mHostLayout;
@@ -136,6 +138,7 @@ public class NotificationShelf extends ActivatableNotificationView {
        mStatusBarHeight = SystemBarUtils.getStatusBarHeight(mContext);
        mPaddingBetweenElements = res.getDimensionPixelSize(R.dimen.notification_divider_height);
        mMaxIconsOnLockscreen = res.getInteger(R.integer.max_notif_icons_on_lockscreen);
        mNotificationScrimPadding = res.getDimensionPixelSize(R.dimen.notification_side_paddings);

        ViewGroup.LayoutParams layoutParams = getLayoutParams();
        final int newShelfHeight = res.getDimensionPixelOffset(R.dimen.notification_shelf_height);
@@ -261,15 +264,31 @@ public class NotificationShelf extends ActivatableNotificationView {
            viewState.hasItemsInStableShelf = false;
        }

        final float stackEnd = ambientState.getStackY() + ambientState.getStackHeight();
        final float stackBottom = SceneContainerFlag.isEnabled()
                ? getStackBottom(ambientState)
                : ambientState.getStackY() + ambientState.getStackHeight();

        if (viewState.hidden) {
            // if the shelf is hidden, position it at the end of the stack (plus the clip
            // padding), such that when it appears animated, it will smoothly move in from the
            // bottom, without jump cutting any notifications
            viewState.setYTranslation(stackEnd + mPaddingBetweenElements);
            viewState.setYTranslation(stackBottom + mPaddingBetweenElements);
        } else {
            viewState.setYTranslation(stackEnd - viewState.height);
            viewState.setYTranslation(stackBottom - viewState.height);
        }
    }

    /**
     * bottom-most position, where we can draw the stack
     */
    private float getStackBottom(AmbientState ambientState) {
        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return 0f;
        float stackBottom = ambientState.getStackCutoff() - mNotificationScrimPadding;
        if (ambientState.isExpansionChanging()) {
            stackBottom = MathUtils.lerp(stackBottom * StackScrollAlgorithm.START_FRACTION,
                    stackBottom, ambientState.getExpansionFraction());
        }
        return stackBottom;
    }

    private int getSpeedBumpIndex() {
+17 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import com.android.systemui.Dumpable;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.res.R;
import com.android.systemui.scene.shared.flag.SceneContainerFlag;
import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StatusBarState;
@@ -63,6 +64,7 @@ public class AmbientState implements Dumpable {
     *  Used to read bouncer states.
     */
    private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
    private float mStackCutoff;
    private int mScrollY;
    private float mOverScrollTopAmount;
    private float mOverScrollBottomAmount;
@@ -346,6 +348,21 @@ public class AmbientState implements Dumpable {
        return mZDistanceBetweenElements;
    }

    /**
     * Y coordinate in view pixels above which the bottom of the notification stack / shelf / footer
     * must be.
     */
    public float getStackCutoff() {
        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return 0f;
        return mStackCutoff;
    }

    /** @see #getStackCutoff() */
    public void setStackCutoff(float stackCutoff) {
        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
        this.mStackCutoff = stackCutoff;
    }

    public int getScrollY() {
        return mScrollY;
    }
+2 −2
Original line number Diff line number Diff line
@@ -837,7 +837,7 @@ public class NotificationStackScrollLayout
            y = (int) mScrollViewFields.getStackTop();
            drawDebugInfo(canvas, y, Color.RED, /* label= */ "getStackTop() = " + y);

            y = (int) mScrollViewFields.getStackCutoff();
            y = (int) mAmbientState.getStackCutoff();
            drawDebugInfo(canvas, y, Color.MAGENTA, /* label= */ "getStackCutoff() = " + y);

            y = (int) mScrollViewFields.getHeadsUpTop();
@@ -1221,7 +1221,7 @@ public class NotificationStackScrollLayout

    @Override
    public void setStackCutoff(float stackCutoff) {
        mScrollViewFields.setStackCutoff(stackCutoff);
        mAmbientState.setStackCutoff(stackCutoff);
    }

    @Override
+0 −6
Original line number Diff line number Diff line
@@ -34,11 +34,6 @@ class ScrollViewFields {
    var scrimClippingShape: ShadeScrimShape? = null
    /** Y coordinate in view pixels of the top of the notification stack */
    var stackTop: Float = 0f
    /**
     * Y coordinate in view pixels above which the bottom of the notification stack / shelf / footer
     * must be.
     */
    var stackCutoff: Float = 0f
    /** Y coordinate in view pixels of the top of the HUN */
    var headsUpTop: Float = 0f
    /** Whether the notifications are scrolled all the way to the top (i.e. when freshly opened) */
@@ -82,7 +77,6 @@ class ScrollViewFields {
        pw.printSection("StackViewStates") {
            pw.println("scrimClippingShape", scrimClippingShape)
            pw.println("stackTop", stackTop)
            pw.println("stackCutoff", stackCutoff)
            pw.println("headsUpTop", headsUpTop)
            pw.println("isScrolledToTop", isScrolledToTop)
        }
+244 −6
Original line number Diff line number Diff line
@@ -10,6 +10,8 @@ import androidx.test.filters.SmallTest
import com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.ShadeInterpolation
import com.android.systemui.flags.DisableSceneContainer
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.res.R
@@ -30,8 +32,8 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.mock
import org.mockito.MockitoAnnotations
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations

/** Tests for {@link NotificationShelf}. */
@SmallTest
@@ -332,6 +334,144 @@ open class NotificationShelfTest : SysuiTestCase() {
    }

    @Test
    fun updateState_lastViewAlmostBelowShelf_completelyInShelf() {
        val viewStart = 0f
        val shelfClipStart = 0.001f

        val expandableView = mock(ExpandableView::class.java)
        whenever(expandableView.shelfIcon).thenReturn(mock(StatusBarIconView::class.java))
        whenever(expandableView.translationY).thenReturn(viewStart)
        whenever(expandableView.actualHeight).thenReturn(20)

        whenever(expandableView.minHeight).thenReturn(20)
        whenever(expandableView.shelfTransformationTarget).thenReturn(null) // use translationY
        whenever(expandableView.isInShelf).thenReturn(true)

        whenever(ambientState.isOnKeyguard).thenReturn(true)
        whenever(ambientState.isExpansionChanging).thenReturn(false)
        whenever(ambientState.isShadeExpanded).thenReturn(true)

        val amountInShelf =
            shelf.getAmountInShelf(
                /* i= */ 0,
                /* view= */ expandableView,
                /* scrollingFast= */ false,
                /* expandingAnimated= */ false,
                /* isLastChild= */ true,
                shelfClipStart
            )
        assertEquals(1f, amountInShelf)
    }

    @Test
    @EnableSceneContainer
    fun updateState_withViewInShelf_showShelf() {
        // GIVEN a view is scrolled into the shelf
        val stackCutoff = 200f
        val scrimPadding =
            context.resources.getDimensionPixelSize(R.dimen.notification_side_paddings)
        val shelfTop = stackCutoff - scrimPadding - shelf.height
        val stackScrollAlgorithmState = StackScrollAlgorithmState()
        val viewInShelf = mock(ExpandableView::class.java)

        whenever(ambientState.stackCutoff).thenReturn(stackCutoff)
        whenever(ambientState.isShadeExpanded).thenReturn(true)
        whenever(ambientState.lastVisibleBackgroundChild).thenReturn(viewInShelf)
        whenever(viewInShelf.viewState).thenReturn(ExpandableViewState())
        whenever(viewInShelf.shelfIcon).thenReturn(mock(StatusBarIconView::class.java))
        whenever(viewInShelf.translationY).thenReturn(shelfTop)
        whenever(viewInShelf.actualHeight).thenReturn(10)
        whenever(viewInShelf.isInShelf).thenReturn(true)
        whenever(viewInShelf.minHeight).thenReturn(10)
        whenever(viewInShelf.shelfTransformationTarget).thenReturn(null) // use translationY
        whenever(viewInShelf.isInShelf).thenReturn(true)

        stackScrollAlgorithmState.visibleChildren.add(viewInShelf)
        stackScrollAlgorithmState.firstViewInShelf = viewInShelf

        // WHEN Shelf's ViewState is updated
        shelf.updateState(stackScrollAlgorithmState, ambientState)

        // THEN the shelf is visible, and positioned correctly
        val shelfState = shelf.viewState as NotificationShelf.ShelfState
        assertEquals(false, shelfState.hidden)
        assertEquals(shelf.height, shelfState.height)
        assertEquals(shelfTop, shelfState.yTranslation)
    }

    @Test
    @EnableSceneContainer
    fun updateState_withViewInShelfDuringExpansion_showShelf() {
        // GIVEN a view is scrolled into the shelf
        val stackCutoff = 200f
        val scrimPadding =
            context.resources.getDimensionPixelSize(R.dimen.notification_side_paddings)
        val stackBottom = stackCutoff - scrimPadding
        val shelfTop = stackBottom - shelf.height
        val stackScrollAlgorithmState = StackScrollAlgorithmState()
        val viewInShelf = mock(ExpandableView::class.java)

        // AND a shade expansion is in progress
        val shadeExpansionFraction = 0.5f

        whenever(ambientState.stackCutoff).thenReturn(stackCutoff)
        whenever(ambientState.isShadeExpanded).thenReturn(true)
        whenever(ambientState.lastVisibleBackgroundChild).thenReturn(viewInShelf)
        whenever(ambientState.isExpansionChanging).thenReturn(true)
        whenever(ambientState.expansionFraction).thenReturn(shadeExpansionFraction)
        whenever(viewInShelf.viewState).thenReturn(ExpandableViewState())
        whenever(viewInShelf.shelfIcon).thenReturn(mock(StatusBarIconView::class.java))
        whenever(viewInShelf.translationY).thenReturn(shelfTop)
        whenever(viewInShelf.actualHeight).thenReturn(10)
        whenever(viewInShelf.isInShelf).thenReturn(true)
        whenever(viewInShelf.minHeight).thenReturn(10)
        whenever(viewInShelf.shelfTransformationTarget).thenReturn(null) // use translationY
        whenever(viewInShelf.isInShelf).thenReturn(true)

        stackScrollAlgorithmState.visibleChildren.add(viewInShelf)
        stackScrollAlgorithmState.firstViewInShelf = viewInShelf

        // WHEN Shelf's ViewState is updated
        shelf.updateState(stackScrollAlgorithmState, ambientState)

        // THEN the shelf is visible
        val shelfState = shelf.viewState as NotificationShelf.ShelfState
        assertEquals(false, shelfState.hidden)
        assertEquals(shelf.height, shelfState.height)
        // AND its translation is scaled by the shade expansion
        assertEquals((stackBottom * 0.75f) - shelf.height, shelfState.yTranslation)
    }

    @Test
    @EnableSceneContainer
    fun updateState_withNullLastVisibleBackgroundChild_hideShelf_withSceneContainer() {
        // GIVEN
        val stackCutoff = 200f
        val scrimPadding =
            context.resources.getDimensionPixelSize(R.dimen.notification_side_paddings)
        val paddingBetweenElements =
            context.resources.getDimensionPixelSize(R.dimen.notification_divider_height)
        whenever(ambientState.stackCutoff).thenReturn(stackCutoff)
        whenever(ambientState.isShadeExpanded).thenReturn(true)
        val lastVisibleBackgroundChild = mock<ExpandableView>()
        val expandableViewState = ExpandableViewState()
        whenever(lastVisibleBackgroundChild.viewState).thenReturn(expandableViewState)
        val stackScrollAlgorithmState = StackScrollAlgorithmState()
        stackScrollAlgorithmState.firstViewInShelf = mock()

        whenever(ambientState.lastVisibleBackgroundChild).thenReturn(null)

        // WHEN
        shelf.updateState(stackScrollAlgorithmState, ambientState)

        // THEN
        val shelfState = shelf.viewState as NotificationShelf.ShelfState
        assertEquals(true, shelfState.hidden)
        assertEquals(stackCutoff - scrimPadding + paddingBetweenElements, shelfState.yTranslation)
    }

    @Test
    @DisableSceneContainer
    fun updateState_withNullLastVisibleBackgroundChild_hideShelf() {
        // GIVEN
        whenever(ambientState.stackY).thenReturn(100f)
@@ -358,6 +498,35 @@ open class NotificationShelfTest : SysuiTestCase() {
    }

    @Test
    @EnableSceneContainer
    fun updateState_withNullFirstViewInShelf_hideShelf_withSceneContainer() {
        // GIVEN
        val stackCutoff = 200f
        val scrimPadding =
            context.resources.getDimensionPixelSize(R.dimen.notification_side_paddings)
        val paddingBetweenElements =
            context.resources.getDimensionPixelSize(R.dimen.notification_divider_height)
        whenever(ambientState.stackCutoff).thenReturn(stackCutoff)
        whenever(ambientState.isShadeExpanded).thenReturn(true)
        val lastVisibleBackgroundChild = mock<ExpandableView>()
        val expandableViewState = ExpandableViewState()
        whenever(lastVisibleBackgroundChild.viewState).thenReturn(expandableViewState)
        whenever(ambientState.lastVisibleBackgroundChild).thenReturn(lastVisibleBackgroundChild)
        val stackScrollAlgorithmState = StackScrollAlgorithmState()

        stackScrollAlgorithmState.firstViewInShelf = null

        // WHEN
        shelf.updateState(stackScrollAlgorithmState, ambientState)

        // THEN
        val shelfState = shelf.viewState as NotificationShelf.ShelfState
        assertEquals(true, shelfState.hidden)
        assertEquals(stackCutoff - scrimPadding + paddingBetweenElements, shelfState.yTranslation)
    }

    @Test
    @DisableSceneContainer
    fun updateState_withNullFirstViewInShelf_hideShelf() {
        // GIVEN
        whenever(ambientState.stackY).thenReturn(100f)
@@ -384,6 +553,35 @@ open class NotificationShelfTest : SysuiTestCase() {
    }

    @Test
    @EnableSceneContainer
    fun updateState_withCollapsedShade_hideShelf_withSceneContainer() {
        // GIVEN
        val stackCutoff = 200f
        val scrimPadding =
            context.resources.getDimensionPixelSize(R.dimen.notification_side_paddings)
        val paddingBetweenElements =
            context.resources.getDimensionPixelSize(R.dimen.notification_divider_height)
        whenever(ambientState.stackCutoff).thenReturn(stackCutoff)
        val lastVisibleBackgroundChild = mock<ExpandableView>()
        val expandableViewState = ExpandableViewState()
        whenever(lastVisibleBackgroundChild.viewState).thenReturn(expandableViewState)
        whenever(ambientState.lastVisibleBackgroundChild).thenReturn(lastVisibleBackgroundChild)
        val stackScrollAlgorithmState = StackScrollAlgorithmState()
        stackScrollAlgorithmState.firstViewInShelf = mock()

        whenever(ambientState.isShadeExpanded).thenReturn(false)

        // WHEN
        shelf.updateState(stackScrollAlgorithmState, ambientState)

        // THEN
        val shelfState = shelf.viewState as NotificationShelf.ShelfState
        assertEquals(true, shelfState.hidden)
        assertEquals(stackCutoff - scrimPadding + paddingBetweenElements, shelfState.yTranslation)
    }

    @Test
    @DisableSceneContainer
    fun updateState_withCollapsedShade_hideShelf() {
        // GIVEN
        whenever(ambientState.stackY).thenReturn(100f)
@@ -410,6 +608,49 @@ open class NotificationShelfTest : SysuiTestCase() {
    }

    @Test
    @EnableSceneContainer
    fun updateState_withHiddenSectionBeforeShelf_hideShelf_withSceneContianer() {
        // GIVEN
        val stackCutoff = 200f
        whenever(ambientState.stackCutoff).thenReturn(stackCutoff)
        val scrimPadding =
            context.resources.getDimensionPixelSize(R.dimen.notification_side_paddings)
        val paddingBetweenElements =
            context.resources.getDimensionPixelSize(R.dimen.notification_divider_height)
        whenever(ambientState.isShadeExpanded).thenReturn(true)
        val lastVisibleBackgroundChild = mock<ExpandableView>()
        val expandableViewState = ExpandableViewState()
        whenever(lastVisibleBackgroundChild.viewState).thenReturn(expandableViewState)
        val stackScrollAlgorithmState = StackScrollAlgorithmState()
        whenever(ambientState.lastVisibleBackgroundChild).thenReturn(lastVisibleBackgroundChild)

        val ssaVisibleChild = mock<ExpandableView>()
        val ssaVisibleChildState = ExpandableViewState()
        ssaVisibleChildState.hidden = true
        whenever(ssaVisibleChild.viewState).thenReturn(ssaVisibleChildState)

        val ssaVisibleChild1 = mock<ExpandableView>()
        val ssaVisibleChildState1 = ExpandableViewState()
        ssaVisibleChildState1.hidden = true
        whenever(ssaVisibleChild1.viewState).thenReturn(ssaVisibleChildState1)

        stackScrollAlgorithmState.visibleChildren.add(ssaVisibleChild)
        stackScrollAlgorithmState.visibleChildren.add(ssaVisibleChild1)
        whenever(ambientState.isExpansionChanging).thenReturn(true)
        whenever(ambientState.expansionFraction).thenReturn(1f)
        stackScrollAlgorithmState.firstViewInShelf = ssaVisibleChild1

        // WHEN
        shelf.updateState(stackScrollAlgorithmState, ambientState)

        // THEN
        val shelfState = shelf.viewState as NotificationShelf.ShelfState
        assertEquals(true, shelfState.hidden)
        assertEquals(stackCutoff - scrimPadding + paddingBetweenElements, shelfState.yTranslation)
    }

    @Test
    @DisableSceneContainer
    fun updateState_withHiddenSectionBeforeShelf_hideShelf() {
        // GIVEN
        whenever(ambientState.stackY).thenReturn(100f)
@@ -461,12 +702,9 @@ open class NotificationShelfTest : SysuiTestCase() {
        expectedAlpha: Float
    ) {
        val sbnMock: StatusBarNotification = mock()
        val mockEntry = mock<NotificationEntry>().apply {
            whenever(this.sbn).thenReturn(sbnMock)
        }
        val mockEntry = mock<NotificationEntry>().apply { whenever(this.sbn).thenReturn(sbnMock) }
        val row = ExpandableNotificationRow(mContext, null, mockEntry)
        whenever(ambientState.lastVisibleBackgroundChild)
            .thenReturn(row)
        whenever(ambientState.lastVisibleBackgroundChild).thenReturn(row)
        whenever(ambientState.isExpansionChanging).thenReturn(true)
        whenever(ambientState.expansionFraction).thenReturn(expansionFraction)
        whenever(hostLayoutController.speedBumpIndex).thenReturn(0)