Loading packages/SystemUI/res/drawable-night/status_bar_notification_section_header_clear_btn.xml 0 → 100644 +25 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- ~ Copyright (C) 2019 The Android Open Source Project ~ ~ Licensed under the Apache License, Version 2.0 (the "License"); ~ you may not use this file except in compliance with the License. ~ You may obtain a copy of the License at ~ ~ http://www.apache.org/licenses/LICENSE-2.0 ~ ~ Unless required by applicable law or agreed to in writing, software ~ distributed under the License is distributed on an "AS IS" BASIS, ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ~ See the License for the specific language governing permissions and ~ limitations under the License --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="40dp" android:height="40dp" android:viewportWidth="40" android:viewportHeight="40"> <path android:fillColor="#9AA0A6" android:pathData="M24.6667 16.2733L23.7267 15.3333L20 19.06L16.2734 15.3333L15.3334 16.2733L19.06 20L15.3334 23.7266L16.2734 24.6666L20 20.94L23.7267 24.6666L24.6667 23.7266L20.94 20L24.6667 16.2733Z"/> </vector> packages/SystemUI/res/drawable/status_bar_notification_section_header_clear_btn.xml 0 → 100644 +25 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2019 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="40dp" android:height="40dp" android:viewportWidth="40" android:viewportHeight="40"> <path android:fillColor="#5F6368" android:pathData="M24.6667 16.2733L23.7267 15.3333L20 19.06L16.2734 15.3333L15.3334 16.2733L19.06 20L15.3334 23.7267L16.2734 24.6667L20 20.94L23.7267 24.6667L24.6667 23.7267L20.94 20L24.6667 16.2733Z"/> </vector> packages/SystemUI/res/layout/status_bar_notification_section_header.xml +2 −1 Original line number Diff line number Diff line Loading @@ -50,9 +50,10 @@ /> <ImageView android:id="@+id/btn_clear_all" android:visibility="gone" android:layout_width="@dimen/notification_section_header_height" android:layout_height="@dimen/notification_section_header_height" android:layout_marginRight="4dp" android:src="@drawable/status_bar_notification_section_header_clear_btn" android:contentDescription="@string/accessibility_notification_section_header_gentle_clear_all" /> </LinearLayout> Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java +18 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.notification.stack; import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE; import android.annotation.Nullable; import android.content.Context; import android.content.Intent; Loading @@ -42,6 +44,7 @@ class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvide private SectionHeaderView mGentleHeader; private boolean mGentleHeaderVisible = false; @Nullable private View.OnClickListener mOnClearGentleNotifsClickListener; NotificationSectionsManager( NotificationStackScrollLayout parent, Loading Loading @@ -70,12 +73,18 @@ class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvide mGentleHeader = (SectionHeaderView) LayoutInflater.from(context).inflate( R.layout.status_bar_notification_section_header, mParent, false); mGentleHeader.setOnHeaderClickListener(this::onGentleHeaderClick); mGentleHeader.setOnClearAllClickListener(this::onClearGentleNotifsClick); if (oldPos != -1) { mParent.addView(mGentleHeader, oldPos); } } /** Listener for when the "clear all" buttton is clciked on the gentle notification header. */ void setOnClearGentleNotifsClickListener(View.OnClickListener listener) { mOnClearGentleNotifsClickListener = listener; } /** Must be called whenever the UI mode changes (i.e. when we enter night mode). */ void onUiModeChanged() { mGentleHeader.onUiModeChanged(); Loading Loading @@ -111,6 +120,9 @@ class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvide } adjustGentleHeaderVisibilityAndPosition(firstGentleNotifIndex); mGentleHeader.setAreThereDismissableGentleNotifs( mParent.hasActiveClearableNotifications(ROWS_GENTLE)); } private void adjustGentleHeaderVisibilityAndPosition(int firstGentleNotifIndex) { Loading Loading @@ -225,4 +237,10 @@ class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvide true, Intent.FLAG_ACTIVITY_SINGLE_TOP); } private void onClearGentleNotifsClick(View v) { if (mOnClearGentleNotifsClickListener != null) { mOnClearGentleNotifsClickListener.onClick(v); } } } packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +113 −35 Original line number Diff line number Diff line Loading @@ -23,10 +23,13 @@ import static com.android.systemui.statusbar.notification.stack.StackStateAnimat import static com.android.systemui.statusbar.phone.NotificationIconAreaController.LOW_PRIORITY; import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT; import static java.lang.annotation.RetentionPolicy.SOURCE; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.TimeAnimator; import android.animation.ValueAnimator; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.WallpaperManager; Loading Loading @@ -143,6 +146,7 @@ import com.android.systemui.tuner.TunerService; import java.io.FileDescriptor; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; Loading Loading @@ -525,12 +529,19 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } mAmbientPulseManager = ambientPulseManager; mSectionsManager = new NotificationSectionsManager( this, activityStarter, NotificationUtils.useNewInterruptionModel(context)); mSectionsManager.inflateViews(context); mSectionsManager.setOnClearGentleNotifsClickListener(v -> { // Leave the shade open if there will be other notifs left over to clear final boolean closeShade = !hasActiveClearableNotifications(ROWS_HIGH_PRIORITY); clearNotifications(ROWS_GENTLE, closeShade); }); mAmbientState = new AmbientState(context, mSectionsManager); mRoundnessManager = notificationRoundnessManager; mBgColor = context.getColor(R.color.notification_shade_background_color); Loading Loading @@ -672,7 +683,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @VisibleForTesting @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public void updateFooter() { boolean showDismissView = mClearAllEnabled && hasActiveClearableNotifications(); boolean showDismissView = mClearAllEnabled && hasActiveClearableNotifications(ROWS_ALL); boolean showFooterView = (showDismissView || mEntryManager.getNotificationData().getActiveNotifications().size() != 0) && mStatusBarState != StatusBarState.KEYGUARD Loading @@ -685,14 +696,15 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd * Return whether there are any clearable notifications */ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public boolean hasActiveClearableNotifications() { public boolean hasActiveClearableNotifications(@SelectedRows int selection) { int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View child = getChildAt(i); if (!(child instanceof ExpandableNotificationRow)) { continue; } if (((ExpandableNotificationRow) child).canViewBeDismissed()) { final ExpandableNotificationRow row = (ExpandableNotificationRow) child; if (row.canViewBeDismissed() && matchesSelection(row, selection)) { return true; } } Loading Loading @@ -1695,11 +1707,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd return mScrollingEnabled; } @ShadeViewRefactor(RefactorComponent.ADAPTER) private boolean canChildBeDismissed(View v) { return StackScrollAlgorithm.canChildBeDismissed(v); } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) private boolean onKeyguard() { return mStatusBarState == StatusBarState.KEYGUARD; Loading Loading @@ -4917,7 +4924,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } else { child.setMinClipTopAmount(0); } previousChildWillBeDismissed = canChildBeDismissed(child); previousChildWillBeDismissed = StackScrollAlgorithm.canChildBeDismissed(child); } } Loading Loading @@ -5473,7 +5480,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) private void clearAllNotifications() { private void clearNotifications( @SelectedRows int selection, boolean closeShade) { // animate-swipe all dismissable notifications, then animate the shade closed int numChildren = getChildCount(); Loading @@ -5485,7 +5494,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd ExpandableNotificationRow row = (ExpandableNotificationRow) child; boolean parentVisible = false; boolean hasClipBounds = child.getClipBounds(mTmpRect); if (canChildBeDismissed(child)) { if (includeChildInDismissAll(row, selection)) { viewsToRemove.add(row); if (child.getVisibility() == View.VISIBLE && (!hasClipBounds || mTmpRect.height() > 0)) { Loading @@ -5499,9 +5508,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd List<ExpandableNotificationRow> children = row.getNotificationChildren(); if (children != null) { for (ExpandableNotificationRow childRow : children) { if (includeChildInDismissAll(row, selection)) { viewsToRemove.add(childRow); if (parentVisible && row.areChildrenExpanded() && canChildBeDismissed(childRow)) { if (parentVisible && row.areChildrenExpanded()) { hasClipBounds = childRow.getClipBounds(mTmpRect); if (childRow.getVisibility() == View.VISIBLE && (!hasClipBounds || mTmpRect.height() > 0)) { Loading @@ -5512,38 +5521,81 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } } } } if (viewsToRemove.isEmpty()) { if (closeShade) { mStatusBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); } return; } mShadeController.addPostCollapseAction(() -> { setDismissAllInProgress(false); performDismissAllAnimations(viewsToHide, closeShade, () -> { for (ExpandableNotificationRow rowToRemove : viewsToRemove) { if (canChildBeDismissed(rowToRemove)) { mEntryManager.removeNotification(rowToRemove.getEntry().key, null /* ranking */, if (StackScrollAlgorithm.canChildBeDismissed(rowToRemove)) { if (selection == ROWS_ALL) { // TODO: This is a listener method; we shouldn't be calling it. Can we just // call performRemoveNotification as below? mEntryManager.removeNotification( rowToRemove.getEntry().key, null /* ranking */, NotificationListenerService.REASON_CANCEL_ALL); } else { mEntryManager.performRemoveNotification( rowToRemove.getEntry().notification, NotificationListenerService.REASON_CANCEL_ALL); } } else { rowToRemove.resetTranslation(); } } if (selection == ROWS_ALL) { try { mBarService.onClearAllNotifications(mLockscreenUserManager.getCurrentUserId()); } catch (Exception ex) { } } }); } performDismissAllAnimations(viewsToHide); private boolean includeChildInDismissAll( ExpandableNotificationRow row, @SelectedRows int selection) { return StackScrollAlgorithm.canChildBeDismissed(row) && matchesSelection(row, selection); } /** * 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. */ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public void performDismissAllAnimations(ArrayList<View> hideAnimatedList) { Runnable animationFinishAction = () -> { private void performDismissAllAnimations( final ArrayList<View> hideAnimatedList, final boolean closeShade, final Runnable onAnimationComplete) { final Runnable onSlideAwayAnimationComplete = () -> { if (closeShade) { mShadeController.addPostCollapseAction(() -> { setDismissAllInProgress(false); onAnimationComplete.run(); }); mStatusBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); } else { setDismissAllInProgress(false); onAnimationComplete.run(); } }; if (hideAnimatedList.isEmpty()) { animationFinishAction.run(); onSlideAwayAnimationComplete.run(); return; } Loading @@ -5560,7 +5612,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd View view = hideAnimatedList.get(i); Runnable endRunnable = null; if (i == 0) { endRunnable = animationFinishAction; endRunnable = onSlideAwayAnimationComplete; } dismissViewAnimated(view, endRunnable, totalDelay, ANIMATION_DURATION_SWIPE); currentDelay = Math.max(50, currentDelay - rowDelayDecrement); Loading @@ -5575,7 +5627,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd R.layout.status_bar_notification_footer, this, false); footerView.setDismissButtonClickListener(v -> { mMetricsLogger.action(MetricsEvent.ACTION_DISMISS_ALL_NOTES); clearAllNotifications(); clearNotifications(ROWS_ALL, true /* closeShade */); }); footerView.setManageButtonClickListener(this::manageNotifications); setFooterView(footerView); Loading Loading @@ -5782,6 +5834,21 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd mSwipeHelper.resetExposedMenuView(animate, force); } private static boolean matchesSelection( ExpandableNotificationRow row, @SelectedRows int selection) { switch (selection) { case ROWS_ALL: return true; case ROWS_HIGH_PRIORITY: return row.getEntry().isHighPriority(); case ROWS_GENTLE: return !row.getEntry().isHighPriority(); default: throw new IllegalArgumentException("Unknown selection: " + selection); } } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) static class AnimationEvent { Loading Loading @@ -6266,7 +6333,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @Override public boolean canChildBeDismissed(View v) { return NotificationStackScrollLayout.this.canChildBeDismissed(v); return StackScrollAlgorithm.canChildBeDismissed(v); } @Override Loading Loading @@ -6473,4 +6540,15 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd public ExpandHelper.Callback getExpandHelperCallback() { return mExpandHelperCallback; } /** Enum for selecting some or all notification rows (does not included non-notif views). */ @Retention(SOURCE) @IntDef({ROWS_ALL, ROWS_HIGH_PRIORITY, ROWS_GENTLE}) public @interface SelectedRows {} /** All rows representing notifs. */ public static final int ROWS_ALL = 0; /** Only rows where entry.isHighPriority() is true. */ public static final int ROWS_HIGH_PRIORITY = 1; /** Only rows where entry.isHighPriority() is false. */ public static final int ROWS_GENTLE = 2; } Loading
packages/SystemUI/res/drawable-night/status_bar_notification_section_header_clear_btn.xml 0 → 100644 +25 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- ~ Copyright (C) 2019 The Android Open Source Project ~ ~ Licensed under the Apache License, Version 2.0 (the "License"); ~ you may not use this file except in compliance with the License. ~ You may obtain a copy of the License at ~ ~ http://www.apache.org/licenses/LICENSE-2.0 ~ ~ Unless required by applicable law or agreed to in writing, software ~ distributed under the License is distributed on an "AS IS" BASIS, ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ~ See the License for the specific language governing permissions and ~ limitations under the License --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="40dp" android:height="40dp" android:viewportWidth="40" android:viewportHeight="40"> <path android:fillColor="#9AA0A6" android:pathData="M24.6667 16.2733L23.7267 15.3333L20 19.06L16.2734 15.3333L15.3334 16.2733L19.06 20L15.3334 23.7266L16.2734 24.6666L20 20.94L23.7267 24.6666L24.6667 23.7266L20.94 20L24.6667 16.2733Z"/> </vector>
packages/SystemUI/res/drawable/status_bar_notification_section_header_clear_btn.xml 0 → 100644 +25 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2019 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="40dp" android:height="40dp" android:viewportWidth="40" android:viewportHeight="40"> <path android:fillColor="#5F6368" android:pathData="M24.6667 16.2733L23.7267 15.3333L20 19.06L16.2734 15.3333L15.3334 16.2733L19.06 20L15.3334 23.7267L16.2734 24.6667L20 20.94L23.7267 24.6667L24.6667 23.7267L20.94 20L24.6667 16.2733Z"/> </vector>
packages/SystemUI/res/layout/status_bar_notification_section_header.xml +2 −1 Original line number Diff line number Diff line Loading @@ -50,9 +50,10 @@ /> <ImageView android:id="@+id/btn_clear_all" android:visibility="gone" android:layout_width="@dimen/notification_section_header_height" android:layout_height="@dimen/notification_section_header_height" android:layout_marginRight="4dp" android:src="@drawable/status_bar_notification_section_header_clear_btn" android:contentDescription="@string/accessibility_notification_section_header_gentle_clear_all" /> </LinearLayout> Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java +18 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.notification.stack; import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE; import android.annotation.Nullable; import android.content.Context; import android.content.Intent; Loading @@ -42,6 +44,7 @@ class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvide private SectionHeaderView mGentleHeader; private boolean mGentleHeaderVisible = false; @Nullable private View.OnClickListener mOnClearGentleNotifsClickListener; NotificationSectionsManager( NotificationStackScrollLayout parent, Loading Loading @@ -70,12 +73,18 @@ class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvide mGentleHeader = (SectionHeaderView) LayoutInflater.from(context).inflate( R.layout.status_bar_notification_section_header, mParent, false); mGentleHeader.setOnHeaderClickListener(this::onGentleHeaderClick); mGentleHeader.setOnClearAllClickListener(this::onClearGentleNotifsClick); if (oldPos != -1) { mParent.addView(mGentleHeader, oldPos); } } /** Listener for when the "clear all" buttton is clciked on the gentle notification header. */ void setOnClearGentleNotifsClickListener(View.OnClickListener listener) { mOnClearGentleNotifsClickListener = listener; } /** Must be called whenever the UI mode changes (i.e. when we enter night mode). */ void onUiModeChanged() { mGentleHeader.onUiModeChanged(); Loading Loading @@ -111,6 +120,9 @@ class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvide } adjustGentleHeaderVisibilityAndPosition(firstGentleNotifIndex); mGentleHeader.setAreThereDismissableGentleNotifs( mParent.hasActiveClearableNotifications(ROWS_GENTLE)); } private void adjustGentleHeaderVisibilityAndPosition(int firstGentleNotifIndex) { Loading Loading @@ -225,4 +237,10 @@ class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvide true, Intent.FLAG_ACTIVITY_SINGLE_TOP); } private void onClearGentleNotifsClick(View v) { if (mOnClearGentleNotifsClickListener != null) { mOnClearGentleNotifsClickListener.onClick(v); } } }
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +113 −35 Original line number Diff line number Diff line Loading @@ -23,10 +23,13 @@ import static com.android.systemui.statusbar.notification.stack.StackStateAnimat import static com.android.systemui.statusbar.phone.NotificationIconAreaController.LOW_PRIORITY; import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT; import static java.lang.annotation.RetentionPolicy.SOURCE; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.TimeAnimator; import android.animation.ValueAnimator; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.WallpaperManager; Loading Loading @@ -143,6 +146,7 @@ import com.android.systemui.tuner.TunerService; import java.io.FileDescriptor; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; Loading Loading @@ -525,12 +529,19 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } mAmbientPulseManager = ambientPulseManager; mSectionsManager = new NotificationSectionsManager( this, activityStarter, NotificationUtils.useNewInterruptionModel(context)); mSectionsManager.inflateViews(context); mSectionsManager.setOnClearGentleNotifsClickListener(v -> { // Leave the shade open if there will be other notifs left over to clear final boolean closeShade = !hasActiveClearableNotifications(ROWS_HIGH_PRIORITY); clearNotifications(ROWS_GENTLE, closeShade); }); mAmbientState = new AmbientState(context, mSectionsManager); mRoundnessManager = notificationRoundnessManager; mBgColor = context.getColor(R.color.notification_shade_background_color); Loading Loading @@ -672,7 +683,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @VisibleForTesting @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public void updateFooter() { boolean showDismissView = mClearAllEnabled && hasActiveClearableNotifications(); boolean showDismissView = mClearAllEnabled && hasActiveClearableNotifications(ROWS_ALL); boolean showFooterView = (showDismissView || mEntryManager.getNotificationData().getActiveNotifications().size() != 0) && mStatusBarState != StatusBarState.KEYGUARD Loading @@ -685,14 +696,15 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd * Return whether there are any clearable notifications */ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public boolean hasActiveClearableNotifications() { public boolean hasActiveClearableNotifications(@SelectedRows int selection) { int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View child = getChildAt(i); if (!(child instanceof ExpandableNotificationRow)) { continue; } if (((ExpandableNotificationRow) child).canViewBeDismissed()) { final ExpandableNotificationRow row = (ExpandableNotificationRow) child; if (row.canViewBeDismissed() && matchesSelection(row, selection)) { return true; } } Loading Loading @@ -1695,11 +1707,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd return mScrollingEnabled; } @ShadeViewRefactor(RefactorComponent.ADAPTER) private boolean canChildBeDismissed(View v) { return StackScrollAlgorithm.canChildBeDismissed(v); } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) private boolean onKeyguard() { return mStatusBarState == StatusBarState.KEYGUARD; Loading Loading @@ -4917,7 +4924,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } else { child.setMinClipTopAmount(0); } previousChildWillBeDismissed = canChildBeDismissed(child); previousChildWillBeDismissed = StackScrollAlgorithm.canChildBeDismissed(child); } } Loading Loading @@ -5473,7 +5480,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) private void clearAllNotifications() { private void clearNotifications( @SelectedRows int selection, boolean closeShade) { // animate-swipe all dismissable notifications, then animate the shade closed int numChildren = getChildCount(); Loading @@ -5485,7 +5494,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd ExpandableNotificationRow row = (ExpandableNotificationRow) child; boolean parentVisible = false; boolean hasClipBounds = child.getClipBounds(mTmpRect); if (canChildBeDismissed(child)) { if (includeChildInDismissAll(row, selection)) { viewsToRemove.add(row); if (child.getVisibility() == View.VISIBLE && (!hasClipBounds || mTmpRect.height() > 0)) { Loading @@ -5499,9 +5508,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd List<ExpandableNotificationRow> children = row.getNotificationChildren(); if (children != null) { for (ExpandableNotificationRow childRow : children) { if (includeChildInDismissAll(row, selection)) { viewsToRemove.add(childRow); if (parentVisible && row.areChildrenExpanded() && canChildBeDismissed(childRow)) { if (parentVisible && row.areChildrenExpanded()) { hasClipBounds = childRow.getClipBounds(mTmpRect); if (childRow.getVisibility() == View.VISIBLE && (!hasClipBounds || mTmpRect.height() > 0)) { Loading @@ -5512,38 +5521,81 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } } } } if (viewsToRemove.isEmpty()) { if (closeShade) { mStatusBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); } return; } mShadeController.addPostCollapseAction(() -> { setDismissAllInProgress(false); performDismissAllAnimations(viewsToHide, closeShade, () -> { for (ExpandableNotificationRow rowToRemove : viewsToRemove) { if (canChildBeDismissed(rowToRemove)) { mEntryManager.removeNotification(rowToRemove.getEntry().key, null /* ranking */, if (StackScrollAlgorithm.canChildBeDismissed(rowToRemove)) { if (selection == ROWS_ALL) { // TODO: This is a listener method; we shouldn't be calling it. Can we just // call performRemoveNotification as below? mEntryManager.removeNotification( rowToRemove.getEntry().key, null /* ranking */, NotificationListenerService.REASON_CANCEL_ALL); } else { mEntryManager.performRemoveNotification( rowToRemove.getEntry().notification, NotificationListenerService.REASON_CANCEL_ALL); } } else { rowToRemove.resetTranslation(); } } if (selection == ROWS_ALL) { try { mBarService.onClearAllNotifications(mLockscreenUserManager.getCurrentUserId()); } catch (Exception ex) { } } }); } performDismissAllAnimations(viewsToHide); private boolean includeChildInDismissAll( ExpandableNotificationRow row, @SelectedRows int selection) { return StackScrollAlgorithm.canChildBeDismissed(row) && matchesSelection(row, selection); } /** * 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. */ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public void performDismissAllAnimations(ArrayList<View> hideAnimatedList) { Runnable animationFinishAction = () -> { private void performDismissAllAnimations( final ArrayList<View> hideAnimatedList, final boolean closeShade, final Runnable onAnimationComplete) { final Runnable onSlideAwayAnimationComplete = () -> { if (closeShade) { mShadeController.addPostCollapseAction(() -> { setDismissAllInProgress(false); onAnimationComplete.run(); }); mStatusBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE); } else { setDismissAllInProgress(false); onAnimationComplete.run(); } }; if (hideAnimatedList.isEmpty()) { animationFinishAction.run(); onSlideAwayAnimationComplete.run(); return; } Loading @@ -5560,7 +5612,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd View view = hideAnimatedList.get(i); Runnable endRunnable = null; if (i == 0) { endRunnable = animationFinishAction; endRunnable = onSlideAwayAnimationComplete; } dismissViewAnimated(view, endRunnable, totalDelay, ANIMATION_DURATION_SWIPE); currentDelay = Math.max(50, currentDelay - rowDelayDecrement); Loading @@ -5575,7 +5627,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd R.layout.status_bar_notification_footer, this, false); footerView.setDismissButtonClickListener(v -> { mMetricsLogger.action(MetricsEvent.ACTION_DISMISS_ALL_NOTES); clearAllNotifications(); clearNotifications(ROWS_ALL, true /* closeShade */); }); footerView.setManageButtonClickListener(this::manageNotifications); setFooterView(footerView); Loading Loading @@ -5782,6 +5834,21 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd mSwipeHelper.resetExposedMenuView(animate, force); } private static boolean matchesSelection( ExpandableNotificationRow row, @SelectedRows int selection) { switch (selection) { case ROWS_ALL: return true; case ROWS_HIGH_PRIORITY: return row.getEntry().isHighPriority(); case ROWS_GENTLE: return !row.getEntry().isHighPriority(); default: throw new IllegalArgumentException("Unknown selection: " + selection); } } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) static class AnimationEvent { Loading Loading @@ -6266,7 +6333,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @Override public boolean canChildBeDismissed(View v) { return NotificationStackScrollLayout.this.canChildBeDismissed(v); return StackScrollAlgorithm.canChildBeDismissed(v); } @Override Loading Loading @@ -6473,4 +6540,15 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd public ExpandHelper.Callback getExpandHelperCallback() { return mExpandHelperCallback; } /** Enum for selecting some or all notification rows (does not included non-notif views). */ @Retention(SOURCE) @IntDef({ROWS_ALL, ROWS_HIGH_PRIORITY, ROWS_GENTLE}) public @interface SelectedRows {} /** All rows representing notifs. */ public static final int ROWS_ALL = 0; /** Only rows where entry.isHighPriority() is true. */ public static final int ROWS_HIGH_PRIORITY = 1; /** Only rows where entry.isHighPriority() is false. */ public static final int ROWS_GENTLE = 2; }