Add overscroll effect to top of split shade
Bug: 250004096 Test: atest NotificationStackScrollLayoutTest Change-Id: Id2311f6edb2029d99509ecbce5aa3da072ad043e
This commit is contained in:
@@ -146,7 +146,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
private static final int DELAY_BEFORE_SHADE_CLOSE = 200;
|
||||
private boolean mShadeNeedsToClose = false;
|
||||
|
||||
private static final float RUBBER_BAND_FACTOR_NORMAL = 0.35f;
|
||||
@VisibleForTesting
|
||||
static final float RUBBER_BAND_FACTOR_NORMAL = 0.35f;
|
||||
private static final float RUBBER_BAND_FACTOR_AFTER_EXPAND = 0.15f;
|
||||
private static final float RUBBER_BAND_FACTOR_ON_PANEL_EXPAND = 0.21f;
|
||||
/**
|
||||
@@ -1326,8 +1327,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
* @param listenerNeedsAnimation does the listener need to animate?
|
||||
*/
|
||||
private void updateStackPosition(boolean listenerNeedsAnimation) {
|
||||
float topOverscrollAmount = mShouldUseSplitNotificationShade
|
||||
? getCurrentOverScrollAmount(true /* top */) : 0f;
|
||||
final float endTopPosition = mTopPadding + mExtraTopInsetForFullShadeTransition
|
||||
+ mAmbientState.getOverExpansion()
|
||||
+ topOverscrollAmount
|
||||
- getCurrentOverScrollAmount(false /* top */);
|
||||
float fraction = mAmbientState.getExpansionFraction();
|
||||
// If we are on quick settings, we need to quickly hide it to show the bouncer to avoid an
|
||||
@@ -2613,8 +2617,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
float bottomAmount = getCurrentOverScrollAmount(false);
|
||||
if (velocityY < 0 && topAmount > 0) {
|
||||
setOwnScrollY(mOwnScrollY - (int) topAmount);
|
||||
mDontReportNextOverScroll = true;
|
||||
setOverScrollAmount(0, true, false);
|
||||
if (!mShouldUseSplitNotificationShade) {
|
||||
mDontReportNextOverScroll = true;
|
||||
setOverScrollAmount(0, true, false);
|
||||
}
|
||||
mMaxOverScroll = Math.abs(velocityY) / 1000f * getRubberBandFactor(true /* onTop */)
|
||||
* mOverflingDistance + topAmount;
|
||||
} else if (velocityY > 0 && bottomAmount > 0) {
|
||||
@@ -2648,6 +2654,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
float topOverScroll = getCurrentOverScrollAmount(true);
|
||||
return mScrolledToTopOnFirstDown
|
||||
&& !mExpandedInThisMotion
|
||||
&& !mShouldUseSplitNotificationShade
|
||||
&& (initialVelocity > mMinimumVelocity
|
||||
|| (topOverScroll > mMinTopOverScrollToEscape && initialVelocity > 0));
|
||||
}
|
||||
@@ -2713,7 +2720,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
return RUBBER_BAND_FACTOR_AFTER_EXPAND;
|
||||
} else if (mIsExpansionChanging || mPanelTracking) {
|
||||
return RUBBER_BAND_FACTOR_ON_PANEL_EXPAND;
|
||||
} else if (mScrolledToTopOnFirstDown) {
|
||||
} else if (mScrolledToTopOnFirstDown && !mShouldUseSplitNotificationShade) {
|
||||
return 1.0f;
|
||||
}
|
||||
return RUBBER_BAND_FACTOR_NORMAL;
|
||||
@@ -5705,7 +5712,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSplitNotificationShade() {
|
||||
@VisibleForTesting
|
||||
void updateSplitNotificationShade() {
|
||||
boolean split = LargeScreenUtils.shouldUseSplitNotificationShade(getResources());
|
||||
if (split != mShouldUseSplitNotificationShade) {
|
||||
mShouldUseSplitNotificationShade = split;
|
||||
|
||||
@@ -20,6 +20,7 @@ import static android.view.View.GONE;
|
||||
|
||||
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
|
||||
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE;
|
||||
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.RUBBER_BAND_FACTOR_NORMAL;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
@@ -47,6 +48,7 @@ import static org.mockito.Mockito.when;
|
||||
import android.graphics.Rect;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
import android.testing.TestableResources;
|
||||
import android.util.MathUtils;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
@@ -99,6 +101,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
|
||||
private NotificationStackScrollLayout mStackScroller; // Normally test this
|
||||
private NotificationStackScrollLayout mStackScrollerInternal; // See explanation below
|
||||
private AmbientState mAmbientState;
|
||||
private TestableResources mTestableResources;
|
||||
|
||||
@Rule public MockitoRule mockito = MockitoJUnit.rule();
|
||||
@Mock private CentralSurfaces mCentralSurfaces;
|
||||
@@ -123,6 +126,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
|
||||
@UiThreadTest
|
||||
public void setUp() throws Exception {
|
||||
allowTestableLooperAsMainThread();
|
||||
mTestableResources = mContext.getOrCreateTestableResources();
|
||||
|
||||
// Interact with real instance of AmbientState.
|
||||
mAmbientState = spy(new AmbientState(
|
||||
@@ -394,7 +398,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testSetExpandedHeight_withSplitShade_doesntInterpolateStackHeight() {
|
||||
mContext.getOrCreateTestableResources()
|
||||
mTestableResources
|
||||
.addOverride(R.bool.config_use_split_notification_shade, /* value= */ true);
|
||||
final int[] expectedStackHeight = {0};
|
||||
|
||||
@@ -405,12 +409,12 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
|
||||
.isEqualTo(expectedStackHeight[0]);
|
||||
});
|
||||
|
||||
mContext.getOrCreateTestableResources()
|
||||
mTestableResources
|
||||
.addOverride(R.bool.config_use_split_notification_shade, /* value= */ false);
|
||||
expectedStackHeight[0] = 0;
|
||||
mStackScroller.setExpandedHeight(100f);
|
||||
|
||||
mContext.getOrCreateTestableResources()
|
||||
mTestableResources
|
||||
.addOverride(R.bool.config_use_split_notification_shade, /* value= */ true);
|
||||
expectedStackHeight[0] = 100;
|
||||
mStackScroller.setExpandedHeight(100f);
|
||||
@@ -781,6 +785,39 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
|
||||
assertEquals(mAmbientState.getScrollY(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitShade_hasTopOverscroll() {
|
||||
mTestableResources
|
||||
.addOverride(R.bool.config_use_split_notification_shade, /* value= */ true);
|
||||
mStackScroller.updateSplitNotificationShade();
|
||||
mAmbientState.setExpansionFraction(1f);
|
||||
|
||||
int topOverscrollPixels = 100;
|
||||
mStackScroller.setOverScrolledPixels(topOverscrollPixels, true, false);
|
||||
|
||||
float expectedTopOverscrollAmount = topOverscrollPixels * RUBBER_BAND_FACTOR_NORMAL;
|
||||
assertEquals(expectedTopOverscrollAmount, mStackScroller.getCurrentOverScrollAmount(true));
|
||||
assertEquals(expectedTopOverscrollAmount, mAmbientState.getStackY());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalShade_hasNoTopOverscroll() {
|
||||
mTestableResources
|
||||
.addOverride(R.bool.config_use_split_notification_shade, /* value= */ false);
|
||||
mStackScroller.updateSplitNotificationShade();
|
||||
mAmbientState.setExpansionFraction(1f);
|
||||
|
||||
int topOverscrollPixels = 100;
|
||||
mStackScroller.setOverScrolledPixels(topOverscrollPixels, true, false);
|
||||
|
||||
float expectedTopOverscrollAmount = topOverscrollPixels * RUBBER_BAND_FACTOR_NORMAL;
|
||||
assertEquals(expectedTopOverscrollAmount, mStackScroller.getCurrentOverScrollAmount(true));
|
||||
// When not in split shade mode, then the overscroll effect is handled in
|
||||
// NotificationPanelViewController and not in NotificationStackScrollLayout. Therefore
|
||||
// mAmbientState must have stackY set to 0
|
||||
assertEquals(0f, mAmbientState.getStackY());
|
||||
}
|
||||
|
||||
private void setBarStateForTest(int state) {
|
||||
// Can't inject this through the listener or we end up on the actual implementation
|
||||
// rather than the mock because the spy just coppied the anonymous inner /shruggie.
|
||||
|
||||
Reference in New Issue
Block a user