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

Commit e1766512 authored by Johannes Gallmann's avatar Johannes Gallmann Committed by Android (Google) Code Review
Browse files

Merge "Scroll NotificationStack in sync with IME when inline replying" into tm-qpr-dev

parents 91a76fbd c1bda5b3
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -109,6 +109,10 @@ object Flags {
    @JvmField
    val NOTIFICATION_ANIMATE_BIG_PICTURE = unreleasedFlag(120, "notification_animate_big_picture")

    @JvmField
    val ANIMATED_NOTIFICATION_SHADE_INSETS =
        unreleasedFlag(270682168, "animated_notification_shade_insets", teamfood = true)

    // 200 - keyguard/lockscreen
    // ** Flag retired **
    // public static final BooleanFlag KEYGUARD_LAYOUT =
+74 −14
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.WindowInsetsAnimation;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.AnimationUtils;
@@ -199,6 +200,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
    private final boolean mDebugRemoveAnimation;
    private final boolean mSimplifiedAppearFraction;
    private final boolean mUseRoundnessSourceTypes;
    private boolean mAnimatedInsets;

    private int mContentHeight;
    private float mIntrinsicContentHeight;
@@ -207,7 +209,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
    private int mTopPadding;
    private boolean mAnimateNextTopPaddingChange;
    private int mBottomPadding;
    private int mBottomInset = 0;
    @VisibleForTesting
    int mBottomInset = 0;
    private float mQsExpansionFraction;
    private final int mSplitShadeMinContentHeight;

@@ -388,9 +391,33 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
            }
        }
    };

    private boolean mPulsing;
    private boolean mScrollable;
    private View mForcedScroll;
    private boolean mIsInsetAnimationRunning;

    private final WindowInsetsAnimation.Callback mInsetsCallback =
            new WindowInsetsAnimation.Callback(
                    WindowInsetsAnimation.Callback.DISPATCH_MODE_CONTINUE_ON_SUBTREE) {

                @Override
                public void onPrepare(WindowInsetsAnimation animation) {
                    mIsInsetAnimationRunning = true;
                }

                @Override
                public WindowInsets onProgress(WindowInsets windowInsets,
                        List<WindowInsetsAnimation> list) {
                    updateBottomInset(windowInsets);
                    return windowInsets;
                }

                @Override
                public void onEnd(WindowInsetsAnimation animation) {
                    mIsInsetAnimationRunning = false;
                }
            };

    /**
     * @see #setHideAmount(float, float)
@@ -584,6 +611,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
        mDebugRemoveAnimation = featureFlags.isEnabled(Flags.NSSL_DEBUG_REMOVE_ANIMATION);
        mSimplifiedAppearFraction = featureFlags.isEnabled(Flags.SIMPLIFIED_APPEAR_FRACTION);
        mUseRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES);
        setAnimatedInsetsEnabled(featureFlags.isEnabled(Flags.ANIMATED_NOTIFICATION_SHADE_INSETS));
        mSectionsManager = Dependency.get(NotificationSectionsManager.class);
        mScreenOffAnimationController =
                Dependency.get(ScreenOffAnimationController.class);
@@ -622,6 +650,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
        mGroupMembershipManager = Dependency.get(GroupMembershipManager.class);
        mGroupExpansionManager = Dependency.get(GroupExpansionManager.class);
        setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
        if (mAnimatedInsets) {
            setWindowInsetsAnimationCallback(mInsetsCallback);
        }
    }

    /**
@@ -689,6 +720,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
        mHasFilteredOutSeenNotifications = hasFilteredOutSeenNotifications;
    }

    @VisibleForTesting
    void setAnimatedInsetsEnabled(boolean enabled) {
        mAnimatedInsets = enabled;
    }

    @VisibleForTesting
    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
    public void updateFooter() {
@@ -1781,8 +1817,12 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
            return;
        }
        mForcedScroll = v;
        if (mAnimatedInsets) {
            updateForcedScroll();
        } else {
            scrollTo(v);
        }
    }

    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
    public boolean scrollTo(View v) {
@@ -1813,16 +1853,35 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
                + ((!isExpanded() && isPinnedHeadsUp(v)) ? mHeadsUpInset : getTopPadding());
    }

    private void updateBottomInset(WindowInsets windowInsets) {
        mBottomInset = windowInsets.getInsets(WindowInsets.Type.ime()).bottom;

        if (mForcedScroll != null) {
            updateForcedScroll();
        }

        int range = getScrollRange();
        if (mOwnScrollY > range) {
            setOwnScrollY(range);
        }
    }

    @Override
    @ShadeViewRefactor(RefactorComponent.COORDINATOR)
    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
        if (!mAnimatedInsets) {
            mBottomInset = insets.getInsets(WindowInsets.Type.ime()).bottom;
        }
        mWaterfallTopInset = 0;
        final DisplayCutout cutout = insets.getDisplayCutout();
        if (cutout != null) {
            mWaterfallTopInset = cutout.getWaterfallInsets().top;
        }

        if (mAnimatedInsets && !mIsInsetAnimationRunning) {
            // update bottom inset e.g. after rotation
            updateBottomInset(insets);
        }
        if (!mAnimatedInsets) {
            int range = getScrollRange();
            if (mOwnScrollY > range) {
                // HACK: We're repeatedly getting staggered insets here while the IME is
@@ -1834,6 +1893,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
                // to scroll up some more do so now.
                scrollTo(mForcedScroll);
            }
        }
        return insets;
    }

+19 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.stack;

import static android.view.View.GONE;
import static android.view.WindowInsets.Type.ime;

import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE;
@@ -46,6 +47,7 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.graphics.Insets;
import android.graphics.Rect;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -54,6 +56,8 @@ import android.util.MathUtils;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
import android.view.WindowInsetsAnimation;
import android.widget.TextView;

import androidx.test.annotation.UiThreadTest;
@@ -91,6 +95,8 @@ import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;

import java.util.ArrayList;

/**
 * Tests for {@link NotificationStackScrollLayout}.
 */
@@ -843,6 +849,19 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
        verify(mEmptyShadeView).setFooterText(not(0));
    }

    @Test
    public void testWindowInsetAnimationProgress_updatesBottomInset() {
        int bottomImeInset = 100;
        mStackScrollerInternal.setAnimatedInsetsEnabled(true);
        WindowInsets windowInsets = new WindowInsets.Builder()
                .setInsets(ime(), Insets.of(0, 0, 0, bottomImeInset)).build();
        ArrayList<WindowInsetsAnimation> windowInsetsAnimations = new ArrayList<>();
        mStackScrollerInternal
                .dispatchWindowInsetsAnimationProgress(windowInsets, windowInsetsAnimations);

        assertEquals(bottomImeInset, mStackScrollerInternal.mBottomInset);
    }

    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.