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

Commit ab6c72c6 authored by Johannes Gallmann's avatar Johannes Gallmann
Browse files

Add overscroll effect to top of split shade

Bug: 250004096
Test: atest NotificationStackScrollLayoutTest
Change-Id: Id2311f6edb2029d99509ecbce5aa3da072ad043e
parent 305d1bc4
Loading
Loading
Loading
Loading
+13 −5
Original line number Diff line number Diff line
@@ -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);
                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;
+40 −3
Original line number Diff line number Diff line
@@ -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.