Loading packages/SystemUI/src/com/android/systemui/flags/Flags.kt +4 −0 Original line number Diff line number Diff line Loading @@ -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 = Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +74 −14 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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) Loading Loading @@ -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); Loading Loading @@ -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); } } /** Loading Loading @@ -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() { Loading Loading @@ -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) { Loading Loading @@ -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 Loading @@ -1834,6 +1893,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable // to scroll up some more do so now. scrollTo(mForcedScroll); } } return insets; } Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +19 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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}. */ Loading Loading @@ -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. Loading Loading
packages/SystemUI/src/com/android/systemui/flags/Flags.kt +4 −0 Original line number Diff line number Diff line Loading @@ -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 = Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +74 −14 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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) Loading Loading @@ -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); Loading Loading @@ -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); } } /** Loading Loading @@ -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() { Loading Loading @@ -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) { Loading Loading @@ -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 Loading @@ -1834,6 +1893,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable // to scroll up some more do so now. scrollTo(mForcedScroll); } } return insets; } Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +19 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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}. */ Loading Loading @@ -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. Loading