From a05b7e337cceceb7623f5c54eff4a0b74471e564 Mon Sep 17 00:00:00 2001 From: Marcello Galhardo Date: Fri, 12 Aug 2022 17:17:13 +0000 Subject: Fix "No Notification" text not gradually showing on LockScreen The problem and solution can be summarised in 3 aspects: - EmptyShadeView visibility was not synchronized with the parent container. To fix that, we will update the `EmptyShadeView` when the container is set to visible (see `NotificationStackScrollLayoutController#updateVisibility`). - EmptyShadeView visibility rule did not consider transitions when deciding to hide itself on keyguard screen. To fix that, we will compare in the current state is different from the outgoing state in addition to the outgoing state been `Keyguard` (see `NotificaitonStackScrollLayoutController#updateShowEmptyShadeView`). - The notification layout is visible while on keyguard when in split mode (large screen), different from the phone where a transition is executed. To fix that, we will manually animate the `EmptyShadeView` while in lock screen using `ShadeInterpolation.getAlphaContent` to reproduce the nice fade transition we have in phones (see `StackScrollAlgorithm#updateAlphaState`). Test: manual (tablet) - Turn on your device. - If you have notifications: - Expand your notifications. - Tap "Clear All" button. - Expand your notifications slowly. - Notice "No Notifications" text will gradually fade in with your movement. Test: manual (phone) - Behaviour did not change. Test: atest ~/tm-qpr-dev/frameworks/base/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt Fixes: 239903210 Change-Id: I25c0d3fdb484d27eb319e4e22e23facb32c6f6fa --- .../android/systemui/statusbar/EmptyShadeView.java | 3 + .../systemui/statusbar/NotificationShelf.java | 3 + .../row/ExpandableNotificationRow.java | 6 +- .../statusbar/notification/row/ExpandableView.java | 11 +- .../statusbar/notification/row/FooterView.java | 3 + .../stack/NotificationStackScrollLayout.java | 11 +- .../NotificationStackScrollLayoutController.java | 43 ++++-- .../notification/stack/StackScrollAlgorithm.java | 84 +++++++----- .../notification/stack/StackScrollAlgorithmTest.kt | 151 ++++++++++++++++++--- 9 files changed, 251 insertions(+), 64 deletions(-) (limited to 'packages/SystemUI') diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java index b9684fcb8a01..3d161d9bfa75 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java @@ -24,6 +24,8 @@ import android.util.AttributeSet; import android.view.View; import android.widget.TextView; +import androidx.annotation.NonNull; + import com.android.systemui.R; import com.android.systemui.statusbar.notification.row.StackScrollerDecorView; import com.android.systemui.statusbar.notification.stack.ExpandableViewState; @@ -73,6 +75,7 @@ public class EmptyShadeView extends StackScrollerDecorView { } @Override + @NonNull public ExpandableViewState createExpandableViewState() { return new EmptyShadeViewState(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index 221428747558..cea3debe6379 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -29,6 +29,8 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; +import androidx.annotation.NonNull; + import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.SystemBarUtils; import com.android.systemui.R; @@ -153,6 +155,7 @@ public class NotificationShelf extends ActivatableNotificationView implements } @Override + @NonNull public ExpandableViewState createExpandableViewState() { return new ShelfState(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 855390d75ff8..8574f872ad9c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -25,8 +25,6 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; -import android.annotation.NonNull; -import android.annotation.Nullable; import android.app.INotificationManager; import android.app.Notification; import android.app.NotificationChannel; @@ -68,6 +66,9 @@ import android.widget.Chronometer; import android.widget.FrameLayout; import android.widget.ImageView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; @@ -3247,6 +3248,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } @Override + @NonNull public ExpandableViewState createExpandableViewState() { return new NotificationViewState(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java index 8f73b802271d..1e09b8a37645 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java @@ -29,6 +29,7 @@ import android.view.ViewGroup; import android.view.ViewParent; import android.widget.FrameLayout; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.systemui.Dumpable; @@ -66,7 +67,7 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable { protected float mContentTransformationAmount; protected boolean mIsLastChild; protected int mContentShift; - private final ExpandableViewState mViewState; + @NonNull private final ExpandableViewState mViewState; private float mContentTranslation; protected boolean mLastInSection; protected boolean mFirstInSection; @@ -610,6 +611,7 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable { public void setActualHeightAnimating(boolean animating) {} + @NonNull protected ExpandableViewState createExpandableViewState() { return new ExpandableViewState(); } @@ -642,7 +644,12 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable { return mViewState; } - @Nullable public ExpandableViewState getViewState() { + /** + * Get the {@link ExpandableViewState} associated with the view. + * + * @return the ExpandableView's view state. + */ + @NonNull public ExpandableViewState getViewState() { return mViewState; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java index e43ecf70a308..49dc6550a51f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java @@ -23,6 +23,8 @@ import android.util.AttributeSet; import android.util.IndentingPrintWriter; import android.view.View; +import androidx.annotation.NonNull; + import com.android.systemui.R; import com.android.systemui.statusbar.notification.stack.ExpandableViewState; import com.android.systemui.statusbar.notification.stack.ViewState; @@ -142,6 +144,7 @@ public class FooterView extends StackScrollerDecorView { } @Override + @NonNull public ExpandableViewState createExpandableViewState() { return new FooterViewState(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index cc87499d39cb..1fb265fea0b1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -4460,8 +4460,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } private void updateVisibility() { - boolean shouldShow = !mAmbientState.isFullyHidden() || !onKeyguard(); - setVisibility(shouldShow ? View.VISIBLE : View.INVISIBLE); + mController.updateVisibility(!mAmbientState.isFullyHidden() || !onKeyguard()); } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) @@ -4526,17 +4525,21 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - void updateEmptyShadeView(boolean visible, boolean notifVisibleInShade) { + void updateEmptyShadeView(boolean visible, boolean areNotificationsHiddenInShade) { mEmptyShadeView.setVisible(visible, mIsExpanded && mAnimationsEnabled); int oldTextRes = mEmptyShadeView.getTextResource(); - int newTextRes = notifVisibleInShade + int newTextRes = areNotificationsHiddenInShade ? R.string.dnd_suppressing_shade_text : R.string.empty_shade_text; if (oldTextRes != newTextRes) { mEmptyShadeView.setText(newTextRes); } } + public boolean isEmptyShadeViewVisible() { + return mEmptyShadeView.isVisible(); + } + @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public void updateFooterView(boolean visible, boolean showDismissView, boolean showHistory) { if (mFooterView == null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index e6eceb555897..ec1e6207ef8f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -177,7 +177,6 @@ public class NotificationStackScrollLayoutController { private NotificationStackScrollLayout mView; private boolean mFadeNotificationsOnDismiss; private NotificationSwipeHelper mSwipeHelper; - private boolean mShowEmptyShadeView; @Nullable private Boolean mHistoryEnabled; private int mBarState; private HeadsUpAppearanceController mHeadsUpAppearanceController; @@ -1173,8 +1172,21 @@ public class NotificationStackScrollLayoutController { } /** - * Update whether we should show the empty shade view (no notifications in the shade). - * If so, send the update to our view. + * Set the visibility of the view, and propagate it to specific children. + * + * @param visible either the view is visible or not. + */ + public void updateVisibility(boolean visible) { + mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE); + + if (mView.getVisibility() == View.VISIBLE) { + // Synchronize EmptyShadeView visibility with the parent container. + updateShowEmptyShadeView(); + } + } + + /** + * Update whether we should show the empty shade view ("no notifications" in the shade). * * When in split mode, notifications are always visible regardless of the state of the * QuickSettings panel. That being the case, empty view is always shown if the other conditions @@ -1182,18 +1194,31 @@ public class NotificationStackScrollLayoutController { */ public void updateShowEmptyShadeView() { Trace.beginSection("NSSLC.updateShowEmptyShadeView"); - mShowEmptyShadeView = mStatusBarStateController.getCurrentOrUpcomingState() != KEYGUARD + + final boolean shouldShow = getVisibleNotificationCount() == 0 && !mView.isQsFullScreen() - && getVisibleNotificationCount() == 0; + // Hide empty shade view when in transition to Keyguard. + // That avoids "No Notifications" to blink when transitioning to AOD. + // For more details, see: b/228790482 + && !isInTransitionToKeyguard(); + + mView.updateEmptyShadeView(shouldShow, mZenModeController.areNotificationsHiddenInShade()); - mView.updateEmptyShadeView( - mShowEmptyShadeView, - mZenModeController.areNotificationsHiddenInShade()); Trace.endSection(); } + /** + * @return true if {@link StatusBarStateController} is in transition to the KEYGUARD + * and false otherwise. + */ + private boolean isInTransitionToKeyguard() { + final int currentState = mStatusBarStateController.getState(); + final int upcomingState = mStatusBarStateController.getCurrentOrUpcomingState(); + return (currentState != upcomingState && upcomingState == KEYGUARD); + } + public boolean isShowingEmptyShadeView() { - return mShowEmptyShadeView; + return mView.isEmptyShadeViewVisible(); } public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java index 6d513d0da5c1..353355bef7bb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java @@ -120,11 +120,64 @@ public class StackScrollAlgorithm { updateClipping(algorithmState, ambientState); updateSpeedBumpState(algorithmState, speedBumpIndex); updateShelfState(algorithmState, ambientState); + updateAlphaState(algorithmState, ambientState); getNotificationChildrenStates(algorithmState, ambientState); } + private void updateAlphaState(StackScrollAlgorithmState algorithmState, + AmbientState ambientState) { + for (ExpandableView view : algorithmState.visibleChildren) { + final ViewState viewState = view.getViewState(); + + final boolean isHunGoingToShade = ambientState.isShadeExpanded() + && view == ambientState.getTrackedHeadsUpRow(); + + if (isHunGoingToShade) { + // Keep 100% opacity for heads up notification going to shade. + viewState.alpha = 1f; + } else if (ambientState.isOnKeyguard()) { + // Adjust alpha for wakeup to lockscreen. + viewState.alpha = 1f - ambientState.getHideAmount(); + } else if (ambientState.isExpansionChanging()) { + // Adjust alpha for shade open & close. + float expansion = ambientState.getExpansionFraction(); + viewState.alpha = ambientState.isBouncerInTransit() + ? BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(expansion) + : ShadeInterpolation.getContentAlpha(expansion); + } + + // For EmptyShadeView if on keyguard, we need to control the alpha to create + // a nice transition when the user is dragging down the notification panel. + if (view instanceof EmptyShadeView && ambientState.isOnKeyguard()) { + final float fractionToShade = ambientState.getFractionToShade(); + viewState.alpha = ShadeInterpolation.getContentAlpha(fractionToShade); + } + + NotificationShelf shelf = ambientState.getShelf(); + if (shelf != null) { + final ViewState shelfState = shelf.getViewState(); + + // After the shelf has updated its yTranslation, explicitly set alpha=0 for view + // below shelf to skip rendering them in the hardware layer. We do not set them + // invisible because that runs invalidate & onDraw when these views return onscreen, + // which is more expensive. + if (shelfState.hidden) { + // When the shelf is hidden, it won't clip views, so we don't hide rows + return; + } + + final float shelfTop = shelfState.yTranslation; + final float viewTop = viewState.yTranslation; + if (viewTop >= shelfTop) { + viewState.alpha = 0; + } + } + } + } + /** * How expanded or collapsed notifications are when pulling down the shade. + * * @param ambientState Current ambient state. * @return 0 when fully collapsed, 1 when expanded. */ @@ -208,22 +261,6 @@ public class StackScrollAlgorithm { } shelf.updateState(algorithmState, ambientState); - - // After the shelf has updated its yTranslation, explicitly set alpha=0 for view below shelf - // to skip rendering them in the hardware layer. We do not set them invisible because that - // runs invalidate & onDraw when these views return onscreen, which is more expensive. - if (shelf.getViewState().hidden) { - // When the shelf is hidden, it won't clip views, so we don't hide rows - return; - } - final float shelfTop = shelf.getViewState().yTranslation; - - for (ExpandableView view : algorithmState.visibleChildren) { - final float viewTop = view.getViewState().yTranslation; - if (viewTop >= shelfTop) { - view.getViewState().alpha = 0; - } - } } private void updateClipping(StackScrollAlgorithmState algorithmState, @@ -473,21 +510,6 @@ public class StackScrollAlgorithm { ExpandableViewState viewState = view.getViewState(); viewState.location = ExpandableViewState.LOCATION_UNKNOWN; - final boolean isHunGoingToShade = ambientState.isShadeExpanded() - && view == ambientState.getTrackedHeadsUpRow(); - if (isHunGoingToShade) { - // Keep 100% opacity for heads up notification going to shade. - } else if (ambientState.isOnKeyguard()) { - // Adjust alpha for wakeup to lockscreen. - viewState.alpha = 1f - ambientState.getHideAmount(); - } else if (ambientState.isExpansionChanging()) { - // Adjust alpha for shade open & close. - float expansion = ambientState.getExpansionFraction(); - viewState.alpha = ambientState.isBouncerInTransit() - ? BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(expansion) - : ShadeInterpolation.getContentAlpha(expansion); - } - final float expansionFraction = getExpansionFractionWithoutShelf( algorithmState, ambientState); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt index 8fd6842911de..35d2363b1c2a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt @@ -3,19 +3,21 @@ package com.android.systemui.statusbar.notification.stack import android.annotation.DimenRes import android.widget.FrameLayout import androidx.test.filters.SmallTest +import com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress import com.android.systemui.R import com.android.systemui.SysuiTestCase +import com.android.systemui.animation.ShadeInterpolation.getContentAlpha import com.android.systemui.dump.DumpManager import com.android.systemui.statusbar.EmptyShadeView +import com.android.systemui.statusbar.NotificationShelf +import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.ExpandableView -import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.BypassController -import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.SectionProvider import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager import com.google.common.truth.Truth.assertThat +import junit.framework.Assert.assertEquals import junit.framework.Assert.assertFalse import junit.framework.Assert.assertTrue -import junit.framework.Assert.assertEquals import org.junit.Before import org.junit.Test import org.mockito.Mockito.mock @@ -26,17 +28,20 @@ class StackScrollAlgorithmTest : SysuiTestCase() { private val hostView = FrameLayout(context) private val stackScrollAlgorithm = StackScrollAlgorithm(context, hostView) - private val expandableViewState = ExpandableViewState() private val notificationRow = mock(ExpandableNotificationRow::class.java) private val dumpManager = mock(DumpManager::class.java) private val mStatusBarKeyguardViewManager = mock(StatusBarKeyguardViewManager::class.java) + private val notificationShelf = mock(NotificationShelf::class.java) + private val emptyShadeView = EmptyShadeView(context, /* attrs= */ null).apply { + layout(/* l= */ 0, /* t= */ 0, /* r= */ 100, /* b= */ 100) + } private val ambientState = AmbientState( - context, - dumpManager, - SectionProvider { _, _ -> false }, - BypassController { false }, - mStatusBarKeyguardViewManager + context, + dumpManager, + /* sectionProvider */ { _, _ -> false }, + /* bypassController */ { false }, + mStatusBarKeyguardViewManager ) private val testableResources = mContext.orCreateTestableResources @@ -49,7 +54,9 @@ class StackScrollAlgorithmTest : SysuiTestCase() { @Before fun setUp() { - whenever(notificationRow.viewState).thenReturn(expandableViewState) + whenever(notificationShelf.viewState).thenReturn(ExpandableViewState()) + whenever(notificationRow.viewState).thenReturn(ExpandableViewState()) + hostView.addView(notificationRow) } @@ -60,7 +67,8 @@ class StackScrollAlgorithmTest : SysuiTestCase() { stackScrollAlgorithm.resetViewStates(ambientState, 0) - assertThat(expandableViewState.yTranslation).isEqualTo(stackScrollAlgorithm.mHeadsUpInset) + assertThat(notificationRow.viewState.yTranslation) + .isEqualTo(stackScrollAlgorithm.mHeadsUpInset) } @Test @@ -75,15 +83,12 @@ class StackScrollAlgorithmTest : SysuiTestCase() { stackScrollAlgorithm.resetViewStates(ambientState, 0) // top margin presence should decrease heads up translation up to minHeadsUpTranslation - assertThat(expandableViewState.yTranslation).isEqualTo(minHeadsUpTranslation) + assertThat(notificationRow.viewState.yTranslation).isEqualTo(minHeadsUpTranslation) } @Test fun resetViewStates_emptyShadeView_isCenteredVertically() { stackScrollAlgorithm.initView(context) - val emptyShadeView = EmptyShadeView(context, /* attrs= */ null).apply { - layout(/* l= */ 0, /* t= */ 0, /* r= */ 100, /* b= */ 100) - } hostView.removeAllViews() hostView.addView(emptyShadeView) ambientState.layoutMaxHeight = 1280 @@ -97,6 +102,121 @@ class StackScrollAlgorithmTest : SysuiTestCase() { assertThat(emptyShadeView.viewState?.yTranslation).isEqualTo(centeredY) } + @Test + fun resetViewStates_hunGoingToShade_viewBecomesOpaque() { + whenever(notificationRow.isAboveShelf).thenReturn(true) + ambientState.isShadeExpanded = true + ambientState.trackedHeadsUpRow = notificationRow + stackScrollAlgorithm.initView(context) + + stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0) + + assertThat(notificationRow.viewState.alpha).isEqualTo(1f) + } + + @Test + fun resetViewStates_isExpansionChanging_viewBecomesTransparent() { + whenever(mStatusBarKeyguardViewManager.isBouncerInTransit).thenReturn(false) + ambientState.isExpansionChanging = true + ambientState.expansionFraction = 0.25f + stackScrollAlgorithm.initView(context) + + stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0) + + val expected = getContentAlpha(0.25f) + assertThat(notificationRow.viewState.alpha).isEqualTo(expected) + } + + @Test + fun resetViewStates_isExpansionChangingWhileBouncerInTransit_viewBecomesTransparent() { + whenever(mStatusBarKeyguardViewManager.isBouncerInTransit).thenReturn(true) + ambientState.isExpansionChanging = true + ambientState.expansionFraction = 0.25f + stackScrollAlgorithm.initView(context) + + stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0) + + val expected = aboutToShowBouncerProgress(0.25f) + assertThat(notificationRow.viewState.alpha).isEqualTo(expected) + } + + @Test + fun resetViewStates_isOnKeyguard_viewBecomesTransparent() { + ambientState.setStatusBarState(StatusBarState.KEYGUARD) + ambientState.hideAmount = 0.25f + stackScrollAlgorithm.initView(context) + + stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0) + + assertThat(notificationRow.viewState.alpha).isEqualTo(1f - ambientState.hideAmount) + } + + @Test + fun resetViewStates_isOnKeyguard_emptyShadeViewBecomesTransparent() { + ambientState.setStatusBarState(StatusBarState.KEYGUARD) + ambientState.fractionToShade = 0.25f + stackScrollAlgorithm.initView(context) + hostView.removeAllViews() + hostView.addView(emptyShadeView) + + stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0) + + val expected = getContentAlpha(ambientState.fractionToShade) + assertThat(emptyShadeView.viewState.alpha).isEqualTo(expected) + } + + @Test + fun resetViewStates_isOnKeyguard_emptyShadeViewBecomesOpaque() { + ambientState.setStatusBarState(StatusBarState.SHADE) + ambientState.fractionToShade = 0.25f + stackScrollAlgorithm.initView(context) + hostView.removeAllViews() + hostView.addView(emptyShadeView) + + stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0) + + assertThat(emptyShadeView.viewState.alpha).isEqualTo(1f) + } + + @Test + fun resetViewStates_hiddenShelf_viewAlphaDoesNotChange() { + val expected = notificationShelf.viewState.alpha + notificationShelf.viewState.hidden = true + ambientState.shelf = notificationShelf + stackScrollAlgorithm.initView(context) + + stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0) + + assertThat(notificationShelf.viewState.alpha).isEqualTo(expected) + } + + @Test + fun resetViewStates_shelfTopLessThanViewTop_hidesView() { + notificationRow.viewState.yTranslation = 10f + notificationShelf.viewState.yTranslation = 0.9f + notificationShelf.viewState.hidden = false + ambientState.shelf = notificationShelf + stackScrollAlgorithm.initView(context) + + stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0) + + assertThat(notificationRow.viewState.alpha).isEqualTo(0f) + } + + @Test + fun resetViewStates_shelfTopGreaterOrEqualThanViewTop_viewAlphaDoesNotChange() { + val expected = notificationRow.viewState.alpha + notificationRow.viewState.yTranslation = 10f + notificationShelf.viewState.yTranslation = 10f + notificationShelf.viewState.hidden = false + ambientState.shelf = notificationShelf + stackScrollAlgorithm.initView(context) + + stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0) + + assertThat(notificationRow.viewState.alpha).isEqualTo(expected) + } + @Test fun getGapForLocation_onLockscreen_returnsSmallGap() { val gap = stackScrollAlgorithm.getGapForLocation( @@ -267,7 +387,6 @@ class StackScrollAlgorithmTest : SysuiTestCase() { assertEquals(10f, expandableViewState.yTranslation) } - @Test fun clampHunToTop_viewYFarAboveVisibleStack_heightCollapsed() { val expandableViewState = ExpandableViewState() -- cgit v1.2.3-59-g8ed1b