blob: f7c07f370cb1c7eaec4e443af4e9f8f9e2009577 [file] [log] [blame]
Joe Onorato503007d2010-04-16 09:20:55 -07001/*
2 * Copyright (C) 2008 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
Rohan Shah20790b82018-07-02 17:21:04 -070014 * limitations under the License
Joe Onorato503007d2010-04-16 09:20:55 -070015 */
16
Rohan Shah20790b82018-07-02 17:21:04 -070017package com.android.systemui.statusbar.notification;
Joe Onorato503007d2010-04-16 09:20:55 -070018
Julia Reynolds25926af2018-05-01 17:05:33 -040019import static android.app.Notification.CATEGORY_ALARM;
20import static android.app.Notification.CATEGORY_CALL;
21import static android.app.Notification.CATEGORY_EVENT;
22import static android.app.Notification.CATEGORY_MESSAGE;
23import static android.app.Notification.CATEGORY_REMINDER;
Julia Reynolds24653c32018-03-02 13:16:37 -050024import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
25import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
Julia Reynolds24653c32018-03-02 13:16:37 -050026import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
27import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
28import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
29
Julia Reynolds5bbb6da2018-03-28 10:48:37 -040030import android.Manifest;
Tony Mak628cb932018-06-19 18:30:41 +010031import android.annotation.NonNull;
Maurice Lam132710e2017-03-03 19:13:42 -080032import android.app.AppGlobals;
Christoph Studer37fe6932014-05-26 13:10:30 +020033import android.app.Notification;
Julia Reynolds924eed12017-01-19 09:52:07 -050034import android.app.NotificationChannel;
Julia Reynolds85769912016-10-25 09:08:57 -040035import android.app.NotificationManager;
Selim Cinekb0dc61b2018-05-22 18:49:36 -070036import android.app.Person;
Julia Reynolds5bbb6da2018-03-28 10:48:37 -040037import android.content.Context;
Maurice Lam132710e2017-03-03 19:13:42 -080038import android.content.pm.IPackageManager;
39import android.content.pm.PackageManager;
Selim Cinek281c2022016-10-13 19:14:43 -070040import android.graphics.drawable.Icon;
Selim Cinekb0dc61b2018-05-22 18:49:36 -070041import android.os.Bundle;
42import android.os.Parcelable;
Maurice Lam132710e2017-03-03 19:13:42 -080043import android.os.RemoteException;
Selim Cinekb18a20f2015-06-04 17:08:35 +020044import android.os.SystemClock;
Christoph Studer37fe6932014-05-26 13:10:30 +020045import android.service.notification.NotificationListenerService.Ranking;
Christoph Studerd0694b62014-06-04 16:36:01 +020046import android.service.notification.NotificationListenerService.RankingMap;
Mady Mellor754d8222017-01-25 15:29:39 -080047import android.service.notification.SnoozeCriterion;
John Spurlockde84f0e2013-06-12 12:41:00 -040048import android.service.notification.StatusBarNotification;
Christoph Studerc8db24b2014-07-25 17:50:30 +020049import android.util.ArrayMap;
Julia Reynoldsfc640012018-02-21 12:25:27 -050050import android.util.ArraySet;
Joe Onoratoe345fff2010-05-23 15:18:27 -040051import android.view.View;
Selim Cinek281c2022016-10-13 19:14:43 -070052import android.widget.ImageView;
Joe Onorato503007d2010-04-16 09:20:55 -070053
Gus Prevasa3226492018-10-23 11:10:09 -040054import androidx.annotation.Nullable;
55
Maurice Lam132710e2017-03-03 19:13:42 -080056import com.android.internal.annotations.VisibleForTesting;
Selim Cinek281c2022016-10-13 19:14:43 -070057import com.android.internal.statusbar.StatusBarIcon;
Selim Cinekb0dc61b2018-05-22 18:49:36 -070058import com.android.internal.util.ArrayUtils;
Lucas Dupina291d192018-06-07 13:59:42 -070059import com.android.internal.util.ContrastColorUtil;
Dan Sandler008cea72017-05-28 12:18:53 -040060import com.android.systemui.Dependency;
61import com.android.systemui.ForegroundServiceController;
Rohan Shah20790b82018-07-02 17:21:04 -070062import com.android.systemui.statusbar.InflationTask;
Jason Monk297c04e2018-08-23 17:16:59 -040063import com.android.systemui.statusbar.NotificationLockscreenUserManager;
64import com.android.systemui.statusbar.NotificationMediaManager;
Rohan Shah20790b82018-07-02 17:21:04 -070065import com.android.systemui.statusbar.StatusBarIconView;
66import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
Selim Cinek25fd4e2b2015-02-20 17:46:07 +010067import com.android.systemui.statusbar.phone.NotificationGroupManager;
Jason Monk297c04e2018-08-23 17:16:59 -040068import com.android.systemui.statusbar.phone.ShadeController;
Jason Monk2a6ea9c2017-01-26 11:14:51 -050069import com.android.systemui.statusbar.phone.StatusBar;
Selim Cinekfbe9a442015-04-13 16:09:49 -070070import com.android.systemui.statusbar.policy.HeadsUpManager;
Selim Cinek25fd4e2b2015-02-20 17:46:07 +010071
Christoph Studerc8db24b2014-07-25 17:50:30 +020072import java.io.PrintWriter;
Joe Onoratoe345fff2010-05-23 15:18:27 -040073import java.util.ArrayList;
Christoph Studer37fe6932014-05-26 13:10:30 +020074import java.util.Collections;
John Spurlockde84f0e2013-06-12 12:41:00 -040075import java.util.Comparator;
Mady Mellor754d8222017-01-25 15:29:39 -080076import java.util.List;
Selim Cinek247fa012016-02-18 09:50:48 -080077import java.util.Objects;
Joe Onoratoe345fff2010-05-23 15:18:27 -040078
79/**
80 * The list of currently displaying notifications.
81 */
Joe Onorato503007d2010-04-16 09:20:55 -070082public class NotificationData {
Christoph Studerc8db24b2014-07-25 17:50:30 +020083
Jason Monk297c04e2018-08-23 17:16:59 -040084 /**
85 * These dependencies are late init-ed
86 */
87 private KeyguardEnvironment mEnvironment;
88 private ShadeController mShadeController;
89 private NotificationMediaManager mMediaManager;
90 private ForegroundServiceController mFsc;
91 private NotificationLockscreenUserManager mUserManager;
Christoph Studerc8db24b2014-07-25 17:50:30 +020092
Jason Monk297c04e2018-08-23 17:16:59 -040093 private HeadsUpManager mHeadsUpManager;
Julia Reynoldsfc640012018-02-21 12:25:27 -050094
Joe Onoratoe345fff2010-05-23 15:18:27 -040095 public static final class Entry {
Selim Cinekb18a20f2015-06-04 17:08:35 +020096 private static final long LAUNCH_COOLDOWN = 2000;
Selim Cinek1397ea32018-01-16 17:34:52 -080097 private static final long REMOTE_INPUT_COOLDOWN = 500;
Aaron Heuckroth1dd67cb2018-06-14 14:28:08 -040098 private static final long INITIALIZATION_DELAY = 400;
Selim Cinekb18a20f2015-06-04 17:08:35 +020099 private static final long NOT_LAUNCHED_YET = -LAUNCH_COOLDOWN;
Selim Cinek281c2022016-10-13 19:14:43 -0700100 private static final int COLOR_INVALID = 1;
Christoph Studer71f18fd2014-05-20 17:02:04 +0200101 public String key;
Joe Onoratoe345fff2010-05-23 15:18:27 -0400102 public StatusBarNotification notification;
Julia Reynolds924eed12017-01-19 09:52:07 -0500103 public NotificationChannel channel;
Gus Prevasa3226492018-10-23 11:10:09 -0400104 public boolean audiblyAlerted;
Gus Prevas9abc5062018-10-31 16:11:04 -0400105 public boolean noisy;
106 public int importance;
Joe Onorato66b4c5b2010-05-23 15:39:40 -0400107 public StatusBarIconView icon;
Selim Cinek281c2022016-10-13 19:14:43 -0700108 public StatusBarIconView expandedIcon;
Chris Wren51c75102013-07-16 20:49:17 -0400109 public ExpandableNotificationRow row; // the outer expanded view
Chris Wrenf0048ce2013-08-07 16:43:43 -0400110 private boolean interruption;
Jorim Jaggi36b15232014-06-10 17:24:20 +0200111 public boolean autoRedacted; // whether the redacted notification was generated by us
Jorim Jaggia1eeade2014-09-08 22:34:39 +0200112 public int targetSdk;
Selim Cinekb18a20f2015-06-04 17:08:35 +0200113 private long lastFullScreenIntentLaunchTime = NOT_LAUNCHED_YET;
Adrian Roos777ef562015-12-01 17:37:14 -0800114 public CharSequence remoteInputText;
Mady Mellor754d8222017-01-25 15:29:39 -0800115 public List<SnoozeCriterion> snoozeCriteria;
Dan Sandler1d958f82018-01-09 21:10:26 -0500116 public int userSentiment = Ranking.USER_SENTIMENT_NEUTRAL;
Tony Mak628cb932018-06-19 18:30:41 +0100117 @NonNull
118 public List<Notification.Action> smartActions = Collections.emptyList();
Tony Makc9acf672018-07-20 13:58:24 +0200119 public CharSequence[] smartReplies = new CharSequence[0];
Dan Sandler1d958f82018-01-09 21:10:26 -0500120
Selim Cinek281c2022016-10-13 19:14:43 -0700121 private int mCachedContrastColor = COLOR_INVALID;
122 private int mCachedContrastColorIsFor = COLOR_INVALID;
Selim Cinek67ff2482017-05-25 10:27:28 -0700123 private InflationTask mRunningTask = null;
Selim Cinek04be3892017-08-08 10:58:32 -0700124 private Throwable mDebugThrowable;
Selim Cinek1397ea32018-01-16 17:34:52 -0800125 public CharSequence remoteInputTextWhenReset;
126 public long lastRemoteInputSent = NOT_LAUNCHED_YET;
Julia Reynoldsfc640012018-02-21 12:25:27 -0500127 public ArraySet<Integer> mActiveAppOps = new ArraySet<>(3);
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800128 public CharSequence headsUpStatusBarText;
129 public CharSequence headsUpStatusBarTextPublic;
Aaron Heuckroth1dd67cb2018-06-14 14:28:08 -0400130
131 private long initializationTime = -1;
132
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400133 /**
134 * Whether or not this row represents a system notification. Note that if this is
135 * {@code null}, that means we were either unable to retrieve the info or have yet to
136 * retrieve the info.
137 */
138 public Boolean mIsSystemNotification;
Jorim Jaggi36b15232014-06-10 17:24:20 +0200139
Selim Cinekb0dc61b2018-05-22 18:49:36 -0700140 /**
141 * Has the user sent a reply through this Notification.
142 */
143 private boolean hasSentReply;
144
Selim Cinek281c2022016-10-13 19:14:43 -0700145 public Entry(StatusBarNotification n) {
Tony Mak628cb932018-06-19 18:30:41 +0100146 this(n, null);
147 }
148
149 public Entry(StatusBarNotification n, @Nullable Ranking ranking) {
Christoph Studer71f18fd2014-05-20 17:02:04 +0200150 this.key = n.getKey();
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400151 this.notification = n;
Tony Mak628cb932018-06-19 18:30:41 +0100152 if (ranking != null) {
153 populateFromRanking(ranking);
154 }
155 }
156
157 public void populateFromRanking(@NonNull Ranking ranking) {
158 channel = ranking.getChannel();
Gus Prevasa3226492018-10-23 11:10:09 -0400159 audiblyAlerted = ranking.audiblyAlerted();
Gus Prevas9abc5062018-10-31 16:11:04 -0400160 noisy = ranking.isNoisy();
161 importance = ranking.getImportance();
Tony Mak628cb932018-06-19 18:30:41 +0100162 snoozeCriteria = ranking.getSnoozeCriteria();
163 userSentiment = ranking.getUserSentiment();
164 smartActions = ranking.getSmartActions() == null
165 ? Collections.emptyList() : ranking.getSmartActions();
Tony Makc9acf672018-07-20 13:58:24 +0200166 smartReplies = ranking.getSmartReplies() == null
167 ? new CharSequence[0]
168 : ranking.getSmartReplies().toArray(new CharSequence[0]);
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400169 }
Chris Wrenf0048ce2013-08-07 16:43:43 -0400170
171 public void setInterruption() {
172 interruption = true;
173 }
Chris Wrend04f6ce2014-06-11 17:37:28 -0400174
175 public boolean hasInterrupted() {
176 return interruption;
177 }
Christoph Studer22f2ee52014-07-29 22:57:21 +0200178
179 /**
180 * Resets the notification entry to be re-used.
181 */
182 public void reset() {
Christoph Studer22f2ee52014-07-29 22:57:21 +0200183 if (row != null) {
184 row.reset();
185 }
186 }
Selim Cinek684a4422015-04-15 16:18:39 -0700187
Selim Cinekb18a20f2015-06-04 17:08:35 +0200188 public void notifyFullScreenIntentLaunched() {
Selim Cinekda371df2017-07-21 16:18:21 -0700189 setInterruption();
Selim Cinekb18a20f2015-06-04 17:08:35 +0200190 lastFullScreenIntentLaunchTime = SystemClock.elapsedRealtime();
191 }
192
193 public boolean hasJustLaunchedFullScreenIntent() {
194 return SystemClock.elapsedRealtime() < lastFullScreenIntentLaunchTime + LAUNCH_COOLDOWN;
195 }
Selim Cinek281c2022016-10-13 19:14:43 -0700196
Selim Cinek1397ea32018-01-16 17:34:52 -0800197 public boolean hasJustSentRemoteInput() {
198 return SystemClock.elapsedRealtime() < lastRemoteInputSent + REMOTE_INPUT_COOLDOWN;
199 }
200
Aaron Heuckroth1dd67cb2018-06-14 14:28:08 -0400201 public boolean hasFinishedInitialization() {
202 return initializationTime == -1 ||
203 SystemClock.elapsedRealtime() > initializationTime + INITIALIZATION_DELAY;
204 }
205
Selim Cinek281c2022016-10-13 19:14:43 -0700206 /**
207 * Create the icons for a notification
208 * @param context the context to create the icons with
209 * @param sbn the notification
Selim Cinek1a48bab2017-02-17 19:38:40 -0800210 * @throws InflationException
Selim Cinek281c2022016-10-13 19:14:43 -0700211 */
Selim Cinek1a48bab2017-02-17 19:38:40 -0800212 public void createIcons(Context context, StatusBarNotification sbn)
213 throws InflationException {
Selim Cinek281c2022016-10-13 19:14:43 -0700214 Notification n = sbn.getNotification();
215 final Icon smallIcon = n.getSmallIcon();
216 if (smallIcon == null) {
Selim Cinek1a48bab2017-02-17 19:38:40 -0800217 throw new InflationException("No small icon in notification from "
Selim Cinek281c2022016-10-13 19:14:43 -0700218 + sbn.getPackageName());
219 }
220
221 // Construct the icon.
222 icon = new StatusBarIconView(context,
Selim Cinek72fc8db2017-06-06 18:07:47 -0700223 sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), sbn);
Selim Cinek281c2022016-10-13 19:14:43 -0700224 icon.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
225
226 // Construct the expanded icon.
227 expandedIcon = new StatusBarIconView(context,
Selim Cinek72fc8db2017-06-06 18:07:47 -0700228 sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), sbn);
Selim Cinek281c2022016-10-13 19:14:43 -0700229 expandedIcon.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
230 final StatusBarIcon ic = new StatusBarIcon(
231 sbn.getUser(),
232 sbn.getPackageName(),
233 smallIcon,
234 n.iconLevel,
235 n.number,
236 StatusBarIconView.contentDescForNotification(context, n));
237 if (!icon.set(ic) || !expandedIcon.set(ic)) {
238 icon = null;
239 expandedIcon = null;
Selim Cinek1a48bab2017-02-17 19:38:40 -0800240 throw new InflationException("Couldn't create icon: " + ic);
Selim Cinek281c2022016-10-13 19:14:43 -0700241 }
Selim Cinek65989742016-12-09 16:05:38 -0800242 expandedIcon.setVisibility(View.INVISIBLE);
Selim Cinek2b549f42016-11-22 16:38:51 -0800243 expandedIcon.setOnVisibilityChangedListener(
244 newVisibility -> {
245 if (row != null) {
246 row.setIconsVisible(newVisibility != View.VISIBLE);
247 }
248 });
Selim Cinek281c2022016-10-13 19:14:43 -0700249 }
250
251 public void setIconTag(int key, Object tag) {
252 if (icon != null) {
253 icon.setTag(key, tag);
254 expandedIcon.setTag(key, tag);
255 }
256 }
257
258 /**
259 * Update the notification icons.
Tony Mak628cb932018-06-19 18:30:41 +0100260 *
Selim Cinek281c2022016-10-13 19:14:43 -0700261 * @param context the context to create the icons with.
Julia Reynoldsfc640012018-02-21 12:25:27 -0500262 * @param sbn the notification to read the icon from.
Selim Cinek1a48bab2017-02-17 19:38:40 -0800263 * @throws InflationException
Selim Cinek281c2022016-10-13 19:14:43 -0700264 */
Selim Cinek72fc8db2017-06-06 18:07:47 -0700265 public void updateIcons(Context context, StatusBarNotification sbn)
266 throws InflationException {
Selim Cinek281c2022016-10-13 19:14:43 -0700267 if (icon != null) {
268 // Update the icon
Selim Cinek72fc8db2017-06-06 18:07:47 -0700269 Notification n = sbn.getNotification();
Selim Cinek281c2022016-10-13 19:14:43 -0700270 final StatusBarIcon ic = new StatusBarIcon(
271 notification.getUser(),
272 notification.getPackageName(),
273 n.getSmallIcon(),
274 n.iconLevel,
275 n.number,
276 StatusBarIconView.contentDescForNotification(context, n));
Selim Cinek72fc8db2017-06-06 18:07:47 -0700277 icon.setNotification(sbn);
278 expandedIcon.setNotification(sbn);
Selim Cinek281c2022016-10-13 19:14:43 -0700279 if (!icon.set(ic) || !expandedIcon.set(ic)) {
Selim Cinek1a48bab2017-02-17 19:38:40 -0800280 throw new InflationException("Couldn't update icon: " + ic);
Selim Cinek281c2022016-10-13 19:14:43 -0700281 }
282 }
283 }
284
Selim Cinekac5f0272017-05-02 16:05:41 -0700285 public int getContrastedColor(Context context, boolean isLowPriority,
286 int backgroundColor) {
287 int rawColor = isLowPriority ? Notification.COLOR_DEFAULT :
Selim Cinek6743c0b2017-01-18 18:24:01 -0800288 notification.getNotification().color;
Selim Cinek281c2022016-10-13 19:14:43 -0700289 if (mCachedContrastColorIsFor == rawColor && mCachedContrastColor != COLOR_INVALID) {
290 return mCachedContrastColor;
291 }
Lucas Dupina291d192018-06-07 13:59:42 -0700292 final int contrasted = ContrastColorUtil.resolveContrastColor(context, rawColor,
Selim Cinekac5f0272017-05-02 16:05:41 -0700293 backgroundColor);
Selim Cinek281c2022016-10-13 19:14:43 -0700294 mCachedContrastColorIsFor = rawColor;
295 mCachedContrastColor = contrasted;
296 return mCachedContrastColor;
297 }
Selim Cinek2630dc72017-04-20 15:16:10 -0700298
299 /**
300 * Abort all existing inflation tasks
301 */
Selim Cinek0f66a4c2017-04-28 19:26:28 -0700302 public void abortTask() {
Selim Cinek01d3da62017-04-28 15:03:48 -0700303 if (mRunningTask != null) {
304 mRunningTask.abort();
305 mRunningTask = null;
Selim Cinek2630dc72017-04-20 15:16:10 -0700306 }
307 }
308
Selim Cinek67ff2482017-05-25 10:27:28 -0700309 public void setInflationTask(InflationTask abortableTask) {
Selim Cinek01d3da62017-04-28 15:03:48 -0700310 // abort any existing inflation
Selim Cinek67ff2482017-05-25 10:27:28 -0700311 InflationTask existing = mRunningTask;
Selim Cinek0f66a4c2017-04-28 19:26:28 -0700312 abortTask();
313 mRunningTask = abortableTask;
Selim Cinek67ff2482017-05-25 10:27:28 -0700314 if (existing != null && mRunningTask != null) {
315 mRunningTask.supersedeTask(existing);
316 }
Selim Cinek2630dc72017-04-20 15:16:10 -0700317 }
Selim Cinekdc1231c2017-04-27 17:30:50 -0700318
Selim Cinek01d3da62017-04-28 15:03:48 -0700319 public void onInflationTaskFinished() {
Tony Mak628cb932018-06-19 18:30:41 +0100320 mRunningTask = null;
Selim Cinekdc1231c2017-04-27 17:30:50 -0700321 }
322
323 @VisibleForTesting
Selim Cinek67ff2482017-05-25 10:27:28 -0700324 public InflationTask getRunningTask() {
Selim Cinek01d3da62017-04-28 15:03:48 -0700325 return mRunningTask;
Selim Cinekdc1231c2017-04-27 17:30:50 -0700326 }
Selim Cinek04be3892017-08-08 10:58:32 -0700327
328 /**
329 * Set a throwable that is used for debugging
330 *
331 * @param debugThrowable the throwable to save
332 */
333 public void setDebugThrowable(Throwable debugThrowable) {
334 mDebugThrowable = debugThrowable;
335 }
336
337 public Throwable getDebugThrowable() {
338 return mDebugThrowable;
339 }
Selim Cinek90d11a12018-01-17 16:24:36 -0800340
341 public void onRemoteInputInserted() {
342 lastRemoteInputSent = NOT_LAUNCHED_YET;
343 remoteInputTextWhenReset = null;
344 }
Selim Cinekb0dc61b2018-05-22 18:49:36 -0700345
346 public void setHasSentReply() {
347 hasSentReply = true;
348 }
349
350 public boolean isLastMessageFromReply() {
351 if (!hasSentReply) {
352 return false;
353 }
354 Bundle extras = notification.getNotification().extras;
355 CharSequence[] replyTexts = extras.getCharSequenceArray(
356 Notification.EXTRA_REMOTE_INPUT_HISTORY);
357 if (!ArrayUtils.isEmpty(replyTexts)) {
358 return true;
359 }
360 Parcelable[] messages = extras.getParcelableArray(Notification.EXTRA_MESSAGES);
361 if (messages != null && messages.length > 0) {
362 Parcelable message = messages[messages.length - 1];
363 if (message instanceof Bundle) {
364 Notification.MessagingStyle.Message lastMessage =
365 Notification.MessagingStyle.Message.getMessageFromBundle(
366 (Bundle) message);
367 if (lastMessage != null) {
368 Person senderPerson = lastMessage.getSenderPerson();
369 if (senderPerson == null) {
370 return true;
371 }
372 Person user = extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON);
373 return Objects.equals(user, senderPerson);
374 }
375 }
376 }
377 return false;
378 }
Aaron Heuckroth1dd67cb2018-06-14 14:28:08 -0400379
380 public void setInitializationTime(long time) {
381 if (initializationTime == -1) {
382 initializationTime = time;
383 }
384 }
Joe Onoratoe345fff2010-05-23 15:18:27 -0400385 }
Christoph Studer71f18fd2014-05-20 17:02:04 +0200386
Christoph Studerc8db24b2014-07-25 17:50:30 +0200387 private final ArrayMap<String, Entry> mEntries = new ArrayMap<>();
388 private final ArrayList<Entry> mSortedAndFiltered = new ArrayList<>();
Dieter Hsu36e1ebc2018-06-06 15:41:46 +0800389 private final ArrayList<Entry> mFilteredForUser = new ArrayList<>();
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100390
Jason Monk297c04e2018-08-23 17:16:59 -0400391 private final NotificationGroupManager mGroupManager
392 = Dependency.get(NotificationGroupManager.class);
Christoph Studerc8db24b2014-07-25 17:50:30 +0200393
Christoph Studer1d599da2014-06-12 15:25:59 +0200394 private RankingMap mRankingMap;
395 private final Ranking mTmpRanking = new Ranking();
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100396
Selim Cinekfbe9a442015-04-13 16:09:49 -0700397 public void setHeadsUpManager(HeadsUpManager headsUpManager) {
398 mHeadsUpManager = headsUpManager;
399 }
400
Christoph Studer37fe6932014-05-26 13:10:30 +0200401 private final Comparator<Entry> mRankingComparator = new Comparator<Entry>() {
Christoph Studer1d599da2014-06-12 15:25:59 +0200402 private final Ranking mRankingA = new Ranking();
403 private final Ranking mRankingB = new Ranking();
404
Christoph Studer37fe6932014-05-26 13:10:30 +0200405 @Override
Daniel Sandler379020a2010-07-29 16:20:06 -0400406 public int compare(Entry a, Entry b) {
Christoph Studer14921162014-09-03 12:51:26 +0200407 final StatusBarNotification na = a.notification;
408 final StatusBarNotification nb = b.notification;
Julia Reynolds85769912016-10-25 09:08:57 -0400409 int aImportance = NotificationManager.IMPORTANCE_DEFAULT;
410 int bImportance = NotificationManager.IMPORTANCE_DEFAULT;
Chris Wrenbdf33762015-12-04 15:50:51 -0500411 int aRank = 0;
412 int bRank = 0;
413
414 if (mRankingMap != null) {
415 // RankingMap as received from NoMan
Kensuke Matsuiefa1a742017-08-03 12:12:36 +0900416 getRanking(a.key, mRankingA);
417 getRanking(b.key, mRankingB);
Chris Wrenbdf33762015-12-04 15:50:51 -0500418 aImportance = mRankingA.getImportance();
419 bImportance = mRankingB.getImportance();
420 aRank = mRankingA.getRank();
421 bRank = mRankingB.getRank();
422 }
Christoph Studer14921162014-09-03 12:51:26 +0200423
Jason Monk297c04e2018-08-23 17:16:59 -0400424 String mediaNotification = getMediaManager().getMediaNotificationKey();
Dan Sandler4e787062015-06-17 15:09:48 -0400425
Julia Reynoldsf0f629f2016-02-25 09:34:04 -0500426 // IMPORTANCE_MIN media streams are allowed to drift to the bottom
Dan Sandler4e787062015-06-17 15:09:48 -0400427 final boolean aMedia = a.key.equals(mediaNotification)
Julia Reynolds85769912016-10-25 09:08:57 -0400428 && aImportance > NotificationManager.IMPORTANCE_MIN;
Dan Sandler4e787062015-06-17 15:09:48 -0400429 final boolean bMedia = b.key.equals(mediaNotification)
Julia Reynolds85769912016-10-25 09:08:57 -0400430 && bImportance > NotificationManager.IMPORTANCE_MIN;
Dan Sandler4e787062015-06-17 15:09:48 -0400431
Julia Reynolds85769912016-10-25 09:08:57 -0400432 boolean aSystemMax = aImportance >= NotificationManager.IMPORTANCE_HIGH &&
Christoph Studer14921162014-09-03 12:51:26 +0200433 isSystemNotification(na);
Julia Reynolds85769912016-10-25 09:08:57 -0400434 boolean bSystemMax = bImportance >= NotificationManager.IMPORTANCE_HIGH &&
Christoph Studer14921162014-09-03 12:51:26 +0200435 isSystemNotification(nb);
Christoph Studer14921162014-09-03 12:51:26 +0200436
Selim Cinekfbe9a442015-04-13 16:09:49 -0700437 boolean isHeadsUp = a.row.isHeadsUp();
438 if (isHeadsUp != b.row.isHeadsUp()) {
439 return isHeadsUp ? -1 : 1;
440 } else if (isHeadsUp) {
441 // Provide consistent ranking with headsUpManager
442 return mHeadsUpManager.compare(a, b);
Kevina97ea052018-09-11 13:53:18 -0700443 } else if (a.row.isAmbientPulsing() != b.row.isAmbientPulsing()) {
444 return a.row.isAmbientPulsing() ? -1 : 1;
Selim Cinekfbe9a442015-04-13 16:09:49 -0700445 } else if (aMedia != bMedia) {
446 // Upsort current media notification.
447 return aMedia ? -1 : 1;
448 } else if (aSystemMax != bSystemMax) {
449 // Upsort PRIORITY_MAX system notifications
450 return aSystemMax ? -1 : 1;
Chris Wrenbdf33762015-12-04 15:50:51 -0500451 } else if (aRank != bRank) {
452 return aRank - bRank;
Chris Wrenf0048ce2013-08-07 16:43:43 -0400453 } else {
Ian Rogers31756df2016-06-06 14:49:30 -0700454 return Long.compare(nb.getNotification().when, na.getNotification().when);
Chris Wrenf0048ce2013-08-07 16:43:43 -0400455 }
Daniel Sandler379020a2010-07-29 16:20:06 -0400456 }
457 };
Joe Onorato503007d2010-04-16 09:20:55 -0700458
Jason Monk297c04e2018-08-23 17:16:59 -0400459 private KeyguardEnvironment getEnvironment() {
460 if (mEnvironment == null) {
461 mEnvironment = Dependency.get(KeyguardEnvironment.class);
462 }
463 return mEnvironment;
464 }
465
466 private ShadeController getShadeController() {
467 if (mShadeController == null) {
468 mShadeController = Dependency.get(ShadeController.class);
469 }
470 return mShadeController;
471 }
472
473 private NotificationMediaManager getMediaManager() {
474 if (mMediaManager == null) {
475 mMediaManager = Dependency.get(NotificationMediaManager.class);
476 }
477 return mMediaManager;
478 }
479
480 private ForegroundServiceController getFsc() {
481 if (mFsc == null) {
482 mFsc = Dependency.get(ForegroundServiceController.class);
483 }
484 return mFsc;
485 }
486
487 private NotificationLockscreenUserManager getUserManager() {
488 if (mUserManager == null) {
489 mUserManager = Dependency.get(NotificationLockscreenUserManager.class);
490 }
491 return mUserManager;
Joe Onoratoe345fff2010-05-23 15:18:27 -0400492 }
Joe Onorato503007d2010-04-16 09:20:55 -0700493
Christoph Studerc8db24b2014-07-25 17:50:30 +0200494 /**
Jason Monk297c04e2018-08-23 17:16:59 -0400495 * Returns the sorted list of active notifications (depending on {@link KeyguardEnvironment}
Christoph Studerc8db24b2014-07-25 17:50:30 +0200496 *
497 * <p>
498 * This call doesn't update the list of active notifications. Call {@link #filterAndSort()}
499 * when the environment changes.
500 * <p>
501 * Don't hold on to or modify the returned list.
502 */
503 public ArrayList<Entry> getActiveNotifications() {
504 return mSortedAndFiltered;
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400505 }
506
Dieter Hsu36e1ebc2018-06-06 15:41:46 +0800507 public ArrayList<Entry> getNotificationsForCurrentUser() {
508 mFilteredForUser.clear();
509
510 synchronized (mEntries) {
511 final int N = mEntries.size();
512 for (int i = 0; i < N; i++) {
513 Entry entry = mEntries.valueAt(i);
514 final StatusBarNotification sbn = entry.notification;
Jason Monk297c04e2018-08-23 17:16:59 -0400515 if (!getEnvironment().isNotificationForCurrentProfiles(sbn)) {
Dieter Hsu36e1ebc2018-06-06 15:41:46 +0800516 continue;
517 }
518 mFilteredForUser.add(entry);
519 }
520 }
521 return mFilteredForUser;
522 }
523
Christoph Studerc8db24b2014-07-25 17:50:30 +0200524 public Entry get(String key) {
525 return mEntries.get(key);
Joe Onorato0e26dff2010-05-24 16:17:02 -0400526 }
527
Selim Cinek2630dc72017-04-20 15:16:10 -0700528 public void add(Entry entry) {
Julia Reynoldse46bb372016-03-17 11:05:58 -0400529 synchronized (mEntries) {
530 mEntries.put(entry.notification.getKey(), entry);
531 }
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100532 mGroupManager.onEntryAdded(entry);
Dan Sandler008cea72017-05-28 12:18:53 -0400533
Selim Cinek608a57a2017-04-28 16:50:41 -0700534 updateRankingAndSort(mRankingMap);
Daniel Sandler3eebd1f2010-07-27 08:39:33 -0400535 }
536
Christoph Studerd0694b62014-06-04 16:36:01 +0200537 public Entry remove(String key, RankingMap ranking) {
Julia Reynoldse46bb372016-03-17 11:05:58 -0400538 Entry removed = null;
539 synchronized (mEntries) {
540 removed = mEntries.remove(key);
541 }
Christoph Studerc8db24b2014-07-25 17:50:30 +0200542 if (removed == null) return null;
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100543 mGroupManager.onEntryRemoved(removed);
Julia Reynoldse46bb372016-03-17 11:05:58 -0400544 updateRankingAndSort(ranking);
Christoph Studerc8db24b2014-07-25 17:50:30 +0200545 return removed;
Joe Onorato503007d2010-04-16 09:20:55 -0700546 }
Joe Onorato20da8f82010-05-24 16:39:29 -0400547
Christoph Studerd0694b62014-06-04 16:36:01 +0200548 public void updateRanking(RankingMap ranking) {
Christoph Studer37fe6932014-05-26 13:10:30 +0200549 updateRankingAndSort(ranking);
550 }
551
Julia Reynolds91590062018-04-02 16:24:11 -0400552 public void updateAppOp(int appOp, int uid, String pkg, String key, boolean showIcon) {
Julia Reynoldsfc640012018-02-21 12:25:27 -0500553 synchronized (mEntries) {
554 final int N = mEntries.size();
555 for (int i = 0; i < N; i++) {
556 Entry entry = mEntries.valueAt(i);
557 if (uid == entry.notification.getUid()
Julia Reynolds91590062018-04-02 16:24:11 -0400558 && pkg.equals(entry.notification.getPackageName())
559 && key.equals(entry.key)) {
Julia Reynoldsfc640012018-02-21 12:25:27 -0500560 if (showIcon) {
561 entry.mActiveAppOps.add(appOp);
562 } else {
563 entry.mActiveAppOps.remove(appOp);
564 }
565 }
566 }
567 }
568 }
569
Christoph Studer37fe6932014-05-26 13:10:30 +0200570 public boolean isAmbient(String key) {
John Spurlockf079fc52014-08-09 11:10:03 -0400571 if (mRankingMap != null) {
Kensuke Matsuiefa1a742017-08-03 12:12:36 +0900572 getRanking(key, mTmpRanking);
John Spurlockf079fc52014-08-09 11:10:03 -0400573 return mTmpRanking.isAmbient();
574 }
575 return false;
Christoph Studer37fe6932014-05-26 13:10:30 +0200576 }
577
Chris Wren3ad4e3a2014-09-02 17:23:51 -0400578 public int getVisibilityOverride(String key) {
579 if (mRankingMap != null) {
Kensuke Matsuiefa1a742017-08-03 12:12:36 +0900580 getRanking(key, mTmpRanking);
Chris Wren3ad4e3a2014-09-02 17:23:51 -0400581 return mTmpRanking.getVisibilityOverride();
582 }
Julia Reynoldsead00aa2015-12-07 08:23:48 -0500583 return Ranking.VISIBILITY_NO_OVERRIDE;
Chris Wren3ad4e3a2014-09-02 17:23:51 -0400584 }
585
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400586 public boolean shouldSuppressFullScreenIntent(Entry entry) {
587 return shouldSuppressVisualEffect(entry, SUPPRESSED_EFFECT_FULL_SCREEN_INTENT);
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400588 }
589
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400590 public boolean shouldSuppressPeek(Entry entry) {
591 return shouldSuppressVisualEffect(entry, SUPPRESSED_EFFECT_PEEK);
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400592 }
593
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400594 public boolean shouldSuppressStatusBar(Entry entry) {
595 return shouldSuppressVisualEffect(entry, SUPPRESSED_EFFECT_STATUS_BAR);
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400596 }
597
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400598 public boolean shouldSuppressAmbient(Entry entry) {
599 return shouldSuppressVisualEffect(entry, SUPPRESSED_EFFECT_AMBIENT);
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400600 }
601
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400602 public boolean shouldSuppressNotificationList(Entry entry) {
603 return shouldSuppressVisualEffect(entry, SUPPRESSED_EFFECT_NOTIFICATION_LIST);
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400604 }
605
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400606 private boolean shouldSuppressVisualEffect(Entry entry, int effect) {
607 if (isExemptFromDndVisualSuppression(entry)) {
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400608 return false;
609 }
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400610 String key = entry.key;
Julia Reynoldsf612869ae2015-11-05 16:48:55 -0500611 if (mRankingMap != null) {
Kensuke Matsuiefa1a742017-08-03 12:12:36 +0900612 getRanking(key, mTmpRanking);
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400613 return (mTmpRanking.getSuppressedVisualEffects() & effect) != 0;
Julia Reynoldsf612869ae2015-11-05 16:48:55 -0500614 }
615 return false;
616 }
617
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400618 protected boolean isExemptFromDndVisualSuppression(Entry entry) {
Julia Reynolds25926af2018-05-01 17:05:33 -0400619 if (isNotificationBlockedByPolicy(entry.notification.getNotification())) {
620 return false;
621 }
622
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400623 if ((entry.notification.getNotification().flags
624 & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400625 return true;
Julia Reynolds24653c32018-03-02 13:16:37 -0500626 }
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400627 if (entry.notification.getNotification().isMediaNotification()) {
628 return true;
629 }
630 if (entry.mIsSystemNotification != null && entry.mIsSystemNotification) {
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400631 return true;
Julia Reynolds61721582016-01-05 08:35:25 -0500632 }
633 return false;
634 }
635
Julia Reynolds25926af2018-05-01 17:05:33 -0400636 /**
637 * Categories that are explicitly called out on DND settings screens are always blocked, if
638 * DND has flagged them, even if they are foreground or system notifications that might
639 * otherwise visually bypass DND.
640 */
641 protected boolean isNotificationBlockedByPolicy(Notification n) {
642 if (isCategory(CATEGORY_CALL, n)
643 || isCategory(CATEGORY_MESSAGE, n)
644 || isCategory(CATEGORY_ALARM, n)
645 || isCategory(CATEGORY_EVENT, n)
646 || isCategory(CATEGORY_REMINDER, n)) {
647 return true;
648 }
649 return false;
650 }
651
652 private boolean isCategory(String category, Notification n) {
653 return Objects.equals(n.category, category);
654 }
655
Chris Wrenbdf33762015-12-04 15:50:51 -0500656 public int getImportance(String key) {
657 if (mRankingMap != null) {
Kensuke Matsuiefa1a742017-08-03 12:12:36 +0900658 getRanking(key, mTmpRanking);
Chris Wrenbdf33762015-12-04 15:50:51 -0500659 return mTmpRanking.getImportance();
660 }
Julia Reynolds85769912016-10-25 09:08:57 -0400661 return NotificationManager.IMPORTANCE_UNSPECIFIED;
Chris Wrenbdf33762015-12-04 15:50:51 -0500662 }
663
Julia Reynoldse46bb372016-03-17 11:05:58 -0400664 public String getOverrideGroupKey(String key) {
665 if (mRankingMap != null) {
Kensuke Matsuiefa1a742017-08-03 12:12:36 +0900666 getRanking(key, mTmpRanking);
Julia Reynoldse46bb372016-03-17 11:05:58 -0400667 return mTmpRanking.getOverrideGroupKey();
668 }
Tony Mak628cb932018-06-19 18:30:41 +0100669 return null;
Julia Reynoldse46bb372016-03-17 11:05:58 -0400670 }
671
Mady Mellor754d8222017-01-25 15:29:39 -0800672 public List<SnoozeCriterion> getSnoozeCriteria(String key) {
673 if (mRankingMap != null) {
Kensuke Matsuiefa1a742017-08-03 12:12:36 +0900674 getRanking(key, mTmpRanking);
Mady Mellor754d8222017-01-25 15:29:39 -0800675 return mTmpRanking.getSnoozeCriteria();
676 }
677 return null;
678 }
679
Julia Reynolds924eed12017-01-19 09:52:07 -0500680 public NotificationChannel getChannel(String key) {
681 if (mRankingMap != null) {
Kensuke Matsuiefa1a742017-08-03 12:12:36 +0900682 getRanking(key, mTmpRanking);
Julia Reynolds924eed12017-01-19 09:52:07 -0500683 return mTmpRanking.getChannel();
684 }
685 return null;
686 }
687
Dieter Hsud39f0d52018-04-14 02:08:30 +0800688 public int getRank(String key) {
689 if (mRankingMap != null) {
690 getRanking(key, mTmpRanking);
691 return mTmpRanking.getRank();
692 }
693 return 0;
694 }
695
Beverly5a20a5e2018-03-06 15:02:44 -0500696 public boolean shouldHide(String key) {
697 if (mRankingMap != null) {
698 getRanking(key, mTmpRanking);
699 return mTmpRanking.isSuspended();
700 }
701 return false;
702 }
703
Christoph Studerd0694b62014-06-04 16:36:01 +0200704 private void updateRankingAndSort(RankingMap ranking) {
Christoph Studer37fe6932014-05-26 13:10:30 +0200705 if (ranking != null) {
Christoph Studer1d599da2014-06-12 15:25:59 +0200706 mRankingMap = ranking;
Julia Reynoldse46bb372016-03-17 11:05:58 -0400707 synchronized (mEntries) {
708 final int N = mEntries.size();
709 for (int i = 0; i < N; i++) {
710 Entry entry = mEntries.valueAt(i);
Kensuke Matsuiefa1a742017-08-03 12:12:36 +0900711 if (!getRanking(entry.key, mTmpRanking)) {
712 continue;
713 }
Selim Cinek7f09ce12017-06-08 13:20:08 -0700714 final StatusBarNotification oldSbn = entry.notification.cloneLight();
Julia Reynoldse46bb372016-03-17 11:05:58 -0400715 final String overrideGroupKey = getOverrideGroupKey(entry.key);
716 if (!Objects.equals(oldSbn.getOverrideGroupKey(), overrideGroupKey)) {
717 entry.notification.setOverrideGroupKey(overrideGroupKey);
718 mGroupManager.onEntryUpdated(entry, oldSbn);
719 }
Tony Mak628cb932018-06-19 18:30:41 +0100720 entry.populateFromRanking(mTmpRanking);
Julia Reynoldse46bb372016-03-17 11:05:58 -0400721 }
722 }
Christoph Studer37fe6932014-05-26 13:10:30 +0200723 }
Christoph Studerc8db24b2014-07-25 17:50:30 +0200724 filterAndSort();
Christoph Studer37fe6932014-05-26 13:10:30 +0200725 }
726
Kensuke Matsuiefa1a742017-08-03 12:12:36 +0900727 /**
728 * Get the ranking from the current ranking map.
729 *
730 * @param key the key to look up
731 * @param outRanking the ranking to populate
732 *
733 * @return {@code true} if the ranking was properly obtained.
734 */
735 @VisibleForTesting
736 protected boolean getRanking(String key, Ranking outRanking) {
737 return mRankingMap.getRanking(key, outRanking);
738 }
739
Christoph Studerc8db24b2014-07-25 17:50:30 +0200740 // TODO: This should not be public. Instead the Environment should notify this class when
741 // anything changed, and this class should call back the UI so it updates itself.
742 public void filterAndSort() {
743 mSortedAndFiltered.clear();
744
Julia Reynoldse46bb372016-03-17 11:05:58 -0400745 synchronized (mEntries) {
746 final int N = mEntries.size();
747 for (int i = 0; i < N; i++) {
748 Entry entry = mEntries.valueAt(i);
Christoph Studerc8db24b2014-07-25 17:50:30 +0200749
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400750 if (shouldFilterOut(entry)) {
Julia Reynoldse46bb372016-03-17 11:05:58 -0400751 continue;
752 }
753
754 mSortedAndFiltered.add(entry);
Joe Onorato9c1d8232010-05-24 20:02:53 -0400755 }
Christoph Studerc8db24b2014-07-25 17:50:30 +0200756 }
757
Christoph Studerc8db24b2014-07-25 17:50:30 +0200758 Collections.sort(mSortedAndFiltered, mRankingComparator);
759 }
760
Dan Sandler008cea72017-05-28 12:18:53 -0400761 /**
Dan Sandler008cea72017-05-28 12:18:53 -0400762 * @return true if this notification should NOT be shown right now
763 */
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400764 public boolean shouldFilterOut(Entry entry) {
765 final StatusBarNotification sbn = entry.notification;
Jason Monk297c04e2018-08-23 17:16:59 -0400766 if (!(getEnvironment().isDeviceProvisioned() ||
Christoph Studerc8db24b2014-07-25 17:50:30 +0200767 showNotificationEvenIfUnprovisioned(sbn))) {
768 return true;
769 }
770
Jason Monk297c04e2018-08-23 17:16:59 -0400771 if (!getEnvironment().isNotificationForCurrentProfiles(sbn)) {
Christoph Studerc8db24b2014-07-25 17:50:30 +0200772 return true;
773 }
774
Jason Monk297c04e2018-08-23 17:16:59 -0400775 if (getUserManager().isLockscreenPublicMode(sbn.getUserId()) &&
Julia Reynolds26fa8a52016-02-24 08:31:22 -0500776 (sbn.getNotification().visibility == Notification.VISIBILITY_SECRET
Jason Monk297c04e2018-08-23 17:16:59 -0400777 || getUserManager().shouldHideNotifications(sbn.getUserId())
778 || getUserManager().shouldHideNotifications(sbn.getKey()))) {
Christoph Studerc8db24b2014-07-25 17:50:30 +0200779 return true;
Joe Onorato9c1d8232010-05-24 20:02:53 -0400780 }
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100781
Jason Monk297c04e2018-08-23 17:16:59 -0400782 if (getShadeController().isDozing() && shouldSuppressAmbient(entry)) {
Julia Reynolds24653c32018-03-02 13:16:37 -0500783 return true;
784 }
785
Jason Monk297c04e2018-08-23 17:16:59 -0400786 if (!getShadeController().isDozing() && shouldSuppressNotificationList(entry)) {
Julia Reynolds24653c32018-03-02 13:16:37 -0500787 return true;
788 }
789
Beverly5a20a5e2018-03-06 15:02:44 -0500790 if (shouldHide(sbn.getKey())) {
791 return true;
792 }
793
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500794 if (!StatusBar.ENABLE_CHILD_NOTIFICATIONS
Selim Cinekb5605e52015-02-20 18:21:41 +0100795 && mGroupManager.isChildInGroupWithSummary(sbn)) {
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100796 return true;
797 }
Dan Sandler008cea72017-05-28 12:18:53 -0400798
Jason Monk297c04e2018-08-23 17:16:59 -0400799 if (getFsc().isDungeonNotification(sbn)
800 && !getFsc().isDungeonNeededForUser(sbn.getUserId())) {
Dan Sandler008cea72017-05-28 12:18:53 -0400801 // this is a foreground-service disclosure for a user that does not need to show one
802 return true;
803 }
Jason Monk297c04e2018-08-23 17:16:59 -0400804 if (getFsc().isSystemAlertNotification(sbn)) {
Julia Reynolds3c7de112018-03-28 09:33:13 -0400805 final String[] apps = sbn.getNotification().extras.getStringArray(
806 Notification.EXTRA_FOREGROUND_APPS);
807 if (apps != null && apps.length >= 1) {
Jason Monk297c04e2018-08-23 17:16:59 -0400808 if (!getFsc().isSystemAlertWarningNeeded(sbn.getUserId(), apps[0])) {
Julia Reynolds3c7de112018-03-28 09:33:13 -0400809 return true;
810 }
811 }
Julia Reynoldsfc640012018-02-21 12:25:27 -0500812 }
Dan Sandler008cea72017-05-28 12:18:53 -0400813
Joe Onorato9c1d8232010-05-24 20:02:53 -0400814 return false;
Joe Onorato20da8f82010-05-24 16:39:29 -0400815 }
816
Christoph Studerc8db24b2014-07-25 17:50:30 +0200817 // Q: What kinds of notifications should show during setup?
Maurice Lam132710e2017-03-03 19:13:42 -0800818 // A: Almost none! Only things coming from packages with permission
819 // android.permission.NOTIFICATION_DURING_SETUP that also have special "kind" tags marking them
820 // as relevant for setup (see below).
Christoph Studerc8db24b2014-07-25 17:50:30 +0200821 public static boolean showNotificationEvenIfUnprovisioned(StatusBarNotification sbn) {
Maurice Lam132710e2017-03-03 19:13:42 -0800822 return showNotificationEvenIfUnprovisioned(AppGlobals.getPackageManager(), sbn);
823 }
824
825 @VisibleForTesting
826 static boolean showNotificationEvenIfUnprovisioned(IPackageManager packageManager,
827 StatusBarNotification sbn) {
828 return checkUidPermission(packageManager, Manifest.permission.NOTIFICATION_DURING_SETUP,
829 sbn.getUid()) == PackageManager.PERMISSION_GRANTED
Christoph Studerc8db24b2014-07-25 17:50:30 +0200830 && sbn.getNotification().extras.getBoolean(Notification.EXTRA_ALLOW_DURING_SETUP);
831 }
832
Maurice Lam132710e2017-03-03 19:13:42 -0800833 private static int checkUidPermission(IPackageManager packageManager, String permission,
834 int uid) {
835 try {
836 return packageManager.checkUidPermission(permission, uid);
837 } catch (RemoteException e) {
838 throw e.rethrowFromSystemServer();
839 }
840 }
841
Christoph Studerc8db24b2014-07-25 17:50:30 +0200842 public void dump(PrintWriter pw, String indent) {
843 int N = mSortedAndFiltered.size();
844 pw.print(indent);
845 pw.println("active notifications: " + N);
Christoph Studer11840cd2014-08-21 16:41:45 +0200846 int active;
847 for (active = 0; active < N; active++) {
848 NotificationData.Entry e = mSortedAndFiltered.get(active);
849 dumpEntry(pw, indent, active, e);
Christoph Studerc8db24b2014-07-25 17:50:30 +0200850 }
Julia Reynoldse46bb372016-03-17 11:05:58 -0400851 synchronized (mEntries) {
852 int M = mEntries.size();
853 pw.print(indent);
854 pw.println("inactive notifications: " + (M - active));
855 int inactiveCount = 0;
856 for (int i = 0; i < M; i++) {
857 Entry entry = mEntries.valueAt(i);
858 if (!mSortedAndFiltered.contains(entry)) {
859 dumpEntry(pw, indent, inactiveCount, entry);
860 inactiveCount++;
861 }
Christoph Studerc8db24b2014-07-25 17:50:30 +0200862 }
863 }
864 }
865
866 private void dumpEntry(PrintWriter pw, String indent, int i, Entry e) {
Kensuke Matsuiefa1a742017-08-03 12:12:36 +0900867 getRanking(e.key, mTmpRanking);
Christoph Studerc8db24b2014-07-25 17:50:30 +0200868 pw.print(indent);
869 pw.println(" [" + i + "] key=" + e.key + " icon=" + e.icon);
870 StatusBarNotification n = e.notification;
871 pw.print(indent);
Chris Wrenbdf33762015-12-04 15:50:51 -0500872 pw.println(" pkg=" + n.getPackageName() + " id=" + n.getId() + " importance=" +
873 mTmpRanking.getImportance());
Christoph Studerc8db24b2014-07-25 17:50:30 +0200874 pw.print(indent);
875 pw.println(" notification=" + n.getNotification());
Christoph Studerc8db24b2014-07-25 17:50:30 +0200876 }
877
Christoph Studer14921162014-09-03 12:51:26 +0200878 private static boolean isSystemNotification(StatusBarNotification sbn) {
879 String sbnPackage = sbn.getPackageName();
880 return "android".equals(sbnPackage) || "com.android.systemui".equals(sbnPackage);
881 }
882
Christoph Studerc8db24b2014-07-25 17:50:30 +0200883 /**
884 * Provides access to keyguard state and user settings dependent data.
885 */
Jason Monk297c04e2018-08-23 17:16:59 -0400886 public interface KeyguardEnvironment {
887 boolean isDeviceProvisioned();
888 boolean isNotificationForCurrentProfiles(StatusBarNotification sbn);
Christoph Studerc8db24b2014-07-25 17:50:30 +0200889 }
Joe Onorato503007d2010-04-16 09:20:55 -0700890}