Loading packages/SystemUI/res/values/config.xml +3 −0 Original line number Diff line number Diff line Loading @@ -357,6 +357,9 @@ the notification is not swiped enough to dismiss it. --> <bool name="config_showNotificationGear">true</bool> <!-- Whether or not a background should be drawn behind a notification. --> <bool name="config_drawNotificationBackground">true</bool> <!-- Whether or the notifications can be shown and dismissed with a drag. --> <bool name="config_enableNotificationShadeDrag">true</bool> Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java +18 −0 Original line number Diff line number Diff line Loading @@ -82,6 +82,9 @@ public class AmbientState { private ExpandableNotificationRow mTrackedHeadsUpRow; private float mAppearFraction; /** Tracks the state from AlertingNotificationManager#hasNotifications() */ private boolean mHasAlertEntries; public AmbientState( Context context, @NonNull SectionProvider sectionProvider) { Loading Loading @@ -365,10 +368,21 @@ public class AmbientState { mPanelTracking = panelTracking; } public boolean hasPulsingNotifications() { return mPulsing && mHasAlertEntries; } public void setPulsing(boolean hasPulsing) { mPulsing = hasPulsing; } /** * @return if we're pulsing in general */ public boolean isPulsing() { return mPulsing; } public boolean isPulsing(NotificationEntry entry) { return mPulsing && entry.isAlerting(); } Loading Loading @@ -527,4 +541,8 @@ public class AmbientState { public float getAppearFraction() { return mAppearFraction; } public void setHasAlertEntries(boolean hasAlertEntries) { mHasAlertEntries = hasAlertEntries; } } packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java +244 −2 Original line number Diff line number Diff line Loading @@ -31,22 +31,175 @@ import com.android.systemui.statusbar.notification.ShadeViewRefactor; import com.android.systemui.statusbar.notification.row.ExpandableView; /** * Represents the priority of a notification section and tracks first and last visible children. * Represents the bounds of a section of the notification shade and handles animation when the * bounds change. */ public class NotificationSection { private @PriorityBucket int mBucket; private View mOwningView; private Rect mBounds = new Rect(); private Rect mCurrentBounds = new Rect(-1, -1, -1, -1); private Rect mStartAnimationRect = new Rect(); private Rect mEndAnimationRect = new Rect(); private ObjectAnimator mTopAnimator = null; private ObjectAnimator mBottomAnimator = null; private ExpandableView mFirstVisibleChild; private ExpandableView mLastVisibleChild; NotificationSection(@PriorityBucket int bucket) { NotificationSection(View owningView, @PriorityBucket int bucket) { mOwningView = owningView; mBucket = bucket; } public void cancelAnimators() { if (mBottomAnimator != null) { mBottomAnimator.cancel(); } if (mTopAnimator != null) { mTopAnimator.cancel(); } } public Rect getCurrentBounds() { return mCurrentBounds; } public Rect getBounds() { return mBounds; } public boolean didBoundsChange() { return !mCurrentBounds.equals(mBounds); } public boolean areBoundsAnimating() { return mBottomAnimator != null || mTopAnimator != null; } @PriorityBucket public int getBucket() { return mBucket; } public void startBackgroundAnimation(boolean animateTop, boolean animateBottom) { // Left and right bounds are always applied immediately. mCurrentBounds.left = mBounds.left; mCurrentBounds.right = mBounds.right; startBottomAnimation(animateBottom); startTopAnimation(animateTop); } @ShadeViewRefactor(ShadeViewRefactor.RefactorComponent.STATE_RESOLVER) private void startTopAnimation(boolean animate) { int previousEndValue = mEndAnimationRect.top; int newEndValue = mBounds.top; ObjectAnimator previousAnimator = mTopAnimator; if (previousAnimator != null && previousEndValue == newEndValue) { return; } if (!animate) { // just a local update was performed if (previousAnimator != null) { // we need to increase all animation keyframes of the previous animator by the // relative change to the end value int previousStartValue = mStartAnimationRect.top; PropertyValuesHolder[] values = previousAnimator.getValues(); values[0].setIntValues(previousStartValue, newEndValue); mStartAnimationRect.top = previousStartValue; mEndAnimationRect.top = newEndValue; previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime()); return; } else { // no new animation needed, let's just apply the value setBackgroundTop(newEndValue); return; } } if (previousAnimator != null) { previousAnimator.cancel(); } ObjectAnimator animator = ObjectAnimator.ofInt(this, "backgroundTop", mCurrentBounds.top, newEndValue); Interpolator interpolator = Interpolators.FAST_OUT_SLOW_IN; animator.setInterpolator(interpolator); animator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); // remove the tag when the animation is finished animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mStartAnimationRect.top = -1; mEndAnimationRect.top = -1; mTopAnimator = null; } }); animator.start(); mStartAnimationRect.top = mCurrentBounds.top; mEndAnimationRect.top = newEndValue; mTopAnimator = animator; } @ShadeViewRefactor(ShadeViewRefactor.RefactorComponent.STATE_RESOLVER) private void startBottomAnimation(boolean animate) { int previousStartValue = mStartAnimationRect.bottom; int previousEndValue = mEndAnimationRect.bottom; int newEndValue = mBounds.bottom; ObjectAnimator previousAnimator = mBottomAnimator; if (previousAnimator != null && previousEndValue == newEndValue) { return; } if (!animate) { // just a local update was performed if (previousAnimator != null) { // we need to increase all animation keyframes of the previous animator by the // relative change to the end value PropertyValuesHolder[] values = previousAnimator.getValues(); values[0].setIntValues(previousStartValue, newEndValue); mStartAnimationRect.bottom = previousStartValue; mEndAnimationRect.bottom = newEndValue; previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime()); return; } else { // no new animation needed, let's just apply the value setBackgroundBottom(newEndValue); return; } } if (previousAnimator != null) { previousAnimator.cancel(); } ObjectAnimator animator = ObjectAnimator.ofInt(this, "backgroundBottom", mCurrentBounds.bottom, newEndValue); Interpolator interpolator = Interpolators.FAST_OUT_SLOW_IN; animator.setInterpolator(interpolator); animator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); // remove the tag when the animation is finished animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mStartAnimationRect.bottom = -1; mEndAnimationRect.bottom = -1; mBottomAnimator = null; } }); animator.start(); mStartAnimationRect.bottom = mCurrentBounds.bottom; mEndAnimationRect.bottom = newEndValue; mBottomAnimator = animator; } @ShadeViewRefactor(ShadeViewRefactor.RefactorComponent.SHADE_VIEW) private void setBackgroundTop(int top) { mCurrentBounds.top = top; mOwningView.invalidate(); } @ShadeViewRefactor(ShadeViewRefactor.RefactorComponent.SHADE_VIEW) private void setBackgroundBottom(int bottom) { mCurrentBounds.bottom = bottom; mOwningView.invalidate(); } public ExpandableView getFirstVisibleChild() { return mFirstVisibleChild; } Loading @@ -66,4 +219,93 @@ public class NotificationSection { mLastVisibleChild = child; return changed; } public void resetCurrentBounds() { mCurrentBounds.set(mBounds); } /** * Returns true if {@code top} is equal to the top of this section (if not currently animating) * or where the top of this section will be when animation completes. */ public boolean isTargetTop(int top) { return (mTopAnimator == null && mCurrentBounds.top == top) || (mTopAnimator != null && mEndAnimationRect.top == top); } /** * Returns true if {@code bottom} is equal to the bottom of this section (if not currently * animating) or where the bottom of this section will be when animation completes. */ public boolean isTargetBottom(int bottom) { return (mBottomAnimator == null && mCurrentBounds.bottom == bottom) || (mBottomAnimator != null && mEndAnimationRect.bottom == bottom); } /** * Update the bounds of this section based on it's views * * @param minTopPosition the minimum position that the top needs to have * @param minBottomPosition the minimum position that the bottom needs to have * @return the position of the new bottom */ public int updateBounds(int minTopPosition, int minBottomPosition, boolean shiftBackgroundWithFirst) { int top = minTopPosition; int bottom = minTopPosition; ExpandableView firstView = getFirstVisibleChild(); if (firstView != null) { // Round Y up to avoid seeing the background during animation int finalTranslationY = (int) Math.ceil(ViewState.getFinalTranslationY(firstView)); // TODO: look into the already animating part int newTop; if (isTargetTop(finalTranslationY)) { // we're ending up at the same location as we are now, let's just skip the // animation newTop = finalTranslationY; } else { newTop = (int) Math.ceil(firstView.getTranslationY()); } top = Math.max(newTop, top); if (firstView.showingPulsing()) { // If we're pulsing, the notification can actually go below! bottom = Math.max(bottom, finalTranslationY + ExpandableViewState.getFinalActualHeight(firstView)); if (shiftBackgroundWithFirst) { mBounds.left += Math.max(firstView.getTranslation(), 0); mBounds.right += Math.min(firstView.getTranslation(), 0); } } } top = Math.max(minTopPosition, top); ExpandableView lastView = getLastVisibleChild(); if (lastView != null) { float finalTranslationY = ViewState.getFinalTranslationY(lastView); int finalHeight = ExpandableViewState.getFinalActualHeight(lastView); // Round Y down to avoid seeing the background during animation int finalBottom = (int) Math.floor( finalTranslationY + finalHeight - lastView.getClipBottomAmount()); int newBottom; if (isTargetBottom(finalBottom)) { // we're ending up at the same location as we are now, lets just skip the animation newBottom = finalBottom; } else { newBottom = (int) (lastView.getTranslationY() + lastView.getActualHeight() - lastView.getClipBottomAmount()); // The background can never be lower than the end of the last view minBottomPosition = (int) Math.min( lastView.getTranslationY() + lastView.getActualHeight(), minBottomPosition); } bottom = Math.max(bottom, Math.max(newBottom, minBottomPosition)); } bottom = Math.max(top, bottom); mBounds.top = top; mBounds.bottom = bottom; return bottom; } public boolean needsBackground() { return mFirstVisibleChild != null && mBucket != BUCKET_MEDIA_CONTROLS; } } packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt +1 −1 Original line number Diff line number Diff line Loading @@ -126,7 +126,7 @@ class NotificationSectionsManager @Inject internal constructor( fun createSectionsForBuckets(): Array<NotificationSection> = sectionsFeatureManager.getNotificationBuckets() .map { NotificationSection(it) } .map { NotificationSection(parent, it) } .toTypedArray() /** Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +394 −13 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
packages/SystemUI/res/values/config.xml +3 −0 Original line number Diff line number Diff line Loading @@ -357,6 +357,9 @@ the notification is not swiped enough to dismiss it. --> <bool name="config_showNotificationGear">true</bool> <!-- Whether or not a background should be drawn behind a notification. --> <bool name="config_drawNotificationBackground">true</bool> <!-- Whether or the notifications can be shown and dismissed with a drag. --> <bool name="config_enableNotificationShadeDrag">true</bool> Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java +18 −0 Original line number Diff line number Diff line Loading @@ -82,6 +82,9 @@ public class AmbientState { private ExpandableNotificationRow mTrackedHeadsUpRow; private float mAppearFraction; /** Tracks the state from AlertingNotificationManager#hasNotifications() */ private boolean mHasAlertEntries; public AmbientState( Context context, @NonNull SectionProvider sectionProvider) { Loading Loading @@ -365,10 +368,21 @@ public class AmbientState { mPanelTracking = panelTracking; } public boolean hasPulsingNotifications() { return mPulsing && mHasAlertEntries; } public void setPulsing(boolean hasPulsing) { mPulsing = hasPulsing; } /** * @return if we're pulsing in general */ public boolean isPulsing() { return mPulsing; } public boolean isPulsing(NotificationEntry entry) { return mPulsing && entry.isAlerting(); } Loading Loading @@ -527,4 +541,8 @@ public class AmbientState { public float getAppearFraction() { return mAppearFraction; } public void setHasAlertEntries(boolean hasAlertEntries) { mHasAlertEntries = hasAlertEntries; } }
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java +244 −2 Original line number Diff line number Diff line Loading @@ -31,22 +31,175 @@ import com.android.systemui.statusbar.notification.ShadeViewRefactor; import com.android.systemui.statusbar.notification.row.ExpandableView; /** * Represents the priority of a notification section and tracks first and last visible children. * Represents the bounds of a section of the notification shade and handles animation when the * bounds change. */ public class NotificationSection { private @PriorityBucket int mBucket; private View mOwningView; private Rect mBounds = new Rect(); private Rect mCurrentBounds = new Rect(-1, -1, -1, -1); private Rect mStartAnimationRect = new Rect(); private Rect mEndAnimationRect = new Rect(); private ObjectAnimator mTopAnimator = null; private ObjectAnimator mBottomAnimator = null; private ExpandableView mFirstVisibleChild; private ExpandableView mLastVisibleChild; NotificationSection(@PriorityBucket int bucket) { NotificationSection(View owningView, @PriorityBucket int bucket) { mOwningView = owningView; mBucket = bucket; } public void cancelAnimators() { if (mBottomAnimator != null) { mBottomAnimator.cancel(); } if (mTopAnimator != null) { mTopAnimator.cancel(); } } public Rect getCurrentBounds() { return mCurrentBounds; } public Rect getBounds() { return mBounds; } public boolean didBoundsChange() { return !mCurrentBounds.equals(mBounds); } public boolean areBoundsAnimating() { return mBottomAnimator != null || mTopAnimator != null; } @PriorityBucket public int getBucket() { return mBucket; } public void startBackgroundAnimation(boolean animateTop, boolean animateBottom) { // Left and right bounds are always applied immediately. mCurrentBounds.left = mBounds.left; mCurrentBounds.right = mBounds.right; startBottomAnimation(animateBottom); startTopAnimation(animateTop); } @ShadeViewRefactor(ShadeViewRefactor.RefactorComponent.STATE_RESOLVER) private void startTopAnimation(boolean animate) { int previousEndValue = mEndAnimationRect.top; int newEndValue = mBounds.top; ObjectAnimator previousAnimator = mTopAnimator; if (previousAnimator != null && previousEndValue == newEndValue) { return; } if (!animate) { // just a local update was performed if (previousAnimator != null) { // we need to increase all animation keyframes of the previous animator by the // relative change to the end value int previousStartValue = mStartAnimationRect.top; PropertyValuesHolder[] values = previousAnimator.getValues(); values[0].setIntValues(previousStartValue, newEndValue); mStartAnimationRect.top = previousStartValue; mEndAnimationRect.top = newEndValue; previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime()); return; } else { // no new animation needed, let's just apply the value setBackgroundTop(newEndValue); return; } } if (previousAnimator != null) { previousAnimator.cancel(); } ObjectAnimator animator = ObjectAnimator.ofInt(this, "backgroundTop", mCurrentBounds.top, newEndValue); Interpolator interpolator = Interpolators.FAST_OUT_SLOW_IN; animator.setInterpolator(interpolator); animator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); // remove the tag when the animation is finished animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mStartAnimationRect.top = -1; mEndAnimationRect.top = -1; mTopAnimator = null; } }); animator.start(); mStartAnimationRect.top = mCurrentBounds.top; mEndAnimationRect.top = newEndValue; mTopAnimator = animator; } @ShadeViewRefactor(ShadeViewRefactor.RefactorComponent.STATE_RESOLVER) private void startBottomAnimation(boolean animate) { int previousStartValue = mStartAnimationRect.bottom; int previousEndValue = mEndAnimationRect.bottom; int newEndValue = mBounds.bottom; ObjectAnimator previousAnimator = mBottomAnimator; if (previousAnimator != null && previousEndValue == newEndValue) { return; } if (!animate) { // just a local update was performed if (previousAnimator != null) { // we need to increase all animation keyframes of the previous animator by the // relative change to the end value PropertyValuesHolder[] values = previousAnimator.getValues(); values[0].setIntValues(previousStartValue, newEndValue); mStartAnimationRect.bottom = previousStartValue; mEndAnimationRect.bottom = newEndValue; previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime()); return; } else { // no new animation needed, let's just apply the value setBackgroundBottom(newEndValue); return; } } if (previousAnimator != null) { previousAnimator.cancel(); } ObjectAnimator animator = ObjectAnimator.ofInt(this, "backgroundBottom", mCurrentBounds.bottom, newEndValue); Interpolator interpolator = Interpolators.FAST_OUT_SLOW_IN; animator.setInterpolator(interpolator); animator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); // remove the tag when the animation is finished animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mStartAnimationRect.bottom = -1; mEndAnimationRect.bottom = -1; mBottomAnimator = null; } }); animator.start(); mStartAnimationRect.bottom = mCurrentBounds.bottom; mEndAnimationRect.bottom = newEndValue; mBottomAnimator = animator; } @ShadeViewRefactor(ShadeViewRefactor.RefactorComponent.SHADE_VIEW) private void setBackgroundTop(int top) { mCurrentBounds.top = top; mOwningView.invalidate(); } @ShadeViewRefactor(ShadeViewRefactor.RefactorComponent.SHADE_VIEW) private void setBackgroundBottom(int bottom) { mCurrentBounds.bottom = bottom; mOwningView.invalidate(); } public ExpandableView getFirstVisibleChild() { return mFirstVisibleChild; } Loading @@ -66,4 +219,93 @@ public class NotificationSection { mLastVisibleChild = child; return changed; } public void resetCurrentBounds() { mCurrentBounds.set(mBounds); } /** * Returns true if {@code top} is equal to the top of this section (if not currently animating) * or where the top of this section will be when animation completes. */ public boolean isTargetTop(int top) { return (mTopAnimator == null && mCurrentBounds.top == top) || (mTopAnimator != null && mEndAnimationRect.top == top); } /** * Returns true if {@code bottom} is equal to the bottom of this section (if not currently * animating) or where the bottom of this section will be when animation completes. */ public boolean isTargetBottom(int bottom) { return (mBottomAnimator == null && mCurrentBounds.bottom == bottom) || (mBottomAnimator != null && mEndAnimationRect.bottom == bottom); } /** * Update the bounds of this section based on it's views * * @param minTopPosition the minimum position that the top needs to have * @param minBottomPosition the minimum position that the bottom needs to have * @return the position of the new bottom */ public int updateBounds(int minTopPosition, int minBottomPosition, boolean shiftBackgroundWithFirst) { int top = minTopPosition; int bottom = minTopPosition; ExpandableView firstView = getFirstVisibleChild(); if (firstView != null) { // Round Y up to avoid seeing the background during animation int finalTranslationY = (int) Math.ceil(ViewState.getFinalTranslationY(firstView)); // TODO: look into the already animating part int newTop; if (isTargetTop(finalTranslationY)) { // we're ending up at the same location as we are now, let's just skip the // animation newTop = finalTranslationY; } else { newTop = (int) Math.ceil(firstView.getTranslationY()); } top = Math.max(newTop, top); if (firstView.showingPulsing()) { // If we're pulsing, the notification can actually go below! bottom = Math.max(bottom, finalTranslationY + ExpandableViewState.getFinalActualHeight(firstView)); if (shiftBackgroundWithFirst) { mBounds.left += Math.max(firstView.getTranslation(), 0); mBounds.right += Math.min(firstView.getTranslation(), 0); } } } top = Math.max(minTopPosition, top); ExpandableView lastView = getLastVisibleChild(); if (lastView != null) { float finalTranslationY = ViewState.getFinalTranslationY(lastView); int finalHeight = ExpandableViewState.getFinalActualHeight(lastView); // Round Y down to avoid seeing the background during animation int finalBottom = (int) Math.floor( finalTranslationY + finalHeight - lastView.getClipBottomAmount()); int newBottom; if (isTargetBottom(finalBottom)) { // we're ending up at the same location as we are now, lets just skip the animation newBottom = finalBottom; } else { newBottom = (int) (lastView.getTranslationY() + lastView.getActualHeight() - lastView.getClipBottomAmount()); // The background can never be lower than the end of the last view minBottomPosition = (int) Math.min( lastView.getTranslationY() + lastView.getActualHeight(), minBottomPosition); } bottom = Math.max(bottom, Math.max(newBottom, minBottomPosition)); } bottom = Math.max(top, bottom); mBounds.top = top; mBounds.bottom = bottom; return bottom; } public boolean needsBackground() { return mFirstVisibleChild != null && mBucket != BUCKET_MEDIA_CONTROLS; } }
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt +1 −1 Original line number Diff line number Diff line Loading @@ -126,7 +126,7 @@ class NotificationSectionsManager @Inject internal constructor( fun createSectionsForBuckets(): Array<NotificationSection> = sectionsFeatureManager.getNotificationBuckets() .map { NotificationSection(it) } .map { NotificationSection(parent, it) } .toTypedArray() /** Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +394 −13 File changed.Preview size limit exceeded, changes collapsed. Show changes