From 129869eb48d422ec6d98cc1e2ab0ce86d128ec7b Mon Sep 17 00:00:00 2001 From: Lyn Han Date: Tue, 19 Jan 2021 21:32:02 -0600 Subject: [PATCH 1/2] Fade in notifications one by one NSSL#applyCurrentState sets ExpandableViewState#shouldFadeForShadeOpen which ViewState uses to determine whether to animate alpha. Bug: 172289889 Test: visual Change-Id: Iab095bdbdbe6c3d882c0a8a0f678a132cdb6eaed --- .../notification/row/ExpandableView.java | 6 +++ .../stack/ExpandableViewState.java | 10 ++++ .../stack/NotificationStackScrollLayout.java | 1 + .../stack/StackScrollAlgorithm.java | 13 +++-- .../stack/StackStateAnimator.java | 1 + .../notification/stack/ViewState.java | 54 ++++++++++++------- 6 files changed, 60 insertions(+), 25 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java index ba03d01b20b06..92b381e58698a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java @@ -614,6 +614,12 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable { } } + public void setShouldFadeForShadeOpen(boolean shouldFade) { + if (!mViewState.gone) { + mViewState.setShouldFadeForShadeOpen(shouldFade); + } + } + /** * @return whether the current view doesn't add height to the overall content. This means that * if it is added to a list of items, its content will still have the same height. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java index 628c4e258e50e..21b6863adf0ec 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java @@ -88,6 +88,12 @@ public class ExpandableViewState extends ViewState { public boolean hideSensitive; public boolean belowSpeedBump; public boolean inShelf; + public boolean shouldFadeForShadeOpen; + + @Override + boolean shouldAnimateAlpha() { + return shouldFadeForShadeOpen; + } /** * A state indicating whether a headsup is currently fully visible, even when not scrolled. @@ -171,6 +177,10 @@ public class ExpandableViewState extends ViewState { } } + public void setShouldFadeForShadeOpen(boolean shouldFade) { + shouldFadeForShadeOpen = shouldFade; + } + @Override public void animateTo(View child, AnimationProperties properties) { super.animateTo(child, properties); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index f07d8740c3e90..a2ce9e1ad6cca 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -3947,6 +3947,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable int numChildren = getChildCount(); for (int i = 0; i < numChildren; i++) { ExpandableView child = (ExpandableView) getChildAt(i); + child.setShouldFadeForShadeOpen(mAmbientState.isShadeOpening()); child.applyViewState(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java index e6efba7ca28bb..4bf7be3ba330c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java @@ -568,11 +568,14 @@ public class StackScrollAlgorithm { // Add padding before sections for overscroll effect. childViewState.yTranslation += ambientState.getSectionPadding(); } - if (childViewState.yTranslation >= shelfStart) { - childViewState.hidden = !child.isExpandAnimationRunning() && !child.hasExpandingChild(); - childViewState.inShelf = true; - childViewState.headsUpIsVisible = false; - } + boolean show = childViewState.yTranslation < shelfStart + && !ambientState.isAppearing(); + childViewState.hidden = !show + && !child.isExpandAnimationRunning() + && !child.hasExpandingChild(); + childViewState.inShelf = !show; + childViewState.headsUpIsVisible = show; + childViewState.alpha = show ? 1f : 0f; } protected int getMaxAllowedChildHeight(View child) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java index 66a48f16b6240..43f1f431e138d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java @@ -45,6 +45,7 @@ public class StackStateAnimator { public static final int ANIMATION_DURATION_CORNER_RADIUS = 200; public static final int ANIMATION_DURATION_WAKEUP = 500; public static final int ANIMATION_DURATION_GO_TO_FULL_SHADE = 448; + public static final int ANIMATION_DURATION_FADE_IN = 700; public static final int ANIMATION_DURATION_APPEAR_DISAPPEAR = 464; public static final int ANIMATION_DURATION_SWIPE = 260; public static final int ANIMATION_DURATION_DIMMED_ACTIVATED = 220; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java index 3da4e321c54d2..abe5c698034e8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.notification.stack; +import static com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_FADE_IN; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; @@ -56,6 +58,16 @@ public class ViewState implements Dumpable { return mAnimationFilter; } }; + + protected static final AnimationProperties ANIMATE_ALPHA = new AnimationProperties() { + AnimationFilter mAnimationFilter = new AnimationFilter(); + @Override + public AnimationFilter getAnimationFilter() { + mAnimationFilter.animateAlpha(); + return mAnimationFilter; + } + }.setDuration(ANIMATION_DURATION_FADE_IN); + private static final int TAG_ANIMATOR_TRANSLATION_X = R.id.translation_x_animator_tag; private static final int TAG_ANIMATOR_TRANSLATION_Y = R.id.translation_y_animator_tag; private static final int TAG_ANIMATOR_TRANSLATION_Z = R.id.translation_z_animator_tag; @@ -148,6 +160,10 @@ public class ViewState implements Dumpable { scaleY = view.getScaleY(); } + boolean shouldAnimateAlpha() { + return false; + } + /** * Applies a {@link ViewState} to a normal view. */ @@ -200,24 +216,26 @@ public class ViewState implements Dumpable { int oldVisibility = view.getVisibility(); boolean becomesInvisible = this.alpha == 0.0f || (this.hidden && (!isAnimating(view) || oldVisibility != View.VISIBLE)); - boolean animatingAlpha = isAnimating(view, TAG_ANIMATOR_ALPHA); - if (animatingAlpha) { - updateAlphaAnimation(view); + if (isAnimating(view, TAG_ANIMATOR_ALPHA)) { + startAlphaAnimation(view, NO_NEW_ANIMATIONS); } else if (view.getAlpha() != this.alpha) { - // apply layer type - boolean becomesFullyVisible = this.alpha == 1.0f; - boolean newLayerTypeIsHardware = !becomesInvisible && !becomesFullyVisible - && view.hasOverlappingRendering(); - int layerType = view.getLayerType(); - int newLayerType = newLayerTypeIsHardware - ? View.LAYER_TYPE_HARDWARE - : View.LAYER_TYPE_NONE; - if (layerType != newLayerType) { - view.setLayerType(newLayerType, null); + if (shouldAnimateAlpha()) { + startAlphaAnimation(view, ANIMATE_ALPHA); + } else { + // apply layer type + boolean becomesFullyVisible = this.alpha == 1.0f; + boolean newLayerTypeIsHardware = !becomesInvisible && !becomesFullyVisible + && view.hasOverlappingRendering(); + int layerType = view.getLayerType(); + int newLayerType = newLayerTypeIsHardware + ? View.LAYER_TYPE_HARDWARE + : View.LAYER_TYPE_NONE; + if (layerType != newLayerType) { + view.setLayerType(newLayerType, null); + } + // apply alpha + view.setAlpha(this.alpha); } - - // apply alpha - view.setAlpha(this.alpha); } // apply visibility @@ -322,10 +340,6 @@ public class ViewState implements Dumpable { } } - private void updateAlphaAnimation(View view) { - startAlphaAnimation(view, NO_NEW_ANIMATIONS); - } - private void startAlphaAnimation(final View child, AnimationProperties properties) { Float previousStartValue = getChildTag(child,TAG_START_ALPHA); Float previousEndValue = getChildTag(child,TAG_END_ALPHA); From 8f3ba5abbd18087b756a89eb8985e265199d0a17 Mon Sep 17 00:00:00 2001 From: Lyn Han Date: Tue, 19 Jan 2021 18:06:31 -0600 Subject: [PATCH 2/2] Clip view before shelf and leave the rest unclipped Bug: 172289889 Test: visual Change-Id: Ic49edf84ba246be9bfff7d39d822ced1d7a23e46 --- .../systemui/statusbar/NotificationShelf.java | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index 20efa32d63c6f..4a8057201c2f7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -204,6 +204,30 @@ public class NotificationShelf extends ActivatableNotificationView implements } } + /** + * @return whether to clip bottom of given view + */ + private boolean shouldClipBottom(ExpandableView view) { + final boolean showShelf = ((ShelfState) getViewState()).hasItemsInStableShelf; + if (showShelf) { + if (mAmbientState.isShadeOpening()) { + final float viewEnd = view.getTranslationY() + + view.getActualHeight() + + mPaddingBetweenElements; + final float finalShelfStart = mMaxLayoutHeight - getIntrinsicHeight(); + // While the shade is opening, only clip view if it overlaps with shelf; + // otherwise leave view unclipped. + if (viewEnd < finalShelfStart) { + return false; + } + } + // Clip for scrolling. + return true; + } + // Don't clip since we have enough space to show all views. + return false; + } + /** * Update the shelf appearance based on the other notifications around it. This transforms * the icons from the notification area into the shelf. @@ -345,7 +369,9 @@ public class NotificationShelf extends ActivatableNotificationView implements clipTransientViews(); setClipTopAmount(clipTopAmount); - boolean isHidden = getViewState().hidden || clipTopAmount >= getIntrinsicHeight(); + boolean isHidden = getViewState().hidden + || clipTopAmount >= getIntrinsicHeight() + || mAmbientState.isShadeOpening(); if (mShowNotificationShelf) { setVisibility(isHidden ? View.INVISIBLE : View.VISIBLE); } @@ -468,7 +494,8 @@ public class NotificationShelf extends ActivatableNotificationView implements } else { shouldClipOwnTop = view.showingPulsing(); } - if (viewEnd > notificationClipEnd && !shouldClipOwnTop + if (shouldClipBottom(view) + && viewEnd > notificationClipEnd && !shouldClipOwnTop && (mAmbientState.isShadeExpanded() || !isPinned)) { int clipBottomAmount = (int) (viewEnd - notificationClipEnd); if (isPinned) {