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
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
&& !mView.isQsFullScreen()
|
||||
&& getVisibleNotificationCount() == 0;
|
||||
|
||||
mView.updateEmptyShadeView(
|
||||
mShowEmptyShadeView,
|
||||
mZenModeController.areNotificationsHiddenInShade());
|
||||
final boolean shouldShow = getVisibleNotificationCount() == 0
|
||||
&& !mView.isQsFullScreen()
|
||||
// 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());
|
||||
|
||||
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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user