1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.statusbar.notification.collection.coordinator; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 22 import com.android.systemui.plugins.statusbar.StatusBarStateController; 23 import com.android.systemui.statusbar.notification.collection.ListEntry; 24 import com.android.systemui.statusbar.notification.collection.NotifPipeline; 25 import com.android.systemui.statusbar.notification.collection.NotificationEntry; 26 import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope; 27 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter; 28 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner; 29 import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider; 30 import com.android.systemui.statusbar.notification.collection.render.NodeController; 31 import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController; 32 import com.android.systemui.statusbar.notification.dagger.AlertingHeader; 33 import com.android.systemui.statusbar.notification.dagger.SilentHeader; 34 import com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt; 35 36 import java.util.List; 37 38 import javax.inject.Inject; 39 40 /** 41 * Filters out NotificationEntries based on its Ranking and dozing state. 42 * Assigns alerting / silent section based on the importance of the notification entry. 43 * We check the NotificationEntry's Ranking for: 44 * - whether the notification's app is suspended or hiding its notifications 45 * - whether DND settings are hiding notifications from ambient display or the notification list 46 */ 47 @CoordinatorScope 48 public class RankingCoordinator implements Coordinator { 49 public static final boolean SHOW_ALL_SECTIONS = false; 50 private final StatusBarStateController mStatusBarStateController; 51 private final HighPriorityProvider mHighPriorityProvider; 52 private final NodeController mSilentNodeController; 53 private final SectionHeaderController mSilentHeaderController; 54 private final NodeController mAlertingHeaderController; 55 56 @Inject RankingCoordinator( StatusBarStateController statusBarStateController, HighPriorityProvider highPriorityProvider, @AlertingHeader NodeController alertingHeaderController, @SilentHeader SectionHeaderController silentHeaderController, @SilentHeader NodeController silentNodeController)57 public RankingCoordinator( 58 StatusBarStateController statusBarStateController, 59 HighPriorityProvider highPriorityProvider, 60 @AlertingHeader NodeController alertingHeaderController, 61 @SilentHeader SectionHeaderController silentHeaderController, 62 @SilentHeader NodeController silentNodeController) { 63 mStatusBarStateController = statusBarStateController; 64 mHighPriorityProvider = highPriorityProvider; 65 mAlertingHeaderController = alertingHeaderController; 66 mSilentNodeController = silentNodeController; 67 mSilentHeaderController = silentHeaderController; 68 } 69 70 @Override attach(NotifPipeline pipeline)71 public void attach(NotifPipeline pipeline) { 72 mStatusBarStateController.addCallback(mStatusBarStateCallback); 73 74 pipeline.addPreGroupFilter(mSuspendedFilter); 75 pipeline.addPreGroupFilter(mDndVisualEffectsFilter); 76 } 77 getAlertingSectioner()78 public NotifSectioner getAlertingSectioner() { 79 return mAlertingNotifSectioner; 80 } 81 getSilentSectioner()82 public NotifSectioner getSilentSectioner() { 83 return mSilentNotifSectioner; 84 } 85 86 private final NotifSectioner mAlertingNotifSectioner = new NotifSectioner("Alerting", 87 NotificationPriorityBucketKt.BUCKET_ALERTING) { 88 @Override 89 public boolean isInSection(ListEntry entry) { 90 return mHighPriorityProvider.isHighPriority(entry); 91 } 92 93 @Nullable 94 @Override 95 public NodeController getHeaderNodeController() { 96 // TODO: remove SHOW_ALL_SECTIONS, this redundant method, and mAlertingHeaderController 97 if (SHOW_ALL_SECTIONS) { 98 return mAlertingHeaderController; 99 } 100 return null; 101 } 102 }; 103 104 private final NotifSectioner mSilentNotifSectioner = new NotifSectioner("Silent", 105 NotificationPriorityBucketKt.BUCKET_SILENT) { 106 @Override 107 public boolean isInSection(ListEntry entry) { 108 return !mHighPriorityProvider.isHighPriority(entry); 109 } 110 111 @Nullable 112 @Override 113 public NodeController getHeaderNodeController() { 114 return mSilentNodeController; 115 } 116 117 @Nullable 118 @Override 119 public void onEntriesUpdated(@NonNull List<ListEntry> entries) { 120 for (int i = 0; i < entries.size(); i++) { 121 if (entries.get(i).getRepresentativeEntry().getSbn().isClearable()) { 122 mSilentHeaderController.setClearSectionEnabled(true); 123 return; 124 } 125 } 126 mSilentHeaderController.setClearSectionEnabled(false); 127 } 128 }; 129 130 /** 131 * Checks whether to filter out the given notification based the notification's Ranking object. 132 * NotifListBuilder invalidates the notification list each time the ranking is updated, 133 * so we don't need to explicitly invalidate this filter on ranking update. 134 */ 135 private final NotifFilter mSuspendedFilter = new NotifFilter("IsSuspendedFilter") { 136 @Override 137 public boolean shouldFilterOut(NotificationEntry entry, long now) { 138 return entry.getRanking().isSuspended(); 139 } 140 }; 141 142 private final NotifFilter mDndVisualEffectsFilter = new NotifFilter( 143 "DndSuppressingVisualEffects") { 144 @Override 145 public boolean shouldFilterOut(NotificationEntry entry, long now) { 146 if (mStatusBarStateController.isDozing() && entry.shouldSuppressAmbient()) { 147 return true; 148 } 149 150 return !mStatusBarStateController.isDozing() && entry.shouldSuppressNotificationList(); 151 } 152 }; 153 154 private final StatusBarStateController.StateListener mStatusBarStateCallback = 155 new StatusBarStateController.StateListener() { 156 @Override 157 public void onDozingChanged(boolean isDozing) { 158 mDndVisualEffectsFilter.invalidateList(); 159 } 160 }; 161 } 162