Loading packages/SystemUI/src/com/android/systemui/SwipeHelper.java +6 −0 Original line number Diff line number Diff line Loading @@ -451,6 +451,12 @@ public class SwipeHelper implements Gefingerpoken { anim.addListener(new AnimatorListenerAdapter() { private boolean mCancelled; @Override public void onAnimationStart(Animator animation) { super.onAnimationStart(animation); mCallback.onBeginDrag(animView); } @Override public void onAnimationCancel(Animator animation) { mCancelled = true; Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java +22 −15 Original line number Diff line number Diff line Loading @@ -85,23 +85,26 @@ public abstract class StackScrollerDecorView extends ExpandableView { } /** * Set the content of this view to be visible in an animated way. * * @param contentVisible True if the content should be visible or false if it should be hidden. * @param visible True if we should animate contents visible */ public void setContentVisible(boolean contentVisible) { setContentVisible(contentVisible, true /* animate */); public void setContentVisible(boolean visible) { setContentVisible(visible, true /* animate */, null /* runAfter */); } /** * Set the content of this view to be visible. * @param contentVisible True if the content should be visible or false if it should be hidden. * @param animate Should an animation be performed. * @param visible True if the contents should be visible * @param animate True if we should fade to new visibility * @param runAfter Runnable to run after visibility updates */ private void setContentVisible(boolean contentVisible, boolean animate) { if (mContentVisible != contentVisible) { public void setContentVisible(boolean visible, boolean animate, Runnable runAfter) { if (mContentVisible != visible) { mContentAnimating = animate; mContentVisible = contentVisible; setViewVisible(mContent, contentVisible, animate, mContentVisibilityEndRunnable); mContentVisible = visible; Runnable endRunnable = runAfter == null ? mContentVisibilityEndRunnable : () -> { mContentVisibilityEndRunnable.run(); runAfter.run(); }; setViewVisible(mContent, visible, animate, endRunnable); } if (!mContentAnimating) { Loading @@ -113,6 +116,10 @@ public abstract class StackScrollerDecorView extends ExpandableView { return mContentVisible; } public void setVisible(boolean nowVisible, boolean animate) { setVisible(nowVisible, animate, null); } /** * Make this view visible. If {@code false} is passed, the view will fade out it's content * and set the view Visibility to GONE. If only the content should be changed Loading @@ -121,7 +128,7 @@ public abstract class StackScrollerDecorView extends ExpandableView { * @param nowVisible should the view be visible * @param animate should the change be animated. */ public void setVisible(boolean nowVisible, boolean animate) { public void setVisible(boolean nowVisible, boolean animate, Runnable runAfter) { if (mIsVisible != nowVisible) { mIsVisible = nowVisible; if (animate) { Loading @@ -132,10 +139,10 @@ public abstract class StackScrollerDecorView extends ExpandableView { } else { setWillBeGone(true); } setContentVisible(nowVisible, true /* animate */); setContentVisible(nowVisible, true /* animate */, runAfter); } else { setVisibility(nowVisible ? VISIBLE : GONE); setContentVisible(nowVisible, false /* animate */); setContentVisible(nowVisible, false /* animate */, runAfter); setWillBeGone(false); notifyHeightChanged(false /* needsAnimation */); } Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java +10 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ public class NotificationRoundnessManager { private ExpandableNotificationRow mTrackedHeadsUp; private float mAppearFraction; private boolean mRoundForPulsingViews; private boolean mIsDismissAllInProgress; private ExpandableView mSwipedView = null; private ExpandableView mViewBeforeSwipedView = null; Loading Loading @@ -158,6 +159,10 @@ public class NotificationRoundnessManager { } } void setDismissAllInProgress(boolean isClearingAll) { mIsDismissAllInProgress = isClearingAll; } private float getRoundnessFraction(ExpandableView view, boolean top) { if (view == null) { return 0f; Loading @@ -167,6 +172,11 @@ public class NotificationRoundnessManager { || view == mViewAfterSwipedView) { return 1f; } if (view instanceof ExpandableNotificationRow && ((ExpandableNotificationRow) view).canViewBeDismissed() && mIsDismissAllInProgress) { return 1.0f; } if ((view.isPinned() || (view.isHeadsUpAnimatingAway()) && !mExpanded)) { return 1.0f; Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +124 −94 Original line number Diff line number Diff line Loading @@ -139,6 +139,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable private static final boolean DEBUG_REMOVE_ANIMATION = SystemProperties.getBoolean( "persist.debug.nssl.dismiss", false /* default */); // Delay in milli-seconds before shade closes for clear all. private final int DELAY_BEFORE_SHADE_CLOSE = 200; private boolean mShadeNeedsToClose = false; private static final float RUBBER_BAND_FACTOR_NORMAL = 0.35f; private static final float RUBBER_BAND_FACTOR_AFTER_EXPAND = 0.15f; private static final float RUBBER_BAND_FACTOR_ON_PANEL_EXPAND = 0.21f; Loading Loading @@ -253,7 +257,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable protected FooterView mFooterView; protected EmptyShadeView mEmptyShadeView; private boolean mDismissAllInProgress; private boolean mFadeNotificationsOnDismiss; private FooterDismissListener mFooterDismissListener; private boolean mFlingAfterUpEvent; Loading Loading @@ -1205,7 +1208,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable @ShadeViewRefactor(RefactorComponent.COORDINATOR) private void clampScrollPosition() { int scrollRange = getScrollRange(); if (scrollRange < mOwnScrollY) { if (scrollRange < mOwnScrollY && !mAmbientState.isDismissAllInProgress()) { boolean animateStackY = false; if (scrollRange < getScrollAmountToScrollBoundary() && mAnimateStackYForContentHeightChange) { Loading Loading @@ -1721,6 +1724,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) public void dismissViewAnimated(View child, Runnable endRunnable, int delay, long duration) { if (child instanceof SectionHeaderView) { ((StackScrollerDecorView) child).setContentVisible( false /* visible */, true /* animate */, endRunnable); return; } mSwipeHelper.dismissChild(child, 0, endRunnable, delay, true, duration, true /* isDismissAll */); } Loading Loading @@ -4062,6 +4070,18 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable runAnimationFinishedRunnables(); clearTransient(); clearHeadsUpDisappearRunning(); if (mAmbientState.isDismissAllInProgress()) { setDismissAllInProgress(false); if (mShadeNeedsToClose) { mShadeNeedsToClose = false; postDelayed( () -> { mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); }, DELAY_BEFORE_SHADE_CLOSE /* delayMillis */); } } } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) Loading Loading @@ -4430,6 +4450,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable public void setDismissAllInProgress(boolean dismissAllInProgress) { mDismissAllInProgress = dismissAllInProgress; mAmbientState.setDismissAllInProgress(dismissAllInProgress); mController.getNoticationRoundessManager().setDismissAllInProgress(dismissAllInProgress); handleDismissAllClipping(); } Loading Loading @@ -4973,129 +4994,137 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mHeadsUpAppearanceController = headsUpAppearanceController; } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) @VisibleForTesting void clearNotifications(@SelectedRows int selection, boolean closeShade) { // animate-swipe all dismissable notifications, then animate the shade closed int numChildren = getChildCount(); final ArrayList<View> viewsToHide = new ArrayList<>(numChildren); final ArrayList<ExpandableNotificationRow> viewsToRemove = new ArrayList<>(numChildren); for (int i = 0; i < numChildren; i++) { final View child = getChildAt(i); if (child instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) child; boolean parentVisible = false; private boolean isVisible(View child) { boolean hasClipBounds = child.getClipBounds(mTmpRect); if (includeChildInDismissAll(row, selection)) { viewsToRemove.add(row); if (child.getVisibility() == View.VISIBLE && (!hasClipBounds || mTmpRect.height() > 0)) { viewsToHide.add(child); parentVisible = true; return child.getVisibility() == View.VISIBLE && (!hasClipBounds || mTmpRect.height() > 0); } } else if (child.getVisibility() == View.VISIBLE && (!hasClipBounds || mTmpRect.height() > 0)) { parentVisible = true; private boolean shouldHideParent(View view, @SelectedRows int selection) { final boolean silentSectionWillBeGone = !mController.hasNotifications(ROWS_GENTLE, false /* clearable */); // The only SectionHeaderView we have is the silent section header. if (view instanceof SectionHeaderView && silentSectionWillBeGone) { return true; } List<ExpandableNotificationRow> children = row.getAttachedChildren(); if (children != null) { for (ExpandableNotificationRow childRow : children) { if (includeChildInDismissAll(row, selection)) { viewsToRemove.add(childRow); if (parentVisible && row.areChildrenExpanded()) { hasClipBounds = childRow.getClipBounds(mTmpRect); if (childRow.getVisibility() == View.VISIBLE && (!hasClipBounds || mTmpRect.height() > 0)) { viewsToHide.add(childRow); if (view instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) view; if (isVisible(row) && includeChildInDismissAll(row, selection)) { return true; } } return false; } private boolean isChildrenVisible(ExpandableNotificationRow parent) { List<ExpandableNotificationRow> children = parent.getAttachedChildren(); return isVisible(parent) && children != null && parent.areChildrenExpanded(); } // Similar to #getRowsToDismissInBackend, but filters for visible views. private ArrayList<View> getVisibleViewsToAnimateAway(@SelectedRows int selection) { final int viewCount = getChildCount(); final ArrayList<View> viewsToHide = new ArrayList<>(viewCount); for (int i = 0; i < viewCount; i++) { final View view = getChildAt(i); if (shouldHideParent(view, selection)) { viewsToHide.add(view); } if (view instanceof ExpandableNotificationRow) { ExpandableNotificationRow parent = (ExpandableNotificationRow) view; if (isChildrenVisible(parent)) { for (ExpandableNotificationRow child : parent.getAttachedChildren()) { if (isVisible(child) && includeChildInDismissAll(child, selection)) { viewsToHide.add(child); } } if (mDismissListener != null) { mDismissListener.onDismiss(selection); } if (viewsToRemove.isEmpty()) { if (closeShade && mShadeController != null) { mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); } return; } performDismissAllAnimations( viewsToHide, closeShade, () -> onDismissAllAnimationsEnd(viewsToRemove, selection)); return viewsToHide; } private boolean includeChildInDismissAll( ExpandableNotificationRow row, private ArrayList<ExpandableNotificationRow> getRowsToDismissInBackend( @SelectedRows int selection) { return canChildBeDismissed(row) && matchesSelection(row, selection); final int childCount = getChildCount(); final ArrayList<ExpandableNotificationRow> viewsToRemove = new ArrayList<>(childCount); for (int i = 0; i < childCount; i++) { final View view = getChildAt(i); if (!(view instanceof ExpandableNotificationRow)) { continue; } ExpandableNotificationRow parent = (ExpandableNotificationRow) view; if (includeChildInDismissAll(parent, selection)) { viewsToRemove.add(parent); } List<ExpandableNotificationRow> children = parent.getAttachedChildren(); if (isVisible(parent) && children != null) { for (ExpandableNotificationRow child : children) { if (includeChildInDismissAll(parent, selection)) { viewsToRemove.add(child); } } } } return viewsToRemove; } /** * Given a list of rows, animates them away in a staggered fashion as if they were dismissed. * Doesn't actually dismiss them, though -- that must be done in the onAnimationComplete * handler. * * @param hideAnimatedList List of rows to animated away. Should only be views that are * currently visible, or else the stagger will look funky. * @param closeShade Whether to close the shade after the stagger animation completes. * @param onAnimationComplete Called after the entire animation completes (including the shade * closing if appropriate). The rows must be dismissed for real here. * Collects a list of visible rows, and animates them away in a staggered fashion as if they * were dismissed. Notifications are dismissed in the backend via onDismissAllAnimationsEnd. */ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) private void performDismissAllAnimations( final ArrayList<View> hideAnimatedList, final boolean closeShade, final Runnable onAnimationComplete) { final Runnable onSlideAwayAnimationComplete = () -> { if (closeShade) { mShadeController.addPostCollapseAction(() -> { setDismissAllInProgress(false); onAnimationComplete.run(); }); mShadeController.animateCollapsePanels( CommandQueue.FLAG_EXCLUDE_NONE); } else { setDismissAllInProgress(false); onAnimationComplete.run(); @VisibleForTesting void clearNotifications(@SelectedRows int selection, boolean closeShade) { // Animate-swipe all dismissable notifications, then animate the shade closed final ArrayList<View> viewsToAnimateAway = getVisibleViewsToAnimateAway(selection); final ArrayList<ExpandableNotificationRow> rowsToDismissInBackend = getRowsToDismissInBackend(selection); if (mDismissListener != null) { mDismissListener.onDismiss(selection); } final Runnable dismissInBackend = () -> { onDismissAllAnimationsEnd(rowsToDismissInBackend, selection); }; if (hideAnimatedList.isEmpty()) { onSlideAwayAnimationComplete.run(); if (viewsToAnimateAway.isEmpty()) { dismissInBackend.run(); return; } // let's disable our normal animations // Disable normal animations setDismissAllInProgress(true); mShadeNeedsToClose = closeShade; // Decrease the delay for every row we animate to give the sense of // accelerating the swipes int rowDelayDecrement = 10; int currentDelay = 140; int totalDelay = 180; int numItems = hideAnimatedList.size(); final int rowDelayDecrement = 5; int currentDelay = 60; int totalDelay = 0; final int numItems = viewsToAnimateAway.size(); for (int i = numItems - 1; i >= 0; i--) { View view = hideAnimatedList.get(i); View view = viewsToAnimateAway.get(i); Runnable endRunnable = null; if (i == 0) { endRunnable = onSlideAwayAnimationComplete; endRunnable = dismissInBackend; } dismissViewAnimated(view, endRunnable, totalDelay, ANIMATION_DURATION_SWIPE); currentDelay = Math.max(50, currentDelay - rowDelayDecrement); currentDelay = Math.max(30, currentDelay - rowDelayDecrement); totalDelay += currentDelay; } } private boolean includeChildInDismissAll( ExpandableNotificationRow row, @SelectedRows int selection) { return canChildBeDismissed(row) && matchesSelection(row, selection); } /** Register a {@link View.OnClickListener} to be invoked when the Manage button is clicked. */ public void setManageButtonClickListener(@Nullable OnClickListener listener) { mManageButtonClickListener = listener; Loading @@ -5114,6 +5143,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mFooterDismissListener.onDismiss(); } clearNotifications(ROWS_ALL, true /* closeShade */); footerView.setSecondaryVisible(false /* visible */, true /* animate */); }); setFooterView(footerView); } Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +13 −2 Original line number Diff line number Diff line Loading @@ -1157,6 +1157,10 @@ public class NotificationStackScrollLayoutController { mZenModeController.areNotificationsHiddenInShade()); } public boolean areNotificationsHiddenInShade() { return mZenModeController.areNotificationsHiddenInShade(); } public boolean isShowingEmptyShadeView() { return mShowEmptyShadeView; } Loading Loading @@ -1205,6 +1209,10 @@ public class NotificationStackScrollLayoutController { * Return whether there are any clearable notifications */ public boolean hasActiveClearableNotifications(@SelectedRows int selection) { return hasNotifications(selection, true /* clearable */); } public boolean hasNotifications(@SelectedRows int selection, boolean isClearable) { if (mDynamicPrivacyController.isInLockedDownShade()) { return false; } Loading @@ -1215,8 +1223,11 @@ public class NotificationStackScrollLayoutController { continue; } final ExpandableNotificationRow row = (ExpandableNotificationRow) child; if (row.canViewBeDismissed() && NotificationStackScrollLayout.matchesSelection(row, selection)) { final boolean matchClearable = isClearable ? row.canViewBeDismissed() : !row.canViewBeDismissed(); final boolean inSection = NotificationStackScrollLayout.matchesSelection(row, selection); if (matchClearable && inSection) { return true; } } Loading Loading
packages/SystemUI/src/com/android/systemui/SwipeHelper.java +6 −0 Original line number Diff line number Diff line Loading @@ -451,6 +451,12 @@ public class SwipeHelper implements Gefingerpoken { anim.addListener(new AnimatorListenerAdapter() { private boolean mCancelled; @Override public void onAnimationStart(Animator animation) { super.onAnimationStart(animation); mCallback.onBeginDrag(animView); } @Override public void onAnimationCancel(Animator animation) { mCancelled = true; Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java +22 −15 Original line number Diff line number Diff line Loading @@ -85,23 +85,26 @@ public abstract class StackScrollerDecorView extends ExpandableView { } /** * Set the content of this view to be visible in an animated way. * * @param contentVisible True if the content should be visible or false if it should be hidden. * @param visible True if we should animate contents visible */ public void setContentVisible(boolean contentVisible) { setContentVisible(contentVisible, true /* animate */); public void setContentVisible(boolean visible) { setContentVisible(visible, true /* animate */, null /* runAfter */); } /** * Set the content of this view to be visible. * @param contentVisible True if the content should be visible or false if it should be hidden. * @param animate Should an animation be performed. * @param visible True if the contents should be visible * @param animate True if we should fade to new visibility * @param runAfter Runnable to run after visibility updates */ private void setContentVisible(boolean contentVisible, boolean animate) { if (mContentVisible != contentVisible) { public void setContentVisible(boolean visible, boolean animate, Runnable runAfter) { if (mContentVisible != visible) { mContentAnimating = animate; mContentVisible = contentVisible; setViewVisible(mContent, contentVisible, animate, mContentVisibilityEndRunnable); mContentVisible = visible; Runnable endRunnable = runAfter == null ? mContentVisibilityEndRunnable : () -> { mContentVisibilityEndRunnable.run(); runAfter.run(); }; setViewVisible(mContent, visible, animate, endRunnable); } if (!mContentAnimating) { Loading @@ -113,6 +116,10 @@ public abstract class StackScrollerDecorView extends ExpandableView { return mContentVisible; } public void setVisible(boolean nowVisible, boolean animate) { setVisible(nowVisible, animate, null); } /** * Make this view visible. If {@code false} is passed, the view will fade out it's content * and set the view Visibility to GONE. If only the content should be changed Loading @@ -121,7 +128,7 @@ public abstract class StackScrollerDecorView extends ExpandableView { * @param nowVisible should the view be visible * @param animate should the change be animated. */ public void setVisible(boolean nowVisible, boolean animate) { public void setVisible(boolean nowVisible, boolean animate, Runnable runAfter) { if (mIsVisible != nowVisible) { mIsVisible = nowVisible; if (animate) { Loading @@ -132,10 +139,10 @@ public abstract class StackScrollerDecorView extends ExpandableView { } else { setWillBeGone(true); } setContentVisible(nowVisible, true /* animate */); setContentVisible(nowVisible, true /* animate */, runAfter); } else { setVisibility(nowVisible ? VISIBLE : GONE); setContentVisible(nowVisible, false /* animate */); setContentVisible(nowVisible, false /* animate */, runAfter); setWillBeGone(false); notifyHeightChanged(false /* needsAnimation */); } Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java +10 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ public class NotificationRoundnessManager { private ExpandableNotificationRow mTrackedHeadsUp; private float mAppearFraction; private boolean mRoundForPulsingViews; private boolean mIsDismissAllInProgress; private ExpandableView mSwipedView = null; private ExpandableView mViewBeforeSwipedView = null; Loading Loading @@ -158,6 +159,10 @@ public class NotificationRoundnessManager { } } void setDismissAllInProgress(boolean isClearingAll) { mIsDismissAllInProgress = isClearingAll; } private float getRoundnessFraction(ExpandableView view, boolean top) { if (view == null) { return 0f; Loading @@ -167,6 +172,11 @@ public class NotificationRoundnessManager { || view == mViewAfterSwipedView) { return 1f; } if (view instanceof ExpandableNotificationRow && ((ExpandableNotificationRow) view).canViewBeDismissed() && mIsDismissAllInProgress) { return 1.0f; } if ((view.isPinned() || (view.isHeadsUpAnimatingAway()) && !mExpanded)) { return 1.0f; Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +124 −94 Original line number Diff line number Diff line Loading @@ -139,6 +139,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable private static final boolean DEBUG_REMOVE_ANIMATION = SystemProperties.getBoolean( "persist.debug.nssl.dismiss", false /* default */); // Delay in milli-seconds before shade closes for clear all. private final int DELAY_BEFORE_SHADE_CLOSE = 200; private boolean mShadeNeedsToClose = false; private static final float RUBBER_BAND_FACTOR_NORMAL = 0.35f; private static final float RUBBER_BAND_FACTOR_AFTER_EXPAND = 0.15f; private static final float RUBBER_BAND_FACTOR_ON_PANEL_EXPAND = 0.21f; Loading Loading @@ -253,7 +257,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable protected FooterView mFooterView; protected EmptyShadeView mEmptyShadeView; private boolean mDismissAllInProgress; private boolean mFadeNotificationsOnDismiss; private FooterDismissListener mFooterDismissListener; private boolean mFlingAfterUpEvent; Loading Loading @@ -1205,7 +1208,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable @ShadeViewRefactor(RefactorComponent.COORDINATOR) private void clampScrollPosition() { int scrollRange = getScrollRange(); if (scrollRange < mOwnScrollY) { if (scrollRange < mOwnScrollY && !mAmbientState.isDismissAllInProgress()) { boolean animateStackY = false; if (scrollRange < getScrollAmountToScrollBoundary() && mAnimateStackYForContentHeightChange) { Loading Loading @@ -1721,6 +1724,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) public void dismissViewAnimated(View child, Runnable endRunnable, int delay, long duration) { if (child instanceof SectionHeaderView) { ((StackScrollerDecorView) child).setContentVisible( false /* visible */, true /* animate */, endRunnable); return; } mSwipeHelper.dismissChild(child, 0, endRunnable, delay, true, duration, true /* isDismissAll */); } Loading Loading @@ -4062,6 +4070,18 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable runAnimationFinishedRunnables(); clearTransient(); clearHeadsUpDisappearRunning(); if (mAmbientState.isDismissAllInProgress()) { setDismissAllInProgress(false); if (mShadeNeedsToClose) { mShadeNeedsToClose = false; postDelayed( () -> { mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); }, DELAY_BEFORE_SHADE_CLOSE /* delayMillis */); } } } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) Loading Loading @@ -4430,6 +4450,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable public void setDismissAllInProgress(boolean dismissAllInProgress) { mDismissAllInProgress = dismissAllInProgress; mAmbientState.setDismissAllInProgress(dismissAllInProgress); mController.getNoticationRoundessManager().setDismissAllInProgress(dismissAllInProgress); handleDismissAllClipping(); } Loading Loading @@ -4973,129 +4994,137 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mHeadsUpAppearanceController = headsUpAppearanceController; } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) @VisibleForTesting void clearNotifications(@SelectedRows int selection, boolean closeShade) { // animate-swipe all dismissable notifications, then animate the shade closed int numChildren = getChildCount(); final ArrayList<View> viewsToHide = new ArrayList<>(numChildren); final ArrayList<ExpandableNotificationRow> viewsToRemove = new ArrayList<>(numChildren); for (int i = 0; i < numChildren; i++) { final View child = getChildAt(i); if (child instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) child; boolean parentVisible = false; private boolean isVisible(View child) { boolean hasClipBounds = child.getClipBounds(mTmpRect); if (includeChildInDismissAll(row, selection)) { viewsToRemove.add(row); if (child.getVisibility() == View.VISIBLE && (!hasClipBounds || mTmpRect.height() > 0)) { viewsToHide.add(child); parentVisible = true; return child.getVisibility() == View.VISIBLE && (!hasClipBounds || mTmpRect.height() > 0); } } else if (child.getVisibility() == View.VISIBLE && (!hasClipBounds || mTmpRect.height() > 0)) { parentVisible = true; private boolean shouldHideParent(View view, @SelectedRows int selection) { final boolean silentSectionWillBeGone = !mController.hasNotifications(ROWS_GENTLE, false /* clearable */); // The only SectionHeaderView we have is the silent section header. if (view instanceof SectionHeaderView && silentSectionWillBeGone) { return true; } List<ExpandableNotificationRow> children = row.getAttachedChildren(); if (children != null) { for (ExpandableNotificationRow childRow : children) { if (includeChildInDismissAll(row, selection)) { viewsToRemove.add(childRow); if (parentVisible && row.areChildrenExpanded()) { hasClipBounds = childRow.getClipBounds(mTmpRect); if (childRow.getVisibility() == View.VISIBLE && (!hasClipBounds || mTmpRect.height() > 0)) { viewsToHide.add(childRow); if (view instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) view; if (isVisible(row) && includeChildInDismissAll(row, selection)) { return true; } } return false; } private boolean isChildrenVisible(ExpandableNotificationRow parent) { List<ExpandableNotificationRow> children = parent.getAttachedChildren(); return isVisible(parent) && children != null && parent.areChildrenExpanded(); } // Similar to #getRowsToDismissInBackend, but filters for visible views. private ArrayList<View> getVisibleViewsToAnimateAway(@SelectedRows int selection) { final int viewCount = getChildCount(); final ArrayList<View> viewsToHide = new ArrayList<>(viewCount); for (int i = 0; i < viewCount; i++) { final View view = getChildAt(i); if (shouldHideParent(view, selection)) { viewsToHide.add(view); } if (view instanceof ExpandableNotificationRow) { ExpandableNotificationRow parent = (ExpandableNotificationRow) view; if (isChildrenVisible(parent)) { for (ExpandableNotificationRow child : parent.getAttachedChildren()) { if (isVisible(child) && includeChildInDismissAll(child, selection)) { viewsToHide.add(child); } } if (mDismissListener != null) { mDismissListener.onDismiss(selection); } if (viewsToRemove.isEmpty()) { if (closeShade && mShadeController != null) { mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); } return; } performDismissAllAnimations( viewsToHide, closeShade, () -> onDismissAllAnimationsEnd(viewsToRemove, selection)); return viewsToHide; } private boolean includeChildInDismissAll( ExpandableNotificationRow row, private ArrayList<ExpandableNotificationRow> getRowsToDismissInBackend( @SelectedRows int selection) { return canChildBeDismissed(row) && matchesSelection(row, selection); final int childCount = getChildCount(); final ArrayList<ExpandableNotificationRow> viewsToRemove = new ArrayList<>(childCount); for (int i = 0; i < childCount; i++) { final View view = getChildAt(i); if (!(view instanceof ExpandableNotificationRow)) { continue; } ExpandableNotificationRow parent = (ExpandableNotificationRow) view; if (includeChildInDismissAll(parent, selection)) { viewsToRemove.add(parent); } List<ExpandableNotificationRow> children = parent.getAttachedChildren(); if (isVisible(parent) && children != null) { for (ExpandableNotificationRow child : children) { if (includeChildInDismissAll(parent, selection)) { viewsToRemove.add(child); } } } } return viewsToRemove; } /** * Given a list of rows, animates them away in a staggered fashion as if they were dismissed. * Doesn't actually dismiss them, though -- that must be done in the onAnimationComplete * handler. * * @param hideAnimatedList List of rows to animated away. Should only be views that are * currently visible, or else the stagger will look funky. * @param closeShade Whether to close the shade after the stagger animation completes. * @param onAnimationComplete Called after the entire animation completes (including the shade * closing if appropriate). The rows must be dismissed for real here. * Collects a list of visible rows, and animates them away in a staggered fashion as if they * were dismissed. Notifications are dismissed in the backend via onDismissAllAnimationsEnd. */ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) private void performDismissAllAnimations( final ArrayList<View> hideAnimatedList, final boolean closeShade, final Runnable onAnimationComplete) { final Runnable onSlideAwayAnimationComplete = () -> { if (closeShade) { mShadeController.addPostCollapseAction(() -> { setDismissAllInProgress(false); onAnimationComplete.run(); }); mShadeController.animateCollapsePanels( CommandQueue.FLAG_EXCLUDE_NONE); } else { setDismissAllInProgress(false); onAnimationComplete.run(); @VisibleForTesting void clearNotifications(@SelectedRows int selection, boolean closeShade) { // Animate-swipe all dismissable notifications, then animate the shade closed final ArrayList<View> viewsToAnimateAway = getVisibleViewsToAnimateAway(selection); final ArrayList<ExpandableNotificationRow> rowsToDismissInBackend = getRowsToDismissInBackend(selection); if (mDismissListener != null) { mDismissListener.onDismiss(selection); } final Runnable dismissInBackend = () -> { onDismissAllAnimationsEnd(rowsToDismissInBackend, selection); }; if (hideAnimatedList.isEmpty()) { onSlideAwayAnimationComplete.run(); if (viewsToAnimateAway.isEmpty()) { dismissInBackend.run(); return; } // let's disable our normal animations // Disable normal animations setDismissAllInProgress(true); mShadeNeedsToClose = closeShade; // Decrease the delay for every row we animate to give the sense of // accelerating the swipes int rowDelayDecrement = 10; int currentDelay = 140; int totalDelay = 180; int numItems = hideAnimatedList.size(); final int rowDelayDecrement = 5; int currentDelay = 60; int totalDelay = 0; final int numItems = viewsToAnimateAway.size(); for (int i = numItems - 1; i >= 0; i--) { View view = hideAnimatedList.get(i); View view = viewsToAnimateAway.get(i); Runnable endRunnable = null; if (i == 0) { endRunnable = onSlideAwayAnimationComplete; endRunnable = dismissInBackend; } dismissViewAnimated(view, endRunnable, totalDelay, ANIMATION_DURATION_SWIPE); currentDelay = Math.max(50, currentDelay - rowDelayDecrement); currentDelay = Math.max(30, currentDelay - rowDelayDecrement); totalDelay += currentDelay; } } private boolean includeChildInDismissAll( ExpandableNotificationRow row, @SelectedRows int selection) { return canChildBeDismissed(row) && matchesSelection(row, selection); } /** Register a {@link View.OnClickListener} to be invoked when the Manage button is clicked. */ public void setManageButtonClickListener(@Nullable OnClickListener listener) { mManageButtonClickListener = listener; Loading @@ -5114,6 +5143,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mFooterDismissListener.onDismiss(); } clearNotifications(ROWS_ALL, true /* closeShade */); footerView.setSecondaryVisible(false /* visible */, true /* animate */); }); setFooterView(footerView); } Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +13 −2 Original line number Diff line number Diff line Loading @@ -1157,6 +1157,10 @@ public class NotificationStackScrollLayoutController { mZenModeController.areNotificationsHiddenInShade()); } public boolean areNotificationsHiddenInShade() { return mZenModeController.areNotificationsHiddenInShade(); } public boolean isShowingEmptyShadeView() { return mShowEmptyShadeView; } Loading Loading @@ -1205,6 +1209,10 @@ public class NotificationStackScrollLayoutController { * Return whether there are any clearable notifications */ public boolean hasActiveClearableNotifications(@SelectedRows int selection) { return hasNotifications(selection, true /* clearable */); } public boolean hasNotifications(@SelectedRows int selection, boolean isClearable) { if (mDynamicPrivacyController.isInLockedDownShade()) { return false; } Loading @@ -1215,8 +1223,11 @@ public class NotificationStackScrollLayoutController { continue; } final ExpandableNotificationRow row = (ExpandableNotificationRow) child; if (row.canViewBeDismissed() && NotificationStackScrollLayout.matchesSelection(row, selection)) { final boolean matchClearable = isClearable ? row.canViewBeDismissed() : !row.canViewBeDismissed(); final boolean inSection = NotificationStackScrollLayout.matchesSelection(row, selection); if (matchClearable && inSection) { return true; } } Loading