• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.provider.SectionStyleProvider;
31 import com.android.systemui.statusbar.notification.collection.render.NodeController;
32 import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController;
33 import com.android.systemui.statusbar.notification.dagger.AlertingHeader;
34 import com.android.systemui.statusbar.notification.dagger.SilentHeader;
35 import com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt;
36 
37 import java.util.Collections;
38 import java.util.List;
39 
40 import javax.inject.Inject;
41 
42 /**
43  * Filters out NotificationEntries based on its Ranking and dozing state.
44  * Assigns alerting / silent section based on the importance of the notification entry.
45  * We check the NotificationEntry's Ranking for:
46  *  - whether the notification's app is suspended or hiding its notifications
47  *  - whether DND settings are hiding notifications from ambient display or the notification list
48  */
49 @CoordinatorScope
50 public class RankingCoordinator implements Coordinator {
51     public static final boolean SHOW_ALL_SECTIONS = false;
52     private final StatusBarStateController mStatusBarStateController;
53     private final HighPriorityProvider mHighPriorityProvider;
54     private final SectionStyleProvider mSectionStyleProvider;
55     private final NodeController mSilentNodeController;
56     private final SectionHeaderController mSilentHeaderController;
57     private final NodeController mAlertingHeaderController;
58     private boolean mHasSilentEntries;
59     private boolean mHasMinimizedEntries;
60 
61     @Inject
RankingCoordinator( StatusBarStateController statusBarStateController, HighPriorityProvider highPriorityProvider, SectionStyleProvider sectionStyleProvider, @AlertingHeader NodeController alertingHeaderController, @SilentHeader SectionHeaderController silentHeaderController, @SilentHeader NodeController silentNodeController)62     public RankingCoordinator(
63             StatusBarStateController statusBarStateController,
64             HighPriorityProvider highPriorityProvider,
65             SectionStyleProvider sectionStyleProvider,
66             @AlertingHeader NodeController alertingHeaderController,
67             @SilentHeader SectionHeaderController silentHeaderController,
68             @SilentHeader NodeController silentNodeController) {
69         mStatusBarStateController = statusBarStateController;
70         mHighPriorityProvider = highPriorityProvider;
71         mSectionStyleProvider = sectionStyleProvider;
72         mAlertingHeaderController = alertingHeaderController;
73         mSilentNodeController = silentNodeController;
74         mSilentHeaderController = silentHeaderController;
75     }
76 
77     @Override
attach(NotifPipeline pipeline)78     public void attach(NotifPipeline pipeline) {
79         mStatusBarStateController.addCallback(mStatusBarStateCallback);
80         mSectionStyleProvider.setMinimizedSections(Collections.singleton(mMinimizedNotifSectioner));
81 
82         pipeline.addPreGroupFilter(mSuspendedFilter);
83         pipeline.addPreGroupFilter(mDndVisualEffectsFilter);
84     }
85 
getAlertingSectioner()86     public NotifSectioner getAlertingSectioner() {
87         return mAlertingNotifSectioner;
88     }
89 
getSilentSectioner()90     public NotifSectioner getSilentSectioner() {
91         return mSilentNotifSectioner;
92     }
93 
getMinimizedSectioner()94     public NotifSectioner getMinimizedSectioner() {
95         return mMinimizedNotifSectioner;
96     }
97 
98     private final NotifSectioner mAlertingNotifSectioner = new NotifSectioner("Alerting",
99             NotificationPriorityBucketKt.BUCKET_ALERTING) {
100         @Override
101         public boolean isInSection(ListEntry entry) {
102             return mHighPriorityProvider.isHighPriority(entry);
103         }
104 
105         @Nullable
106         @Override
107         public NodeController getHeaderNodeController() {
108             // TODO: remove SHOW_ALL_SECTIONS, this redundant method, and mAlertingHeaderController
109             if (SHOW_ALL_SECTIONS) {
110                 return mAlertingHeaderController;
111             }
112             return null;
113         }
114     };
115 
116     private final NotifSectioner mSilentNotifSectioner = new NotifSectioner("Silent",
117             NotificationPriorityBucketKt.BUCKET_SILENT) {
118         @Override
119         public boolean isInSection(ListEntry entry) {
120             return !mHighPriorityProvider.isHighPriority(entry)
121                     && !entry.getRepresentativeEntry().isAmbient();
122         }
123 
124         @Nullable
125         @Override
126         public NodeController getHeaderNodeController() {
127             return mSilentNodeController;
128         }
129 
130         @Nullable
131         @Override
132         public void onEntriesUpdated(@NonNull List<ListEntry> entries) {
133             mHasSilentEntries = false;
134             for (int i = 0; i < entries.size(); i++) {
135                 if (entries.get(i).getRepresentativeEntry().getSbn().isClearable()) {
136                     mHasSilentEntries = true;
137                     break;
138                 }
139             }
140             mSilentHeaderController.setClearSectionEnabled(
141                     mHasSilentEntries | mHasMinimizedEntries);
142         }
143     };
144 
145     private final NotifSectioner mMinimizedNotifSectioner = new NotifSectioner("Minimized",
146             NotificationPriorityBucketKt.BUCKET_SILENT) {
147         @Override
148         public boolean isInSection(ListEntry entry) {
149             return !mHighPriorityProvider.isHighPriority(entry)
150                     && entry.getRepresentativeEntry().isAmbient();
151         }
152 
153         @Nullable
154         @Override
155         public NodeController getHeaderNodeController() {
156             return mSilentNodeController;
157         }
158 
159         @Nullable
160         @Override
161         public void onEntriesUpdated(@NonNull List<ListEntry> entries) {
162             mHasMinimizedEntries = false;
163             for (int i = 0; i < entries.size(); i++) {
164                 if (entries.get(i).getRepresentativeEntry().getSbn().isClearable()) {
165                     mHasMinimizedEntries = true;
166                     break;
167                 }
168             }
169             mSilentHeaderController.setClearSectionEnabled(
170                     mHasSilentEntries | mHasMinimizedEntries);
171         }
172     };
173 
174     /**
175      * Checks whether to filter out the given notification based the notification's Ranking object.
176      * NotifListBuilder invalidates the notification list each time the ranking is updated,
177      * so we don't need to explicitly invalidate this filter on ranking update.
178      */
179     private final NotifFilter mSuspendedFilter = new NotifFilter("IsSuspendedFilter") {
180         @Override
181         public boolean shouldFilterOut(NotificationEntry entry, long now) {
182             return entry.getRanking().isSuspended();
183         }
184     };
185 
186     private final NotifFilter mDndVisualEffectsFilter = new NotifFilter(
187             "DndSuppressingVisualEffects") {
188         @Override
189         public boolean shouldFilterOut(NotificationEntry entry, long now) {
190             if (mStatusBarStateController.isDozing() && entry.shouldSuppressAmbient()) {
191                 return true;
192             }
193 
194             return !mStatusBarStateController.isDozing() && entry.shouldSuppressNotificationList();
195         }
196     };
197 
198     private final StatusBarStateController.StateListener mStatusBarStateCallback =
199             new StatusBarStateController.StateListener() {
200                 @Override
201                 public void onDozingChanged(boolean isDozing) {
202                     mDndVisualEffectsFilter.invalidateList("onDozingChanged to " + isDozing);
203                 }
204             };
205 }
206