Loading packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +22 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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() { Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java +17 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; } Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +2 −2 Original line number Diff line number Diff line Loading @@ -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(); Loading Loading @@ -1221,7 +1221,7 @@ public class NotificationStackScrollLayout @Override public void setStackCutoff(float stackCutoff) { mScrollViewFields.setStackCutoff(stackCutoff); mAmbientState.setStackCutoff(stackCutoff); } @Override Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt +0 −6 Original line number Diff line number Diff line Loading @@ -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) */ Loading Loading @@ -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) } Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt +244 −6 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading Loading @@ -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) Loading @@ -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) Loading @@ -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) Loading @@ -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) Loading Loading @@ -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) Loading Loading
packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +22 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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() { Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java +17 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; } Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +2 −2 Original line number Diff line number Diff line Loading @@ -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(); Loading Loading @@ -1221,7 +1221,7 @@ public class NotificationStackScrollLayout @Override public void setStackCutoff(float stackCutoff) { mScrollViewFields.setStackCutoff(stackCutoff); mAmbientState.setStackCutoff(stackCutoff); } @Override Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt +0 −6 Original line number Diff line number Diff line Loading @@ -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) */ Loading Loading @@ -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) } Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt +244 −6 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading Loading @@ -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) Loading @@ -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) Loading @@ -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) Loading @@ -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) Loading Loading @@ -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) Loading