diff options
| author | 2021-04-30 18:20:50 +0000 | |
|---|---|---|
| committer | 2021-04-30 18:20:50 +0000 | |
| commit | 2c4f9ddaf940f32311285667562b893dcfcc1cc1 (patch) | |
| tree | cb9a77715c8bd912fdb0fbee6fd98b491080a6cb | |
| parent | e0f6dc071fb1c16189dec64980b561cb86ef935f (diff) | |
| parent | 80a42c0fe1cc1d56ceca75c0c398e88174583c52 (diff) | |
Merge "New shelf shape, notification corner animations on scroll" into sc-dev
6 files changed, 84 insertions, 56 deletions
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 5371b413f389..13c285f12393 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -181,6 +181,9 @@ <!-- Radius for notifications corners without adjacent notifications --> <dimen name="notification_corner_radius">28dp</dimen> + <!-- Distance over which notification corner animations run, near the shelf while scrolling. --> + <dimen name="notification_corner_animation_distance">48dp</dimen> + <!-- Radius for notifications corners with adjacent notifications --> <dimen name="notification_corner_radius_small">4dp</dimen> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index fb109f310e15..8f462fea0468 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -84,7 +84,7 @@ public class NotificationShelf extends ActivatableNotificationView implements private int mCutoutHeight; private int mGapHeight; private int mIndexOfFirstViewInShelf = -1; - + private float mCornerAnimationDistance; private NotificationShelfController mController; public NotificationShelf(Context context, AttributeSet attrs) { @@ -104,6 +104,7 @@ public class NotificationShelf extends ActivatableNotificationView implements setClipToPadding(false); mShelfIcons.setIsStaticLayout(false); setBottomRoundness(1.0f, false /* animate */); + setTopRoundness(1f, false /* animate */); // Setting this to first in section to get the clipping to the top roundness correct. This // value determines the way we are clipping to the top roundness of the overall shade @@ -134,6 +135,8 @@ public class NotificationShelf extends ActivatableNotificationView implements mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size); mHiddenShelfIconSize = res.getDimensionPixelOffset(R.dimen.hidden_shelf_icon_size); mGapHeight = res.getDimensionPixelSize(R.dimen.qs_notification_padding); + mCornerAnimationDistance = res.getDimensionPixelSize( + R.dimen.notification_corner_animation_distance); mShelfIcons.setInNotificationIconShelf(true); if (!mShowNotificationShelf) { @@ -256,7 +259,7 @@ public class NotificationShelf extends ActivatableNotificationView implements boolean aboveShelf = ViewState.getFinalTranslationZ(child) > baseZHeight || child.isPinned(); boolean isLastChild = child == lastChild; - float rowTranslationY = child.getTranslationY(); + final float viewStart = child.getTranslationY(); final float inShelfAmount = updateShelfTransformation(i, child, scrollingFast, expandingAnimated, isLastChild); @@ -278,7 +281,7 @@ public class NotificationShelf extends ActivatableNotificationView implements ExpandableNotificationRow expandableRow = (ExpandableNotificationRow) child; numViewsInShelf += inShelfAmount; int ownColorUntinted = expandableRow.getBackgroundColorWithoutTint(); - if (rowTranslationY >= shelfStart && mNotGoneIndex == -1) { + if (viewStart >= shelfStart && mNotGoneIndex == -1) { mNotGoneIndex = notGoneIndex; setTintColor(previousColor); setOverrideTintColor(colorTwoBefore, transitionAmount); @@ -317,26 +320,44 @@ public class NotificationShelf extends ActivatableNotificationView implements notGoneIndex++; } + final float viewEnd = viewStart + child.getActualHeight(); + final float cornerAnimationDistance = mCornerAnimationDistance + * mAmbientState.getExpansionFraction(); + final float cornerAnimationTop = shelfStart - cornerAnimationDistance; + if (child instanceof ActivatableNotificationView) { ActivatableNotificationView anv = (ActivatableNotificationView) child; - if (anv.isFirstInSection() && previousAnv != null - && previousAnv.isLastInSection()) { - // If the top of the shelf is between the view before a gap and the view after a - // gap then we need to adjust the shelf's top roundness. - float distanceToGapBottom = child.getTranslationY() - getTranslationY(); - float distanceToGapTop = getTranslationY() - - (previousAnv.getTranslationY() + previousAnv.getActualHeight()); - if (distanceToGapTop > 0) { - // We interpolate our top roundness so that it's fully rounded if we're at - // the bottom of the gap, and not rounded at all if we're at the top of the - // gap (directly up against the bottom of previousAnv) - // Then we apply the same roundness to the bottom of previousAnv so that the - // corners join together as the shelf approaches previousAnv. - firstElementRoundness = (float) Math.min(1.0, - distanceToGapTop / mGapHeight); - previousAnv.setBottomRoundness(firstElementRoundness, - false /* don't animate */); + + if (viewStart < shelfStart + && !mHostLayoutController.isViewAffectedBySwipe(anv) + && !mAmbientState.isPulsing() + && !mAmbientState.isDozing()) { + + if (viewEnd >= cornerAnimationTop) { + // Round bottom corners within animation bounds + final float changeFraction = MathUtils.saturate( + (viewEnd - cornerAnimationTop) / cornerAnimationDistance); + final float roundness = anv.isLastInSection() ? 1f : changeFraction * 1f; + anv.setBottomRoundness(roundness, false); + + } else if (viewEnd < cornerAnimationTop) { + // Fast scroll skips frames and leaves corners with unfinished rounding. + // Reset top and bottom corners outside of animation bounds. + anv.setBottomRoundness(anv.isLastInSection() ? 1f : 0f, false); + } + + if (viewStart >= cornerAnimationTop) { + // Round top corners within animation bounds + final float changeFraction = MathUtils.saturate( + (viewStart - cornerAnimationTop) / cornerAnimationDistance); + final float roundness = anv.isFirstInSection() ? 1f : changeFraction * 1f; + anv.setTopRoundness(roundness, false); + + } else if (viewStart < cornerAnimationTop) { + // Fast scroll skips frames and leaves corners with unfinished rounding. + // Reset top and bottom corners outside of animation bounds. + anv.setTopRoundness(anv.isFirstInSection() ? 1f : 0f, false); } } previousAnv = anv; @@ -394,7 +415,6 @@ public class NotificationShelf extends ActivatableNotificationView implements private void setFirstElementRoundness(float firstElementRoundness) { if (mFirstElementRoundness != firstElementRoundness) { mFirstElementRoundness = firstElementRoundness; - setTopRoundness(firstElementRoundness, false /* animate */); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java index af8b4d99792a..f6ab409998bf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java @@ -84,8 +84,7 @@ public class NotificationBackgroundView extends View { int bottom = mActualHeight; if (mBottomIsRounded && mBottomAmountClips - && !mExpandAnimationRunning - && !mLastInSection) { + && !mExpandAnimationRunning) { bottom -= mClipBottomAmount; } int left = 0; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java index b1ac12e84fb3..4b49e3a90ede 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java @@ -71,6 +71,13 @@ public class NotificationRoundnessManager { } } + public boolean isViewAffectedBySwipe(ExpandableView expandableView) { + return expandableView != null + && (expandableView == mSwipedView + || expandableView == mViewBeforeSwipedView + || expandableView == mViewAfterSwipedView); + } + boolean updateViewWithoutCallback(ExpandableView view, boolean animate) { if (view == null @@ -78,38 +85,35 @@ public class NotificationRoundnessManager { || view == mViewAfterSwipedView) { return false; } - float topRoundness = getRoundness(view, true /* top */); - float bottomRoundness = getRoundness(view, false /* top */); - boolean topChanged = view.setTopRoundness(topRoundness, animate); - boolean bottomChanged = view.setBottomRoundness(bottomRoundness, animate); - boolean firstInSection = isFirstInSection(view, false /* exclude first section */); - boolean lastInSection = isLastInSection(view, false /* exclude last section */); - view.setFirstInSection(firstInSection); - view.setLastInSection(lastInSection); - return (firstInSection || lastInSection) && (topChanged || bottomChanged); + + final float topRoundness = getRoundness(view, true /* top */); + final float bottomRoundness = getRoundness(view, false /* top */); + + final boolean topChanged = view.setTopRoundness(topRoundness, animate); + final boolean bottomChanged = view.setBottomRoundness(bottomRoundness, animate); + + final boolean isFirstInSection = isFirstInSection(view); + final boolean isLastInSection = isLastInSection(view); + + view.setFirstInSection(isFirstInSection); + view.setLastInSection(isLastInSection); + + return (isFirstInSection || isLastInSection) && (topChanged || bottomChanged); } - private boolean isFirstInSection(ExpandableView view, boolean includeFirstSection) { - int numNonEmptySections = 0; + private boolean isFirstInSection(ExpandableView view) { for (int i = 0; i < mFirstInSectionViews.length; i++) { if (view == mFirstInSectionViews[i]) { - return includeFirstSection || numNonEmptySections > 0; - } - if (mFirstInSectionViews[i] != null) { - numNonEmptySections++; + return true; } } return false; } - private boolean isLastInSection(ExpandableView view, boolean includeLastSection) { - int numNonEmptySections = 0; + private boolean isLastInSection(ExpandableView view) { for (int i = mLastInSectionViews.length - 1; i >= 0; i--) { if (view == mLastInSectionViews[i]) { - return includeLastSection || numNonEmptySections > 0; - } - if (mLastInSectionViews[i] != null) { - numNonEmptySections++; + return true; } } return false; @@ -172,10 +176,10 @@ public class NotificationRoundnessManager { || (view.isHeadsUpAnimatingAway()) && !mExpanded)) { return 1.0f; } - if (isFirstInSection(view, true /* include first section */) && top) { + if (isFirstInSection(view) && top) { return 1.0f; } - if (isLastInSection(view, true /* include last section */) && !top) { + if (isLastInSection(view) && !top) { return 1.0f; } if (view == mTrackedHeadsUp) { @@ -229,10 +233,8 @@ public class NotificationRoundnessManager { : section.getLastVisibleChild()); if (newView == oldView) { isStillPresent = true; - if (oldView.isFirstInSection() != isFirstInSection(oldView, - false /* exclude first section */) - || oldView.isLastInSection() != isLastInSection(oldView, - false /* exclude last section */)) { + if (oldView.isFirstInSection() != isFirstInSection(oldView) + || oldView.isLastInSection() != isLastInSection(oldView)) { adjacentSectionChanged = true; } break; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index ae9467eb651b..b039df3f32af 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -740,6 +740,10 @@ public class NotificationStackScrollLayoutController { return true; } + public boolean isViewAffectedBySwipe(ExpandableView expandableView) { + return mNotificationRoundnessManager.isViewAffectedBySwipe(expandableView); + } + public void addOnExpandedHeightChangedListener(BiConsumer<Float, Float> listener) { mView.addOnExpandedHeightChangedListener(listener); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java index 919ddcb488c2..0772c03d10d0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java @@ -315,8 +315,8 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase { @Test public void testNoViewsFirstOrLastInSectionWhenSecondSectionEmpty() { - Assert.assertFalse(mFirst.isFirstInSection()); - Assert.assertFalse(mFirst.isLastInSection()); + Assert.assertTrue(mFirst.isFirstInSection()); + Assert.assertTrue(mFirst.isLastInSection()); } @Test @@ -325,8 +325,8 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase { createSection(null, null), createSection(mSecond, mSecond) }); - Assert.assertFalse(mSecond.isFirstInSection()); - Assert.assertFalse(mSecond.isLastInSection()); + Assert.assertTrue(mSecond.isFirstInSection()); + Assert.assertTrue(mSecond.isLastInSection()); } @Test @@ -335,10 +335,10 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase { createSection(mFirst, mFirst), createSection(mSecond, mSecond) }); - Assert.assertFalse(mFirst.isFirstInSection()); + Assert.assertTrue(mFirst.isFirstInSection()); Assert.assertTrue(mFirst.isLastInSection()); Assert.assertTrue(mSecond.isFirstInSection()); - Assert.assertFalse(mSecond.isLastInSection()); + Assert.assertTrue(mSecond.isLastInSection()); } private NotificationSection createSection(ExpandableNotificationRow first, |