OSDN Git Service

[automerger] Fix Layout.primaryIsTrailingPreviousAllLineOffsets am: d3e81cd63f
[android-x86/frameworks-base.git] / services / core / java / com / android / server / notification / NotificationManagerService.java
1 /*
2  * Copyright (C) 2007 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.server.notification;
18
19 import static android.app.NotificationManager.IMPORTANCE_MIN;
20 import static android.app.NotificationManager.IMPORTANCE_NONE;
21 import static android.content.pm.PackageManager.FEATURE_LEANBACK;
22 import static android.content.pm.PackageManager.FEATURE_TELEVISION;
23 import static android.service.notification.NotificationListenerService
24         .NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
25 import static android.service.notification.NotificationListenerService
26         .NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
27 import static android.service.notification.NotificationListenerService
28         .NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
29 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
30 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
31 import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
32 import static android.service.notification.NotificationListenerService.REASON_CANCEL;
33 import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
34 import static android.service.notification.NotificationListenerService.REASON_CLICK;
35 import static android.service.notification.NotificationListenerService.REASON_ERROR;
36 import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
37 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL;
38 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL;
39 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED;
40 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED;
41 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED;
42 import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF;
43 import static android.service.notification.NotificationListenerService.REASON_SNOOZED;
44 import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
45 import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
46 import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
47 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
48 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
49 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
50 import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
51 import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
52 import static android.service.notification.NotificationListenerService.TRIM_FULL;
53 import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
54
55 import static android.view.Display.DEFAULT_DISPLAY;
56 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
57 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
58
59 import android.Manifest;
60 import android.annotation.NonNull;
61 import android.annotation.Nullable;
62 import android.app.ActivityManager;
63 import android.app.ActivityManagerInternal;
64 import android.app.AlarmManager;
65 import android.app.AppGlobals;
66 import android.app.AppOpsManager;
67 import android.app.AutomaticZenRule;
68 import android.app.NotificationChannelGroup;
69 import android.app.backup.BackupManager;
70 import android.app.IActivityManager;
71 import android.app.INotificationManager;
72 import android.app.ITransientNotification;
73 import android.app.Notification;
74 import android.app.NotificationChannel;
75 import android.app.NotificationManager.Policy;
76 import android.app.NotificationManager;
77 import android.app.PendingIntent;
78 import android.app.StatusBarManager;
79 import android.app.usage.UsageEvents;
80 import android.app.usage.UsageStatsManagerInternal;
81 import android.companion.ICompanionDeviceManager;
82 import android.content.BroadcastReceiver;
83 import android.content.ComponentName;
84 import android.content.ContentResolver;
85 import android.content.Context;
86 import android.content.Intent;
87 import android.content.IntentFilter;
88 import android.content.pm.ApplicationInfo;
89 import android.content.pm.IPackageManager;
90 import android.content.pm.PackageInfo;
91 import android.content.pm.PackageManager;
92 import android.content.pm.PackageManager.NameNotFoundException;
93 import android.content.pm.ParceledListSlice;
94 import android.content.res.Resources;
95 import android.database.ContentObserver;
96 import android.media.AudioManager;
97 import android.media.AudioManagerInternal;
98 import android.media.IRingtonePlayer;
99 import android.media.ToneGenerator;
100 import android.net.Uri;
101 import android.os.Binder;
102 import android.os.Build;
103 import android.os.Bundle;
104 import android.os.Environment;
105 import android.os.Handler;
106 import android.os.HandlerThread;
107 import android.os.IBinder;
108 import android.os.IInterface;
109 import android.os.Looper;
110 import android.os.Message;
111 import android.os.Process;
112 import android.os.RemoteException;
113 import android.os.ServiceManager;
114 import android.os.SystemClock;
115 import android.os.SystemProperties;
116 import android.os.UserHandle;
117 import android.os.Vibrator;
118 import android.os.VibrationEffect;
119 import android.provider.Settings;
120 import android.service.notification.Adjustment;
121 import android.service.notification.Condition;
122 import android.service.notification.IConditionProvider;
123 import android.service.notification.INotificationListener;
124 import android.service.notification.IStatusBarNotificationHolder;
125 import android.service.notification.NotificationAssistantService;
126 import android.service.notification.NotificationListenerService;
127 import android.service.notification.NotificationRankingUpdate;
128 import android.service.notification.NotificationRecordProto;
129 import android.service.notification.NotificationServiceDumpProto;
130 import android.service.notification.NotificationServiceProto;
131 import android.service.notification.SnoozeCriterion;
132 import android.service.notification.StatusBarNotification;
133 import android.service.notification.ZenModeConfig;
134 import android.service.notification.ZenModeProto;
135 import android.telephony.PhoneStateListener;
136 import android.telephony.TelephonyManager;
137 import android.text.TextUtils;
138 import android.util.ArrayMap;
139 import android.util.ArraySet;
140 import android.util.AtomicFile;
141 import android.util.Log;
142 import android.util.Slog;
143 import android.util.SparseArray;
144 import android.util.Xml;
145 import android.util.proto.ProtoOutputStream;
146 import android.view.WindowManagerInternal;
147 import android.view.accessibility.AccessibilityEvent;
148 import android.view.accessibility.AccessibilityManager;
149 import android.widget.Toast;
150
151 import com.android.internal.R;
152 import com.android.internal.annotations.GuardedBy;
153 import com.android.internal.annotations.VisibleForTesting;
154 import com.android.internal.logging.MetricsLogger;
155 import com.android.internal.logging.nano.MetricsProto;
156 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
157 import com.android.internal.statusbar.NotificationVisibility;
158 import com.android.internal.util.ArrayUtils;
159 import com.android.internal.util.DumpUtils;
160 import com.android.internal.util.FastXmlSerializer;
161 import com.android.internal.util.Preconditions;
162 import com.android.server.DeviceIdleController;
163 import com.android.server.EventLogTags;
164 import com.android.server.LocalServices;
165 import com.android.server.SystemService;
166 import com.android.server.lights.Light;
167 import com.android.server.lights.LightsManager;
168 import com.android.server.notification.ManagedServices.ManagedServiceInfo;
169 import com.android.server.policy.PhoneWindowManager;
170 import com.android.server.statusbar.StatusBarManagerInternal;
171 import com.android.server.notification.ManagedServices.UserProfiles;
172
173 import libcore.io.IoUtils;
174
175 import org.json.JSONException;
176 import org.json.JSONObject;
177 import org.xmlpull.v1.XmlPullParser;
178 import org.xmlpull.v1.XmlPullParserException;
179 import org.xmlpull.v1.XmlSerializer;
180
181 import java.io.ByteArrayInputStream;
182 import java.io.ByteArrayOutputStream;
183 import java.io.File;
184 import java.io.FileDescriptor;
185 import java.io.FileInputStream;
186 import java.io.FileNotFoundException;
187 import java.io.FileOutputStream;
188 import java.io.IOException;
189 import java.io.InputStream;
190 import java.io.OutputStream;
191 import java.io.PrintWriter;
192 import java.nio.charset.StandardCharsets;
193 import java.util.ArrayDeque;
194 import java.util.ArrayList;
195 import java.util.Arrays;
196 import java.util.Iterator;
197 import java.util.List;
198 import java.util.Map;
199 import java.util.Map.Entry;
200 import java.util.Objects;
201 import java.util.concurrent.TimeUnit;
202
203 /** {@hide} */
204 public class NotificationManagerService extends SystemService {
205     static final String TAG = "NotificationService";
206     static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
207     public static final boolean ENABLE_CHILD_NOTIFICATIONS
208             = SystemProperties.getBoolean("debug.child_notifs", true);
209
210     static final int MAX_PACKAGE_NOTIFICATIONS = 50;
211     static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 10f;
212
213     // message codes
214     static final int MESSAGE_TIMEOUT = 2;
215     static final int MESSAGE_SAVE_POLICY_FILE = 3;
216     static final int MESSAGE_SEND_RANKING_UPDATE = 4;
217     static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
218     static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
219
220     // ranking thread messages
221     private static final int MESSAGE_RECONSIDER_RANKING = 1000;
222     private static final int MESSAGE_RANKING_SORT = 1001;
223
224     static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
225     static final int SHORT_DELAY = 2000; // 2 seconds
226
227     static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
228
229     static final long SNOOZE_UNTIL_UNSPECIFIED = -1;
230
231     static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
232
233     static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
234
235     static final boolean ENABLE_BLOCKED_TOASTS = true;
236
237     // When #matchesCallFilter is called from the ringer, wait at most
238     // 3s to resolve the contacts. This timeout is required since
239     // ContactsProvider might take a long time to start up.
240     //
241     // Return STARRED_CONTACT when the timeout is hit in order to avoid
242     // missed calls in ZEN mode "Important".
243     static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
244     static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
245             ValidateNotificationPeople.STARRED_CONTACT;
246
247     /** notification_enqueue status value for a newly enqueued notification. */
248     private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
249
250     /** notification_enqueue status value for an existing notification. */
251     private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
252
253     /** notification_enqueue status value for an ignored notification. */
254     private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
255     private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
256
257     private static final long DELAY_FOR_ASSISTANT_TIME = 100;
258
259     private static final String ACTION_NOTIFICATION_TIMEOUT =
260             NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
261     private static final int REQUEST_CODE_TIMEOUT = 1;
262     private static final String SCHEME_TIMEOUT = "timeout";
263     private static final String EXTRA_KEY = "key";
264
265     private IActivityManager mAm;
266     private IPackageManager mPackageManager;
267     private PackageManager mPackageManagerClient;
268     AudioManager mAudioManager;
269     AudioManagerInternal mAudioManagerInternal;
270     @Nullable StatusBarManagerInternal mStatusBar;
271     Vibrator mVibrator;
272     private WindowManagerInternal mWindowManagerInternal;
273     private AlarmManager mAlarmManager;
274     private ICompanionDeviceManager mCompanionManager;
275
276     final IBinder mForegroundToken = new Binder();
277     private Handler mHandler;
278     private final HandlerThread mRankingThread = new HandlerThread("ranker",
279             Process.THREAD_PRIORITY_BACKGROUND);
280
281     private Light mNotificationLight;
282     Light mAttentionLight;
283
284     private long[] mFallbackVibrationPattern;
285     private boolean mUseAttentionLight;
286     boolean mSystemReady;
287
288     private boolean mDisableNotificationEffects;
289     private int mCallState;
290     private String mSoundNotificationKey;
291     private String mVibrateNotificationKey;
292
293     private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
294             new SparseArray<ArraySet<ManagedServiceInfo>>();
295     private List<ComponentName> mEffectsSuppressors = new ArrayList<ComponentName>();
296     private int mListenerHints;  // right now, all hints are global
297     private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
298
299     // for enabling and disabling notification pulse behavior
300     private boolean mScreenOn = true;
301     private boolean mInCall = false;
302     private boolean mNotificationPulseEnabled;
303
304     // for generating notification tones in-call
305     private ToneGenerator mInCallToneGenerator;
306     private final Object mInCallToneGeneratorLock = new Object();
307
308     // used as a mutex for access to all active notifications & listeners
309     final Object mNotificationLock = new Object();
310     @GuardedBy("mNotificationLock")
311     final ArrayList<NotificationRecord> mNotificationList =
312             new ArrayList<NotificationRecord>();
313     @GuardedBy("mNotificationLock")
314     final ArrayMap<String, NotificationRecord> mNotificationsByKey =
315             new ArrayMap<String, NotificationRecord>();
316     @GuardedBy("mNotificationLock")
317     final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();
318     @GuardedBy("mNotificationLock")
319     final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
320     final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();
321     final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
322     final PolicyAccess mPolicyAccess = new PolicyAccess();
323
324     // The last key in this list owns the hardware.
325     ArrayList<String> mLights = new ArrayList<>();
326
327     private AppOpsManager mAppOps;
328     private UsageStatsManagerInternal mAppUsageStats;
329
330     private Archive mArchive;
331
332     // Persistent storage for notification policy
333     private AtomicFile mPolicyFile;
334
335     private static final int DB_VERSION = 1;
336
337     private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
338     private static final String ATTR_VERSION = "version";
339
340     private RankingHelper mRankingHelper;
341
342     private final UserProfiles mUserProfiles = new UserProfiles();
343     private NotificationListeners mListeners;
344     private NotificationAssistants mNotificationAssistants;
345     private ConditionProviders mConditionProviders;
346     private NotificationUsageStats mUsageStats;
347
348     private static final int MY_UID = Process.myUid();
349     private static final int MY_PID = Process.myPid();
350     private static final IBinder WHITELIST_TOKEN = new Binder();
351     private RankingHandler mRankingHandler;
352     private long mLastOverRateLogTime;
353     private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
354
355     private SnoozeHelper mSnoozeHelper;
356     private GroupHelper mGroupHelper;
357     private boolean mIsTelevision;
358
359     private static class Archive {
360         final int mBufferSize;
361         final ArrayDeque<StatusBarNotification> mBuffer;
362
363         public Archive(int size) {
364             mBufferSize = size;
365             mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
366         }
367
368         public String toString() {
369             final StringBuilder sb = new StringBuilder();
370             final int N = mBuffer.size();
371             sb.append("Archive (");
372             sb.append(N);
373             sb.append(" notification");
374             sb.append((N==1)?")":"s)");
375             return sb.toString();
376         }
377
378         public void record(StatusBarNotification nr) {
379             if (mBuffer.size() == mBufferSize) {
380                 mBuffer.removeFirst();
381             }
382
383             // We don't want to store the heavy bits of the notification in the archive,
384             // but other clients in the system process might be using the object, so we
385             // store a (lightened) copy.
386             mBuffer.addLast(nr.cloneLight());
387         }
388
389         public Iterator<StatusBarNotification> descendingIterator() {
390             return mBuffer.descendingIterator();
391         }
392
393         public StatusBarNotification[] getArray(int count) {
394             if (count == 0) count = mBufferSize;
395             final StatusBarNotification[] a
396                     = new StatusBarNotification[Math.min(count, mBuffer.size())];
397             Iterator<StatusBarNotification> iter = descendingIterator();
398             int i=0;
399             while (iter.hasNext() && i < count) {
400                 a[i++] = iter.next();
401             }
402             return a;
403         }
404
405     }
406
407     private void readPolicyXml(InputStream stream, boolean forRestore)
408             throws XmlPullParserException, NumberFormatException, IOException {
409         final XmlPullParser parser = Xml.newPullParser();
410         parser.setInput(stream, StandardCharsets.UTF_8.name());
411
412         while (parser.next() != END_DOCUMENT) {
413             mZenModeHelper.readXml(parser, forRestore);
414             mRankingHelper.readXml(parser, forRestore);
415         }
416     }
417
418     private void loadPolicyFile() {
419         if (DBG) Slog.d(TAG, "loadPolicyFile");
420         synchronized (mPolicyFile) {
421
422             FileInputStream infile = null;
423             try {
424                 infile = mPolicyFile.openRead();
425                 readPolicyXml(infile, false /*forRestore*/);
426             } catch (FileNotFoundException e) {
427                 // No data yet
428             } catch (IOException e) {
429                 Log.wtf(TAG, "Unable to read notification policy", e);
430             } catch (NumberFormatException e) {
431                 Log.wtf(TAG, "Unable to parse notification policy", e);
432             } catch (XmlPullParserException e) {
433                 Log.wtf(TAG, "Unable to parse notification policy", e);
434             } finally {
435                 IoUtils.closeQuietly(infile);
436             }
437         }
438     }
439
440     public void savePolicyFile() {
441         mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
442         mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
443     }
444
445     private void handleSavePolicyFile() {
446         if (DBG) Slog.d(TAG, "handleSavePolicyFile");
447         synchronized (mPolicyFile) {
448             final FileOutputStream stream;
449             try {
450                 stream = mPolicyFile.startWrite();
451             } catch (IOException e) {
452                 Slog.w(TAG, "Failed to save policy file", e);
453                 return;
454             }
455
456             try {
457                 writePolicyXml(stream, false /*forBackup*/);
458                 mPolicyFile.finishWrite(stream);
459             } catch (IOException e) {
460                 Slog.w(TAG, "Failed to save policy file, restoring backup", e);
461                 mPolicyFile.failWrite(stream);
462             }
463         }
464         BackupManager.dataChanged(getContext().getPackageName());
465     }
466
467     private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
468         final XmlSerializer out = new FastXmlSerializer();
469         out.setOutput(stream, StandardCharsets.UTF_8.name());
470         out.startDocument(null, true);
471         out.startTag(null, TAG_NOTIFICATION_POLICY);
472         out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
473         mZenModeHelper.writeXml(out, forBackup);
474         mRankingHelper.writeXml(out, forBackup);
475         out.endTag(null, TAG_NOTIFICATION_POLICY);
476         out.endDocument();
477     }
478
479     /** Use this to check if a package can post a notification or toast. */
480     private boolean checkNotificationOp(String pkg, int uid) {
481         return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
482                 == AppOpsManager.MODE_ALLOWED && !isPackageSuspendedForUser(pkg, uid);
483     }
484
485     private static final class ToastRecord
486     {
487         final int pid;
488         final String pkg;
489         final ITransientNotification callback;
490         int duration;
491         Binder token;
492
493         ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
494                     Binder token) {
495             this.pid = pid;
496             this.pkg = pkg;
497             this.callback = callback;
498             this.duration = duration;
499             this.token = token;
500         }
501
502         void update(int duration) {
503             this.duration = duration;
504         }
505
506         void dump(PrintWriter pw, String prefix, DumpFilter filter) {
507             if (filter != null && !filter.matches(pkg)) return;
508             pw.println(prefix + this);
509         }
510
511         @Override
512         public final String toString()
513         {
514             return "ToastRecord{"
515                 + Integer.toHexString(System.identityHashCode(this))
516                 + " pkg=" + pkg
517                 + " callback=" + callback
518                 + " duration=" + duration;
519         }
520     }
521
522     @VisibleForTesting
523     final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
524
525         @Override
526         public void onSetDisabled(int status) {
527             synchronized (mNotificationLock) {
528                 mDisableNotificationEffects =
529                         (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
530                 if (disableNotificationEffects(null) != null) {
531                     // cancel whatever's going on
532                     long identity = Binder.clearCallingIdentity();
533                     try {
534                         final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
535                         if (player != null) {
536                             player.stopAsync();
537                         }
538                     } catch (RemoteException e) {
539                     } finally {
540                         Binder.restoreCallingIdentity(identity);
541                     }
542
543                     identity = Binder.clearCallingIdentity();
544                     try {
545                         mVibrator.cancel();
546                     } finally {
547                         Binder.restoreCallingIdentity(identity);
548                     }
549                 }
550             }
551         }
552
553         @Override
554         public void onClearAll(int callingUid, int callingPid, int userId) {
555             synchronized (mNotificationLock) {
556                 cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null,
557                         /*includeCurrentProfiles*/ true);
558             }
559         }
560
561         @Override
562         public void onNotificationClick(int callingUid, int callingPid, String key) {
563             synchronized (mNotificationLock) {
564                 NotificationRecord r = mNotificationsByKey.get(key);
565                 if (r == null) {
566                     Log.w(TAG, "No notification with key: " + key);
567                     return;
568                 }
569                 final long now = System.currentTimeMillis();
570                 MetricsLogger.action(r.getLogMaker(now)
571                         .setCategory(MetricsEvent.NOTIFICATION_ITEM)
572                         .setType(MetricsEvent.TYPE_ACTION));
573                 EventLogTags.writeNotificationClicked(key,
574                         r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
575
576                 StatusBarNotification sbn = r.sbn;
577                 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
578                         sbn.getId(), Notification.FLAG_AUTO_CANCEL,
579                         Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
580                         REASON_CLICK, null);
581             }
582         }
583
584         @Override
585         public void onNotificationActionClick(int callingUid, int callingPid, String key,
586                 int actionIndex) {
587             synchronized (mNotificationLock) {
588                 NotificationRecord r = mNotificationsByKey.get(key);
589                 if (r == null) {
590                     Log.w(TAG, "No notification with key: " + key);
591                     return;
592                 }
593                 final long now = System.currentTimeMillis();
594                 MetricsLogger.action(r.getLogMaker(now)
595                         .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION)
596                         .setType(MetricsEvent.TYPE_ACTION)
597                         .setSubtype(actionIndex));
598                 EventLogTags.writeNotificationActionClicked(key, actionIndex,
599                         r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
600                 // TODO: Log action click via UsageStats.
601             }
602         }
603
604         @Override
605         public void onNotificationClear(int callingUid, int callingPid,
606                 String pkg, String tag, int id, int userId) {
607             cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
608                     Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
609                     true, userId, REASON_CANCEL, null);
610         }
611
612         @Override
613         public void onPanelRevealed(boolean clearEffects, int items) {
614             MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL);
615             MetricsLogger.histogram(getContext(), "note_load", items);
616             EventLogTags.writeNotificationPanelRevealed(items);
617             if (clearEffects) {
618                 clearEffects();
619             }
620         }
621
622         @Override
623         public void onPanelHidden() {
624             MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL);
625             EventLogTags.writeNotificationPanelHidden();
626         }
627
628         @Override
629         public void clearEffects() {
630             synchronized (mNotificationLock) {
631                 if (DBG) Slog.d(TAG, "clearEffects");
632                 clearSoundLocked();
633                 clearVibrateLocked();
634                 clearLightsLocked();
635             }
636         }
637
638         @Override
639         public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
640                 int uid, int initialPid, String message, int userId) {
641             Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
642                     + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
643             cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
644                     REASON_ERROR, null);
645             long ident = Binder.clearCallingIdentity();
646             try {
647                 ActivityManager.getService().crashApplication(uid, initialPid, pkg, -1,
648                         "Bad notification posted from package " + pkg
649                         + ": " + message);
650             } catch (RemoteException e) {
651             }
652             Binder.restoreCallingIdentity(ident);
653         }
654
655         @Override
656         public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
657                 NotificationVisibility[] noLongerVisibleKeys) {
658             synchronized (mNotificationLock) {
659                 for (NotificationVisibility nv : newlyVisibleKeys) {
660                     NotificationRecord r = mNotificationsByKey.get(nv.key);
661                     if (r == null) continue;
662                     r.setVisibility(true, nv.rank);
663                     nv.recycle();
664                 }
665                 // Note that we might receive this event after notifications
666                 // have already left the system, e.g. after dismissing from the
667                 // shade. Hence not finding notifications in
668                 // mNotificationsByKey is not an exceptional condition.
669                 for (NotificationVisibility nv : noLongerVisibleKeys) {
670                     NotificationRecord r = mNotificationsByKey.get(nv.key);
671                     if (r == null) continue;
672                     r.setVisibility(false, nv.rank);
673                     nv.recycle();
674                 }
675             }
676         }
677
678         @Override
679         public void onNotificationExpansionChanged(String key,
680                 boolean userAction, boolean expanded) {
681             synchronized (mNotificationLock) {
682                 NotificationRecord r = mNotificationsByKey.get(key);
683                 if (r != null) {
684                     r.stats.onExpansionChanged(userAction, expanded);
685                     final long now = System.currentTimeMillis();
686                     MetricsLogger.action(r.getLogMaker(now)
687                             .setCategory(MetricsEvent.NOTIFICATION_ITEM)
688                             .setType(MetricsEvent.TYPE_DETAIL));
689                     EventLogTags.writeNotificationExpansion(key,
690                             userAction ? 1 : 0, expanded ? 1 : 0,
691                             r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
692                 }
693             }
694         }
695     };
696
697     @GuardedBy("mNotificationLock")
698     private void clearSoundLocked() {
699         mSoundNotificationKey = null;
700         long identity = Binder.clearCallingIdentity();
701         try {
702             final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
703             if (player != null) {
704                 player.stopAsync();
705             }
706         } catch (RemoteException e) {
707         } finally {
708             Binder.restoreCallingIdentity(identity);
709         }
710     }
711
712     @GuardedBy("mNotificationLock")
713     private void clearVibrateLocked() {
714         mVibrateNotificationKey = null;
715         long identity = Binder.clearCallingIdentity();
716         try {
717             mVibrator.cancel();
718         } finally {
719             Binder.restoreCallingIdentity(identity);
720         }
721     }
722
723     @GuardedBy("mNotificationLock")
724     private void clearLightsLocked() {
725         // light
726         mLights.clear();
727         updateLightsLocked();
728     }
729
730     private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() {
731         @Override
732         public void onReceive(Context context, Intent intent) {
733             String action = intent.getAction();
734             if (action == null) {
735                 return;
736             }
737             if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) {
738                 final NotificationRecord record;
739                 synchronized (mNotificationLock) {
740                     record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
741                 }
742                 if (record != null) {
743                     cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(),
744                             record.sbn.getPackageName(), record.sbn.getTag(),
745                             record.sbn.getId(), 0,
746                             Notification.FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
747                             REASON_TIMEOUT, null);
748                 }
749             }
750         }
751     };
752
753     private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
754         @Override
755         public void onReceive(Context context, Intent intent) {
756             String action = intent.getAction();
757             if (action == null) {
758                 return;
759             }
760
761             boolean queryRestart = false;
762             boolean queryRemove = false;
763             boolean packageChanged = false;
764             boolean cancelNotifications = true;
765             int reason = REASON_PACKAGE_CHANGED;
766
767             if (action.equals(Intent.ACTION_PACKAGE_ADDED)
768                     || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
769                     || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
770                     || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
771                     || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
772                     || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
773                     || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
774                 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
775                         UserHandle.USER_ALL);
776                 String pkgList[] = null;
777                 int uidList[] = null;
778                 boolean removingPackage = queryRemove &&
779                         !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
780                 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
781                 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
782                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
783                     uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
784                 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
785                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
786                     reason = REASON_PACKAGE_SUSPENDED;
787                 } else if (queryRestart) {
788                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
789                     uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
790                 } else {
791                     Uri uri = intent.getData();
792                     if (uri == null) {
793                         return;
794                     }
795                     String pkgName = uri.getSchemeSpecificPart();
796                     if (pkgName == null) {
797                         return;
798                     }
799                     if (packageChanged) {
800                         // We cancel notifications for packages which have just been disabled
801                         try {
802                             final int enabled = mPackageManager.getApplicationEnabledSetting(
803                                     pkgName,
804                                     changeUserId != UserHandle.USER_ALL ? changeUserId :
805                                             UserHandle.USER_SYSTEM);
806                             if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
807                                     || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
808                                 cancelNotifications = false;
809                             }
810                         } catch (IllegalArgumentException e) {
811                             // Package doesn't exist; probably racing with uninstall.
812                             // cancelNotifications is already true, so nothing to do here.
813                             if (DBG) {
814                                 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
815                             }
816                         } catch (RemoteException e) {
817                             // Failed to talk to PackageManagerService Should never happen!
818                         }
819                     }
820                     pkgList = new String[]{pkgName};
821                     uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
822                 }
823                 if (pkgList != null && (pkgList.length > 0)) {
824                     for (String pkgName : pkgList) {
825                         if (cancelNotifications) {
826                             cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0,
827                                     !queryRestart, changeUserId, reason, null);
828                         }
829                     }
830                 }
831                 mListeners.onPackagesChanged(removingPackage, pkgList);
832                 mNotificationAssistants.onPackagesChanged(removingPackage, pkgList);
833                 mConditionProviders.onPackagesChanged(removingPackage, pkgList);
834                 mRankingHelper.onPackagesChanged(removingPackage, changeUserId, pkgList, uidList);
835                 savePolicyFile();
836             }
837         }
838     };
839
840     private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
841         @Override
842         public void onReceive(Context context, Intent intent) {
843             String action = intent.getAction();
844
845             if (action.equals(Intent.ACTION_SCREEN_ON)) {
846                 // Keep track of screen on/off state, but do not turn off the notification light
847                 // until user passes through the lock screen or views the notification.
848                 mScreenOn = true;
849                 updateNotificationPulse();
850             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
851                 mScreenOn = false;
852                 updateNotificationPulse();
853             } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
854                 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
855                         .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
856                 updateNotificationPulse();
857                 synchronized (mInCallToneGeneratorLock) {
858                     if (mInCall) {
859                         if (mInCallToneGenerator == null) {
860                             int relativeToneVolume = getContext().getResources().getInteger(
861                                     R.integer.config_inCallNotificationVolumeRelative);
862                             if (relativeToneVolume < ToneGenerator.MIN_VOLUME
863                                     || relativeToneVolume > ToneGenerator.MAX_VOLUME) {
864                                 relativeToneVolume = ToneGenerator.MAX_VOLUME;
865                             }
866                             try {
867                                 mInCallToneGenerator = new ToneGenerator(
868                                         AudioManager.STREAM_VOICE_CALL, relativeToneVolume);
869                             } catch (RuntimeException e) {
870                                 Log.e(TAG, "Error creating local tone generator: " + e);
871                                 mInCallToneGenerator = null;
872                             }
873                         }
874                     } else {
875                         if (mInCallToneGenerator != null) {
876                             mInCallToneGenerator.release();
877                             mInCallToneGenerator = null;
878                         }
879                      }
880                 }
881             } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
882                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
883                 if (userHandle >= 0) {
884                     cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
885                             REASON_USER_STOPPED, null);
886                 }
887             } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
888                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
889                 if (userHandle >= 0) {
890                     cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
891                             REASON_PROFILE_TURNED_OFF, null);
892                 }
893             } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
894                 // turn off LED when user passes through lock screen
895                 mNotificationLight.turnOff();
896             } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
897                 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
898                 // reload per-user settings
899                 mSettingsObserver.update(null);
900                 mUserProfiles.updateCache(context);
901                 // Refresh managed services
902                 mConditionProviders.onUserSwitched(user);
903                 mListeners.onUserSwitched(user);
904                 mNotificationAssistants.onUserSwitched(user);
905                 mZenModeHelper.onUserSwitched(user);
906             } else if (action.equals(Intent.ACTION_USER_ADDED)) {
907                 mUserProfiles.updateCache(context);
908             } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
909                 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
910                 mZenModeHelper.onUserRemoved(user);
911                 mRankingHelper.onUserRemoved(user);
912                 savePolicyFile();
913             } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
914                 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
915                 mConditionProviders.onUserUnlocked(user);
916                 mListeners.onUserUnlocked(user);
917                 mNotificationAssistants.onUserUnlocked(user);
918                 mZenModeHelper.onUserUnlocked(user);
919             }
920         }
921     };
922
923     private final class SettingsObserver extends ContentObserver {
924         private final Uri NOTIFICATION_BADGING_URI
925                 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING);
926         private final Uri NOTIFICATION_LIGHT_PULSE_URI
927                 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
928         private final Uri NOTIFICATION_RATE_LIMIT_URI
929                 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
930
931         SettingsObserver(Handler handler) {
932             super(handler);
933         }
934
935         void observe() {
936             ContentResolver resolver = getContext().getContentResolver();
937             resolver.registerContentObserver(NOTIFICATION_BADGING_URI,
938                     false, this, UserHandle.USER_ALL);
939             resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
940                     false, this, UserHandle.USER_ALL);
941             resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
942                     false, this, UserHandle.USER_ALL);
943             update(null);
944         }
945
946         @Override public void onChange(boolean selfChange, Uri uri) {
947             update(uri);
948         }
949
950         public void update(Uri uri) {
951             ContentResolver resolver = getContext().getContentResolver();
952             if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
953                 boolean pulseEnabled = Settings.System.getInt(resolver,
954                             Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
955                 if (mNotificationPulseEnabled != pulseEnabled) {
956                     mNotificationPulseEnabled = pulseEnabled;
957                     updateNotificationPulse();
958                 }
959             }
960             if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
961                 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
962                             Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
963             }
964             if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) {
965                 mRankingHelper.updateBadgingEnabled();
966             }
967         }
968     }
969
970     private SettingsObserver mSettingsObserver;
971     private ZenModeHelper mZenModeHelper;
972
973     static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
974         int[] ar = r.getIntArray(resid);
975         if (ar == null) {
976             return def;
977         }
978         final int len = ar.length > maxlen ? maxlen : ar.length;
979         long[] out = new long[len];
980         for (int i=0; i<len; i++) {
981             out[i] = ar[i];
982         }
983         return out;
984     }
985
986     public NotificationManagerService(Context context) {
987         super(context);
988         Notification.processWhitelistToken = WHITELIST_TOKEN;
989     }
990
991     // TODO - replace these methods with a single VisibleForTesting constructor
992     @VisibleForTesting
993     void setAudioManager(AudioManager audioMananger) {
994         mAudioManager = audioMananger;
995     }
996
997     @VisibleForTesting
998     void setVibrator(Vibrator vibrator) {
999         mVibrator = vibrator;
1000     }
1001
1002     @VisibleForTesting
1003     void setLights(Light light) {
1004         mNotificationLight = light;
1005         mAttentionLight = light;
1006         mNotificationPulseEnabled = true;
1007     }
1008
1009     @VisibleForTesting
1010     void setScreenOn(boolean on) {
1011         mScreenOn = on;
1012     }
1013
1014     @VisibleForTesting
1015     int getNotificationRecordCount() {
1016         synchronized (mNotificationLock) {
1017             int count = mNotificationList.size() + mNotificationsByKey.size()
1018                     + mSummaryByGroupKey.size() + mEnqueuedNotifications.size();
1019             // subtract duplicates
1020             for (NotificationRecord posted : mNotificationList) {
1021                 if (mNotificationsByKey.containsKey(posted.getKey())) {
1022                     count--;
1023                 }
1024                 if (posted.sbn.isGroup() && posted.getNotification().isGroupSummary()) {
1025                     count --;
1026                 }
1027             }
1028
1029             return count;
1030         }
1031     }
1032
1033     @VisibleForTesting
1034     void addNotification(NotificationRecord r) {
1035         mNotificationList.add(r);
1036         mNotificationsByKey.put(r.sbn.getKey(), r);
1037         if (r.sbn.isGroup()) {
1038             mSummaryByGroupKey.put(r.getGroupKey(), r);
1039         }
1040     }
1041
1042     @VisibleForTesting
1043     void addEnqueuedNotification(NotificationRecord r) {
1044         mEnqueuedNotifications.add(r);
1045     }
1046
1047     @VisibleForTesting
1048     void setSystemReady(boolean systemReady) {
1049         mSystemReady = systemReady;
1050     }
1051
1052     @VisibleForTesting
1053     void setHandler(Handler handler) {
1054         mHandler = handler;
1055     }
1056
1057     @VisibleForTesting
1058     void setFallbackVibrationPattern(long[] vibrationPattern) {
1059         mFallbackVibrationPattern = vibrationPattern;
1060     }
1061
1062     @VisibleForTesting
1063     void setPackageManager(IPackageManager packageManager) {
1064         mPackageManager = packageManager;
1065     }
1066
1067     @VisibleForTesting
1068     void setRankingHelper(RankingHelper rankingHelper) {
1069         mRankingHelper = rankingHelper;
1070     }
1071
1072     @VisibleForTesting
1073     void setIsTelevision(boolean isTelevision) {
1074         mIsTelevision = isTelevision;
1075     }
1076
1077     // TODO: Tests should call onStart instead once the methods above are removed.
1078     @VisibleForTesting
1079     void init(Looper looper, IPackageManager packageManager, PackageManager packageManagerClient,
1080             LightsManager lightsManager, NotificationListeners notificationListeners,
1081             ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
1082             NotificationUsageStats usageStats) {
1083         Resources resources = getContext().getResources();
1084         mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
1085                 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
1086                 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
1087
1088         mAm = ActivityManager.getService();
1089         mPackageManager = packageManager;
1090         mPackageManagerClient = packageManagerClient;
1091         mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
1092         mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
1093         mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
1094         mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
1095         mCompanionManager = companionManager;
1096
1097         mHandler = new WorkerHandler(looper);
1098         mRankingThread.start();
1099         String[] extractorNames;
1100         try {
1101             extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
1102         } catch (Resources.NotFoundException e) {
1103             extractorNames = new String[0];
1104         }
1105         mUsageStats = usageStats;
1106         mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
1107         mRankingHelper = new RankingHelper(getContext(),
1108                 getContext().getPackageManager(),
1109                 mRankingHandler,
1110                 mUsageStats,
1111                 extractorNames);
1112         mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles);
1113         mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
1114         mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
1115             @Override
1116             public void onConfigChanged() {
1117                 savePolicyFile();
1118             }
1119
1120             @Override
1121             void onZenModeChanged() {
1122                 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
1123                 getContext().sendBroadcastAsUser(
1124                         new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
1125                                 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
1126                         UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
1127                 synchronized (mNotificationLock) {
1128                     updateInterruptionFilterLocked();
1129                 }
1130             }
1131
1132             @Override
1133             void onPolicyChanged() {
1134                 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
1135             }
1136         });
1137         mSnoozeHelper = snoozeHelper;
1138         mGroupHelper = new GroupHelper(new GroupHelper.Callback() {
1139             @Override
1140             public void addAutoGroup(String key) {
1141                 synchronized (mNotificationLock) {
1142                     addAutogroupKeyLocked(key);
1143                 }
1144                 mRankingHandler.requestSort(false);
1145             }
1146
1147             @Override
1148             public void removeAutoGroup(String key) {
1149                 synchronized (mNotificationLock) {
1150                     removeAutogroupKeyLocked(key);
1151                 }
1152                 mRankingHandler.requestSort(false);
1153             }
1154
1155             @Override
1156             public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) {
1157                 createAutoGroupSummary(userId, pkg, triggeringKey);
1158             }
1159
1160             @Override
1161             public void removeAutoGroupSummary(int userId, String pkg) {
1162                 synchronized (mNotificationLock) {
1163                     clearAutogroupSummaryLocked(userId, pkg);
1164                 }
1165             }
1166         });
1167
1168         final File systemDir = new File(Environment.getDataDirectory(), "system");
1169         mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
1170
1171         loadPolicyFile();
1172
1173         // This is a ManagedServices object that keeps track of the listeners.
1174         mListeners = notificationListeners;
1175
1176         // This is a MangedServices object that keeps track of the assistant.
1177         mNotificationAssistants = new NotificationAssistants();
1178
1179         mStatusBar = getLocalService(StatusBarManagerInternal.class);
1180         if (mStatusBar != null) {
1181             mStatusBar.setNotificationDelegate(mNotificationDelegate);
1182         }
1183
1184         mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
1185         mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
1186
1187         mFallbackVibrationPattern = getLongArray(resources,
1188                 R.array.config_notificationFallbackVibePattern,
1189                 VIBRATE_PATTERN_MAXLEN,
1190                 DEFAULT_VIBRATE_PATTERN);
1191
1192         mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
1193
1194         // Don't start allowing notifications until the setup wizard has run once.
1195         // After that, including subsequent boots, init with notifications turned on.
1196         // This works on the first boot because the setup wizard will toggle this
1197         // flag at least once and we'll go back to 0 after that.
1198         if (0 == Settings.Global.getInt(getContext().getContentResolver(),
1199                     Settings.Global.DEVICE_PROVISIONED, 0)) {
1200             mDisableNotificationEffects = true;
1201         }
1202         mZenModeHelper.initZenMode();
1203         mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1204
1205         mUserProfiles.updateCache(getContext());
1206         listenForCallState();
1207
1208         // register for various Intents
1209         IntentFilter filter = new IntentFilter();
1210         filter.addAction(Intent.ACTION_SCREEN_ON);
1211         filter.addAction(Intent.ACTION_SCREEN_OFF);
1212         filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
1213         filter.addAction(Intent.ACTION_USER_PRESENT);
1214         filter.addAction(Intent.ACTION_USER_STOPPED);
1215         filter.addAction(Intent.ACTION_USER_SWITCHED);
1216         filter.addAction(Intent.ACTION_USER_ADDED);
1217         filter.addAction(Intent.ACTION_USER_REMOVED);
1218         filter.addAction(Intent.ACTION_USER_UNLOCKED);
1219         filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
1220         getContext().registerReceiver(mIntentReceiver, filter);
1221
1222         IntentFilter pkgFilter = new IntentFilter();
1223         pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
1224         pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1225         pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
1226         pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1227         pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1228         pkgFilter.addDataScheme("package");
1229         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1230                 null);
1231
1232         IntentFilter suspendedPkgFilter = new IntentFilter();
1233         suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
1234         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1235                 suspendedPkgFilter, null, null);
1236
1237         IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
1238         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1239                 null);
1240
1241         IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
1242         timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
1243         getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter);
1244
1245         mSettingsObserver = new SettingsObserver(mHandler);
1246
1247         mArchive = new Archive(resources.getInteger(
1248                 R.integer.config_notificationServiceArchiveSize));
1249
1250         mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
1251                 || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
1252     }
1253
1254     @Override
1255     public void onStart() {
1256         SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() {
1257             @Override
1258             public void repost(int userId, NotificationRecord r) {
1259                 try {
1260                     if (DBG) {
1261                         Slog.d(TAG, "Reposting " + r.getKey());
1262                     }
1263                     enqueueNotificationInternal(r.sbn.getPackageName(), r.sbn.getOpPkg(),
1264                             r.sbn.getUid(), r.sbn.getInitialPid(), r.sbn.getTag(), r.sbn.getId(),
1265                             r.sbn.getNotification(), userId);
1266                 } catch (Exception e) {
1267                     Slog.e(TAG, "Cannot un-snooze notification", e);
1268                 }
1269             }
1270         }, mUserProfiles);
1271
1272         init(Looper.myLooper(), AppGlobals.getPackageManager(), getContext().getPackageManager(),
1273                 getLocalService(LightsManager.class), new NotificationListeners(),
1274                 null, snoozeHelper, new NotificationUsageStats(getContext()));
1275         publishBinderService(Context.NOTIFICATION_SERVICE, mService);
1276         publishLocalService(NotificationManagerInternal.class, mInternalService);
1277     }
1278
1279     private void sendRegisteredOnlyBroadcast(String action) {
1280         getContext().sendBroadcastAsUser(new Intent(action)
1281                 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
1282     }
1283
1284     @Override
1285     public void onBootPhase(int phase) {
1286         if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1287             // no beeping until we're basically done booting
1288             mSystemReady = true;
1289
1290             // Grab our optional AudioService
1291             mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
1292             mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
1293             mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
1294             mZenModeHelper.onSystemReady();
1295         } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1296             // This observer will force an update when observe is called, causing us to
1297             // bind to listener services.
1298             mSettingsObserver.observe();
1299             mListeners.onBootPhaseAppsCanStart();
1300             mNotificationAssistants.onBootPhaseAppsCanStart();
1301             mConditionProviders.onBootPhaseAppsCanStart();
1302         }
1303     }
1304
1305     @GuardedBy("mNotificationLock")
1306     private void updateListenerHintsLocked() {
1307         final int hints = calculateHints();
1308         if (hints == mListenerHints) return;
1309         ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
1310         mListenerHints = hints;
1311         scheduleListenerHintsChanged(hints);
1312     }
1313
1314     @GuardedBy("mNotificationLock")
1315     private void updateEffectsSuppressorLocked() {
1316         final long updatedSuppressedEffects = calculateSuppressedEffects();
1317         if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1318         final List<ComponentName> suppressors = getSuppressors();
1319         ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1320         mEffectsSuppressors = suppressors;
1321         mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
1322         sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
1323     }
1324
1325     private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
1326             boolean fromListener) {
1327         if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
1328             // cancel
1329             cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
1330                     UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
1331                     null);
1332         }
1333         mRankingHelper.updateNotificationChannel(pkg, uid, channel);
1334
1335         final NotificationChannel modifiedChannel =
1336                 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
1337
1338         if (!fromListener) {
1339             mListeners.notifyNotificationChannelChanged(
1340                     pkg, UserHandle.getUserHandleForUid(uid),
1341                     modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
1342         }
1343
1344         synchronized (mNotificationLock) {
1345             final int N = mNotificationList.size();
1346             for (int i = N - 1; i >= 0; --i) {
1347                 NotificationRecord r = mNotificationList.get(i);
1348                 if (r.sbn.getPackageName().equals(pkg)
1349                         && r.sbn.getUid() == uid
1350                         && channel.getId() != null
1351                         && channel.getId().equals(r.getChannel().getId())) {
1352                     r.updateNotificationChannel(modifiedChannel);
1353                 }
1354             }
1355         }
1356         mRankingHandler.requestSort(true);
1357         savePolicyFile();
1358     }
1359
1360     private ArrayList<ComponentName> getSuppressors() {
1361         ArrayList<ComponentName> names = new ArrayList<ComponentName>();
1362         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1363             ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1364
1365             for (ManagedServiceInfo info : serviceInfoList) {
1366                 names.add(info.component);
1367             }
1368         }
1369
1370         return names;
1371     }
1372
1373     private boolean removeDisabledHints(ManagedServiceInfo info) {
1374         return removeDisabledHints(info, 0);
1375     }
1376
1377     private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
1378         boolean removed = false;
1379
1380         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1381             final int hint = mListenersDisablingEffects.keyAt(i);
1382             final ArraySet<ManagedServiceInfo> listeners =
1383                     mListenersDisablingEffects.valueAt(i);
1384
1385             if (hints == 0 || (hint & hints) == hint) {
1386                 removed = removed || listeners.remove(info);
1387             }
1388         }
1389
1390         return removed;
1391     }
1392
1393     private void addDisabledHints(ManagedServiceInfo info, int hints) {
1394         if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1395             addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
1396         }
1397
1398         if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1399             addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1400         }
1401
1402         if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1403             addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
1404         }
1405     }
1406
1407     private void addDisabledHint(ManagedServiceInfo info, int hint) {
1408         if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
1409             mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
1410         }
1411
1412         ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
1413         hintListeners.add(info);
1414     }
1415
1416     private int calculateHints() {
1417         int hints = 0;
1418         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1419             int hint = mListenersDisablingEffects.keyAt(i);
1420             ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1421
1422             if (!serviceInfoList.isEmpty()) {
1423                 hints |= hint;
1424             }
1425         }
1426
1427         return hints;
1428     }
1429
1430     private long calculateSuppressedEffects() {
1431         int hints = calculateHints();
1432         long suppressedEffects = 0;
1433
1434         if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1435             suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
1436         }
1437
1438         if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1439             suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
1440         }
1441
1442         if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1443             suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
1444         }
1445
1446         return suppressedEffects;
1447     }
1448
1449     @GuardedBy("mNotificationLock")
1450     private void updateInterruptionFilterLocked() {
1451         int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1452         if (interruptionFilter == mInterruptionFilter) return;
1453         mInterruptionFilter = interruptionFilter;
1454         scheduleInterruptionFilterChanged(interruptionFilter);
1455     }
1456
1457     @VisibleForTesting
1458     INotificationManager getBinderService() {
1459         return INotificationManager.Stub.asInterface(mService);
1460     }
1461
1462     @VisibleForTesting
1463     NotificationManagerInternal getInternalService() {
1464         return mInternalService;
1465     }
1466
1467     private final IBinder mService = new INotificationManager.Stub() {
1468         // Toasts
1469         // ============================================================================
1470
1471         @Override
1472         public void enqueueToast(String pkg, ITransientNotification callback, int duration)
1473         {
1474             if (DBG) {
1475                 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1476                         + " duration=" + duration);
1477             }
1478
1479             if (pkg == null || callback == null) {
1480                 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1481                 return ;
1482             }
1483
1484             final boolean isSystemToast = isCallerSystemOrPhone() || ("android".equals(pkg));
1485             final boolean isPackageSuspended =
1486                     isPackageSuspendedForUser(pkg, Binder.getCallingUid());
1487
1488             if (ENABLE_BLOCKED_TOASTS && !isSystemToast &&
1489                     (!areNotificationsEnabledForPackage(pkg, Binder.getCallingUid())
1490                             || isPackageSuspended)) {
1491                 Slog.e(TAG, "Suppressing toast from package " + pkg
1492                         + (isPackageSuspended
1493                                 ? " due to package suspended by administrator."
1494                                 : " by user request."));
1495                 return;
1496             }
1497
1498             synchronized (mToastQueue) {
1499                 int callingPid = Binder.getCallingPid();
1500                 long callingId = Binder.clearCallingIdentity();
1501                 try {
1502                     ToastRecord record;
1503                     int index = indexOfToastLocked(pkg, callback);
1504                     // If it's already in the queue, we update it in place, we don't
1505                     // move it to the end of the queue.
1506                     if (index >= 0) {
1507                         record = mToastQueue.get(index);
1508                         record.update(duration);
1509                     } else {
1510                         // Limit the number of toasts that any given package except the android
1511                         // package can enqueue.  Prevents DOS attacks and deals with leaks.
1512                         if (!isSystemToast) {
1513                             int count = 0;
1514                             final int N = mToastQueue.size();
1515                             for (int i=0; i<N; i++) {
1516                                  final ToastRecord r = mToastQueue.get(i);
1517                                  if (r.pkg.equals(pkg)) {
1518                                      count++;
1519                                      if (count >= MAX_PACKAGE_NOTIFICATIONS) {
1520                                          Slog.e(TAG, "Package has already posted " + count
1521                                                 + " toasts. Not showing more. Package=" + pkg);
1522                                          return;
1523                                      }
1524                                  }
1525                             }
1526                         }
1527
1528                         Binder token = new Binder();
1529                         mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, DEFAULT_DISPLAY);
1530                         record = new ToastRecord(callingPid, pkg, callback, duration, token);
1531                         mToastQueue.add(record);
1532                         index = mToastQueue.size() - 1;
1533                         keepProcessAliveIfNeededLocked(callingPid);
1534                     }
1535                     // If it's at index 0, it's the current toast.  It doesn't matter if it's
1536                     // new or just been updated.  Call back and tell it to show itself.
1537                     // If the callback fails, this will remove it from the list, so don't
1538                     // assume that it's valid after this.
1539                     if (index == 0) {
1540                         showNextToastLocked();
1541                     }
1542                 } finally {
1543                     Binder.restoreCallingIdentity(callingId);
1544                 }
1545             }
1546         }
1547
1548         @Override
1549         public void cancelToast(String pkg, ITransientNotification callback) {
1550             Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
1551
1552             if (pkg == null || callback == null) {
1553                 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
1554                 return ;
1555             }
1556
1557             synchronized (mToastQueue) {
1558                 long callingId = Binder.clearCallingIdentity();
1559                 try {
1560                     int index = indexOfToastLocked(pkg, callback);
1561                     if (index >= 0) {
1562                         cancelToastLocked(index);
1563                     } else {
1564                         Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
1565                                 + " callback=" + callback);
1566                     }
1567                 } finally {
1568                     Binder.restoreCallingIdentity(callingId);
1569                 }
1570             }
1571         }
1572
1573         @Override
1574         public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
1575                 Notification notification, int userId) throws RemoteException {
1576             enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
1577                     Binder.getCallingPid(), tag, id, notification, userId);
1578         }
1579
1580         @Override
1581         public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
1582             checkCallerIsSystemOrSameApp(pkg);
1583             userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1584                     Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
1585             // Don't allow client applications to cancel foreground service notis or autobundled
1586             // summaries.
1587             final int mustNotHaveFlags = isCallingUidSystem() ? 0 :
1588                     (Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTOGROUP_SUMMARY);
1589             cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
1590                     mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null);
1591         }
1592
1593         @Override
1594         public void cancelAllNotifications(String pkg, int userId) {
1595             checkCallerIsSystemOrSameApp(pkg);
1596
1597             userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1598                     Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
1599
1600             // Calling from user space, don't allow the canceling of actively
1601             // running foreground services.
1602             cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
1603                     pkg, null, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
1604                     REASON_APP_CANCEL_ALL, null);
1605         }
1606
1607         @Override
1608         public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
1609             checkCallerIsSystem();
1610
1611             mRankingHelper.setEnabled(pkg, uid, enabled);
1612             // Now, cancel any outstanding notifications that are part of a just-disabled app
1613             if (!enabled) {
1614                 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
1615                         UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
1616             }
1617             savePolicyFile();
1618         }
1619
1620         /**
1621          * Use this when you just want to know if notifications are OK for this package.
1622          */
1623         @Override
1624         public boolean areNotificationsEnabled(String pkg) {
1625             return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
1626         }
1627
1628         /**
1629          * Use this when you just want to know if notifications are OK for this package.
1630          */
1631         @Override
1632         public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
1633             checkCallerIsSystemOrSameApp(pkg);
1634             if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) {
1635                 getContext().enforceCallingPermission(
1636                         android.Manifest.permission.INTERACT_ACROSS_USERS,
1637                         "canNotifyAsPackage for uid " + uid);
1638             }
1639
1640             return mRankingHelper.getImportance(pkg, uid) != IMPORTANCE_NONE;
1641         }
1642
1643         @Override
1644         public int getPackageImportance(String pkg) {
1645             checkCallerIsSystemOrSameApp(pkg);
1646             return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
1647         }
1648
1649         @Override
1650         public boolean canShowBadge(String pkg, int uid) {
1651             checkCallerIsSystem();
1652             return mRankingHelper.canShowBadge(pkg, uid);
1653         }
1654
1655         @Override
1656         public void setShowBadge(String pkg, int uid, boolean showBadge) {
1657             checkCallerIsSystem();
1658             mRankingHelper.setShowBadge(pkg, uid, showBadge);
1659             savePolicyFile();
1660         }
1661
1662         @Override
1663         public void createNotificationChannelGroups(String pkg,
1664                 ParceledListSlice channelGroupList) throws RemoteException {
1665             checkCallerIsSystemOrSameApp(pkg);
1666             List<NotificationChannelGroup> groups = channelGroupList.getList();
1667             final int groupSize = groups.size();
1668             for (int i = 0; i < groupSize; i++) {
1669                 final NotificationChannelGroup group = groups.get(i);
1670                 Preconditions.checkNotNull(group, "group in list is null");
1671                 mRankingHelper.createNotificationChannelGroup(pkg, Binder.getCallingUid(), group,
1672                         true /* fromTargetApp */);
1673                 mListeners.notifyNotificationChannelGroupChanged(pkg,
1674                         UserHandle.of(UserHandle.getCallingUserId()), group,
1675                         NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1676             }
1677             savePolicyFile();
1678         }
1679
1680         private void createNotificationChannelsImpl(String pkg, int uid,
1681                 ParceledListSlice channelsList) {
1682             List<NotificationChannel> channels = channelsList.getList();
1683             final int channelsSize = channels.size();
1684             for (int i = 0; i < channelsSize; i++) {
1685                 final NotificationChannel channel = channels.get(i);
1686                 Preconditions.checkNotNull(channel, "channel in list is null");
1687                 mRankingHelper.createNotificationChannel(pkg, uid, channel,
1688                         true /* fromTargetApp */);
1689                 mListeners.notifyNotificationChannelChanged(pkg,
1690                         UserHandle.getUserHandleForUid(uid),
1691                         mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false),
1692                         NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1693             }
1694             savePolicyFile();
1695         }
1696
1697         @Override
1698         public void createNotificationChannels(String pkg,
1699                 ParceledListSlice channelsList) throws RemoteException {
1700             checkCallerIsSystemOrSameApp(pkg);
1701             createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList);
1702         }
1703
1704         @Override
1705         public void createNotificationChannelsForPackage(String pkg, int uid,
1706                 ParceledListSlice channelsList) throws RemoteException {
1707             checkCallerIsSystem();
1708             createNotificationChannelsImpl(pkg, uid, channelsList);
1709         }
1710
1711         @Override
1712         public NotificationChannel getNotificationChannel(String pkg, String channelId) {
1713             checkCallerIsSystemOrSameApp(pkg);
1714             return mRankingHelper.getNotificationChannel(
1715                     pkg, Binder.getCallingUid(), channelId, false /* includeDeleted */);
1716         }
1717
1718         @Override
1719         public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
1720                 String channelId, boolean includeDeleted) {
1721             checkCallerIsSystem();
1722             return mRankingHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted);
1723         }
1724
1725         @Override
1726         public void deleteNotificationChannel(String pkg, String channelId) {
1727             checkCallerIsSystemOrSameApp(pkg);
1728             final int callingUid = Binder.getCallingUid();
1729             if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
1730                 throw new IllegalArgumentException("Cannot delete default channel");
1731             }
1732             cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
1733                     UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
1734             mRankingHelper.deleteNotificationChannel(pkg, callingUid, channelId);
1735             mListeners.notifyNotificationChannelChanged(pkg,
1736                     UserHandle.getUserHandleForUid(callingUid),
1737                     mRankingHelper.getNotificationChannel(pkg, callingUid, channelId, true),
1738                     NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1739             savePolicyFile();
1740         }
1741
1742         @Override
1743         public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
1744                 String pkg) {
1745             checkCallerIsSystemOrSameApp(pkg);
1746             return new ParceledListSlice<>(new ArrayList(
1747                     mRankingHelper.getNotificationChannelGroups(pkg, Binder.getCallingUid())));
1748         }
1749
1750         @Override
1751         public void deleteNotificationChannelGroup(String pkg, String groupId) {
1752             checkCallerIsSystemOrSameApp(pkg);
1753
1754             final int callingUid = Binder.getCallingUid();
1755             NotificationChannelGroup groupToDelete =
1756                     mRankingHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
1757             if (groupToDelete != null) {
1758                 List<NotificationChannel> deletedChannels =
1759                         mRankingHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
1760                 for (int i = 0; i < deletedChannels.size(); i++) {
1761                     final NotificationChannel deletedChannel = deletedChannels.get(i);
1762                     cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
1763                             true,
1764                             UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
1765                             null);
1766                     mListeners.notifyNotificationChannelChanged(pkg,
1767                             UserHandle.getUserHandleForUid(callingUid),
1768                             deletedChannel,
1769                             NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1770                 }
1771                 mListeners.notifyNotificationChannelGroupChanged(
1772                         pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete,
1773                         NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1774                 savePolicyFile();
1775             }
1776         }
1777
1778         @Override
1779         public void updateNotificationChannelForPackage(String pkg, int uid,
1780                 NotificationChannel channel) {
1781             enforceSystemOrSystemUI("Caller not system or systemui");
1782             Preconditions.checkNotNull(channel);
1783             updateNotificationChannelInt(pkg, uid, channel, false);
1784         }
1785
1786         @Override
1787         public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
1788                 int uid, boolean includeDeleted) {
1789             enforceSystemOrSystemUI("getNotificationChannelsForPackage");
1790             return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted);
1791         }
1792
1793         @Override
1794         public int getNumNotificationChannelsForPackage(String pkg, int uid,
1795                 boolean includeDeleted) {
1796             enforceSystemOrSystemUI("getNumNotificationChannelsForPackage");
1797             return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted)
1798                     .getList().size();
1799         }
1800
1801         @Override
1802         public boolean onlyHasDefaultChannel(String pkg, int uid) {
1803             enforceSystemOrSystemUI("onlyHasDefaultChannel");
1804             return mRankingHelper.onlyHasDefaultChannel(pkg, uid);
1805         }
1806
1807         @Override
1808         public int getDeletedChannelCount(String pkg, int uid) {
1809             enforceSystemOrSystemUI("getDeletedChannelCount");
1810             return mRankingHelper.getDeletedChannelCount(pkg, uid);
1811         }
1812
1813         @Override
1814         public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
1815                 String pkg, int uid, boolean includeDeleted) {
1816             checkCallerIsSystem();
1817             return mRankingHelper.getNotificationChannelGroups(pkg, uid, includeDeleted);
1818         }
1819
1820         @Override
1821         public NotificationChannelGroup getNotificationChannelGroupForPackage(
1822                 String groupId, String pkg, int uid) {
1823             enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
1824             return mRankingHelper.getNotificationChannelGroup(groupId, pkg, uid);
1825         }
1826
1827         @Override
1828         public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
1829             checkCallerIsSystemOrSameApp(pkg);
1830             return mRankingHelper.getNotificationChannels(
1831                     pkg, Binder.getCallingUid(), false /* includeDeleted */);
1832         }
1833
1834         @Override
1835         public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
1836             checkCallerIsSystem();
1837
1838             // Cancel posted notifications
1839             cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true,
1840                     UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
1841
1842             // Listener & assistant
1843             mListeners.onPackagesChanged(true, new String[] {packageName});
1844             mNotificationAssistants.onPackagesChanged(true, new String[] {packageName});
1845
1846             // Zen
1847             mConditionProviders.onPackagesChanged(true, new String[] {packageName});
1848
1849             // Reset notification preferences
1850             if (!fromApp) {
1851                 mRankingHelper.onPackagesChanged(true, UserHandle.getCallingUserId(),
1852                         new String[]{packageName}, new int[]{uid});
1853             }
1854
1855             savePolicyFile();
1856         }
1857
1858
1859         /**
1860          * System-only API for getting a list of current (i.e. not cleared) notifications.
1861          *
1862          * Requires ACCESS_NOTIFICATIONS which is signature|system.
1863          * @returns A list of all the notifications, in natural order.
1864          */
1865         @Override
1866         public StatusBarNotification[] getActiveNotifications(String callingPkg) {
1867             // enforce() will ensure the calling uid has the correct permission
1868             getContext().enforceCallingOrSelfPermission(
1869                     android.Manifest.permission.ACCESS_NOTIFICATIONS,
1870                     "NotificationManagerService.getActiveNotifications");
1871
1872             StatusBarNotification[] tmp = null;
1873             int uid = Binder.getCallingUid();
1874
1875             // noteOp will check to make sure the callingPkg matches the uid
1876             if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1877                     == AppOpsManager.MODE_ALLOWED) {
1878                 synchronized (mNotificationLock) {
1879                     tmp = new StatusBarNotification[mNotificationList.size()];
1880                     final int N = mNotificationList.size();
1881                     for (int i=0; i<N; i++) {
1882                         tmp[i] = mNotificationList.get(i).sbn;
1883                     }
1884                 }
1885             }
1886             return tmp;
1887         }
1888
1889         /**
1890          * Public API for getting a list of current notifications for the calling package/uid.
1891          *
1892          * Note that since notification posting is done asynchronously, this will not return
1893          * notifications that are in the process of being posted.
1894          *
1895          * @returns A list of all the package's notifications, in natural order.
1896          */
1897         @Override
1898         public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
1899                 int incomingUserId) {
1900             checkCallerIsSystemOrSameApp(pkg);
1901             int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1902                     Binder.getCallingUid(), incomingUserId, true, false,
1903                     "getAppActiveNotifications", pkg);
1904             synchronized (mNotificationLock) {
1905                 final ArrayMap<String, StatusBarNotification> map
1906                         = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
1907                 final int N = mNotificationList.size();
1908                 for (int i = 0; i < N; i++) {
1909                     StatusBarNotification sbn = sanitizeSbn(pkg, userId,
1910                             mNotificationList.get(i).sbn);
1911                     if (sbn != null) {
1912                         map.put(sbn.getKey(), sbn);
1913                     }
1914                 }
1915                 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
1916                     StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn);
1917                     if (sbn != null) {
1918                         map.put(sbn.getKey(), sbn);
1919                     }
1920                 }
1921                 final int M = mEnqueuedNotifications.size();
1922                 for (int i = 0; i < M; i++) {
1923                     StatusBarNotification sbn = sanitizeSbn(pkg, userId,
1924                             mEnqueuedNotifications.get(i).sbn);
1925                     if (sbn != null) {
1926                         map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
1927                     }
1928                 }
1929                 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
1930                 list.addAll(map.values());
1931                 return new ParceledListSlice<StatusBarNotification>(list);
1932             }
1933         }
1934
1935         private StatusBarNotification sanitizeSbn(String pkg, int userId,
1936                 StatusBarNotification sbn) {
1937             if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId
1938                     && (sbn.getNotification().flags
1939                     & Notification.FLAG_AUTOGROUP_SUMMARY) == 0) {
1940                 // We could pass back a cloneLight() but clients might get confused and
1941                 // try to send this thing back to notify() again, which would not work
1942                 // very well.
1943                 return new StatusBarNotification(
1944                         sbn.getPackageName(),
1945                         sbn.getOpPkg(),
1946                         sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
1947                         sbn.getNotification().clone(),
1948                         sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
1949             }
1950             return null;
1951         }
1952
1953         /**
1954          * System-only API for getting a list of recent (cleared, no longer shown) notifications.
1955          *
1956          * Requires ACCESS_NOTIFICATIONS which is signature|system.
1957          */
1958         @Override
1959         public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
1960             // enforce() will ensure the calling uid has the correct permission
1961             getContext().enforceCallingOrSelfPermission(
1962                     android.Manifest.permission.ACCESS_NOTIFICATIONS,
1963                     "NotificationManagerService.getHistoricalNotifications");
1964
1965             StatusBarNotification[] tmp = null;
1966             int uid = Binder.getCallingUid();
1967
1968             // noteOp will check to make sure the callingPkg matches the uid
1969             if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1970                     == AppOpsManager.MODE_ALLOWED) {
1971                 synchronized (mArchive) {
1972                     tmp = mArchive.getArray(count);
1973                 }
1974             }
1975             return tmp;
1976         }
1977
1978         /**
1979          * Register a listener binder directly with the notification manager.
1980          *
1981          * Only works with system callers. Apps should extend
1982          * {@link android.service.notification.NotificationListenerService}.
1983          */
1984         @Override
1985         public void registerListener(final INotificationListener listener,
1986                 final ComponentName component, final int userid) {
1987             enforceSystemOrSystemUI("INotificationManager.registerListener");
1988             mListeners.registerService(listener, component, userid);
1989         }
1990
1991         /**
1992          * Remove a listener binder directly
1993          */
1994         @Override
1995         public void unregisterListener(INotificationListener token, int userid) {
1996             mListeners.unregisterService(token, userid);
1997         }
1998
1999         /**
2000          * Allow an INotificationListener to simulate a "clear all" operation.
2001          *
2002          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
2003          *
2004          * @param token The binder for the listener, to check that the caller is allowed
2005          */
2006         @Override
2007         public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
2008             final int callingUid = Binder.getCallingUid();
2009             final int callingPid = Binder.getCallingPid();
2010             long identity = Binder.clearCallingIdentity();
2011             try {
2012                 synchronized (mNotificationLock) {
2013                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2014                     if (keys != null) {
2015                         final int N = keys.length;
2016                         for (int i = 0; i < N; i++) {
2017                             NotificationRecord r = mNotificationsByKey.get(keys[i]);
2018                             if (r == null) continue;
2019                             final int userId = r.sbn.getUserId();
2020                             if (userId != info.userid && userId != UserHandle.USER_ALL &&
2021                                     !mUserProfiles.isCurrentProfile(userId)) {
2022                                 throw new SecurityException("Disallowed call from listener: "
2023                                         + info.service);
2024                             }
2025                             cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2026                                     r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
2027                                     userId);
2028                         }
2029                     } else {
2030                         cancelAllLocked(callingUid, callingPid, info.userid,
2031                                 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
2032                     }
2033                 }
2034             } finally {
2035                 Binder.restoreCallingIdentity(identity);
2036             }
2037         }
2038
2039         /**
2040          * Handle request from an approved listener to re-enable itself.
2041          *
2042          * @param component The componenet to be re-enabled, caller must match package.
2043          */
2044         @Override
2045         public void requestBindListener(ComponentName component) {
2046             checkCallerIsSystemOrSameApp(component.getPackageName());
2047             long identity = Binder.clearCallingIdentity();
2048             try {
2049                 ManagedServices manager =
2050                         mNotificationAssistants.isComponentEnabledForCurrentProfiles(component)
2051                         ? mNotificationAssistants
2052                         : mListeners;
2053                 manager.setComponentState(component, true);
2054             } finally {
2055                 Binder.restoreCallingIdentity(identity);
2056             }
2057         }
2058
2059         @Override
2060         public void requestUnbindListener(INotificationListener token) {
2061             long identity = Binder.clearCallingIdentity();
2062             try {
2063                 // allow bound services to disable themselves
2064                 synchronized (mNotificationLock) {
2065                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2066                     info.getOwner().setComponentState(info.component, false);
2067                 }
2068             } finally {
2069                 Binder.restoreCallingIdentity(identity);
2070             }
2071         }
2072
2073         @Override
2074         public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
2075             long identity = Binder.clearCallingIdentity();
2076             try {
2077                 synchronized (mNotificationLock) {
2078                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2079                     if (keys != null) {
2080                         final int N = keys.length;
2081                         for (int i = 0; i < N; i++) {
2082                             NotificationRecord r = mNotificationsByKey.get(keys[i]);
2083                             if (r == null) continue;
2084                             final int userId = r.sbn.getUserId();
2085                             if (userId != info.userid && userId != UserHandle.USER_ALL &&
2086                                     !mUserProfiles.isCurrentProfile(userId)) {
2087                                 throw new SecurityException("Disallowed call from listener: "
2088                                         + info.service);
2089                             }
2090                             if (!r.isSeen()) {
2091                                 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
2092                                 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
2093                                         userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM
2094                                                 : userId,
2095                                         UsageEvents.Event.USER_INTERACTION);
2096                                 r.setSeen();
2097                             }
2098                         }
2099                     }
2100                 }
2101             } finally {
2102                 Binder.restoreCallingIdentity(identity);
2103             }
2104         }
2105
2106         /**
2107          * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2108          *
2109          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2110          *
2111          * @param info The binder for the listener, to check that the caller is allowed
2112          */
2113         @GuardedBy("mNotificationLock")
2114         private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
2115                 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
2116             cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
2117                     Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
2118                     true,
2119                     userId, REASON_LISTENER_CANCEL, info);
2120         }
2121
2122         /**
2123          * Allow an INotificationListener to snooze a single notification until a context.
2124          *
2125          * @param token The binder for the listener, to check that the caller is allowed
2126          */
2127         @Override
2128         public void snoozeNotificationUntilContextFromListener(INotificationListener token,
2129                 String key, String snoozeCriterionId) {
2130             long identity = Binder.clearCallingIdentity();
2131             try {
2132                 synchronized (mNotificationLock) {
2133                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2134                     snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info);
2135                 }
2136             } finally {
2137                 Binder.restoreCallingIdentity(identity);
2138             }
2139         }
2140
2141         /**
2142          * Allow an INotificationListener to snooze a single notification until a time.
2143          *
2144          * @param token The binder for the listener, to check that the caller is allowed
2145          */
2146         @Override
2147         public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
2148                 long duration) {
2149             long identity = Binder.clearCallingIdentity();
2150             try {
2151                 synchronized (mNotificationLock) {
2152                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2153                     snoozeNotificationInt(key, duration, null, info);
2154                 }
2155             } finally {
2156                 Binder.restoreCallingIdentity(identity);
2157             }
2158         }
2159
2160         /**
2161          * Allows the notification assistant to un-snooze a single notification.
2162          *
2163          * @param token The binder for the assistant, to check that the caller is allowed
2164          */
2165         @Override
2166         public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
2167             long identity = Binder.clearCallingIdentity();
2168             try {
2169                 synchronized (mNotificationLock) {
2170                     final ManagedServiceInfo info =
2171                             mNotificationAssistants.checkServiceTokenLocked(token);
2172                     unsnoozeNotificationInt(key, info);
2173                 }
2174             } finally {
2175                 Binder.restoreCallingIdentity(identity);
2176             }
2177         }
2178
2179         /**
2180          * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2181          *
2182          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2183          *
2184          * @param token The binder for the listener, to check that the caller is allowed
2185          */
2186         @Override
2187         public void cancelNotificationFromListener(INotificationListener token, String pkg,
2188                 String tag, int id) {
2189             final int callingUid = Binder.getCallingUid();
2190             final int callingPid = Binder.getCallingPid();
2191             long identity = Binder.clearCallingIdentity();
2192             try {
2193                 synchronized (mNotificationLock) {
2194                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2195                     if (info.supportsProfiles()) {
2196                         Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
2197                                 + "from " + info.component
2198                                 + " use cancelNotification(key) instead.");
2199                     } else {
2200                         cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2201                                 pkg, tag, id, info.userid);
2202                     }
2203                 }
2204             } finally {
2205                 Binder.restoreCallingIdentity(identity);
2206             }
2207         }
2208
2209         /**
2210          * Allow an INotificationListener to request the list of outstanding notifications seen by
2211          * the current user. Useful when starting up, after which point the listener callbacks
2212          * should be used.
2213          *
2214          * @param token The binder for the listener, to check that the caller is allowed
2215          * @param keys An array of notification keys to fetch, or null to fetch everything
2216          * @returns The return value will contain the notifications specified in keys, in that
2217          *      order, or if keys is null, all the notifications, in natural order.
2218          */
2219         @Override
2220         public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
2221                 INotificationListener token, String[] keys, int trim) {
2222             synchronized (mNotificationLock) {
2223                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2224                 final boolean getKeys = keys != null;
2225                 final int N = getKeys ? keys.length : mNotificationList.size();
2226                 final ArrayList<StatusBarNotification> list
2227                         = new ArrayList<StatusBarNotification>(N);
2228                 for (int i=0; i<N; i++) {
2229                     final NotificationRecord r = getKeys
2230                             ? mNotificationsByKey.get(keys[i])
2231                             : mNotificationList.get(i);
2232                     if (r == null) continue;
2233                     StatusBarNotification sbn = r.sbn;
2234                     if (!isVisibleToListener(sbn, info)) continue;
2235                     StatusBarNotification sbnToSend =
2236                             (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2237                     list.add(sbnToSend);
2238                 }
2239                 return new ParceledListSlice<StatusBarNotification>(list);
2240             }
2241         }
2242
2243         /**
2244          * Allow an INotificationListener to request the list of outstanding snoozed notifications
2245          * seen by the current user. Useful when starting up, after which point the listener
2246          * callbacks should be used.
2247          *
2248          * @param token The binder for the listener, to check that the caller is allowed
2249          * @returns The return value will contain the notifications specified in keys, in that
2250          *      order, or if keys is null, all the notifications, in natural order.
2251          */
2252         @Override
2253         public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
2254                 INotificationListener token, int trim) {
2255             synchronized (mNotificationLock) {
2256                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2257                 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
2258                 final int N = snoozedRecords.size();
2259                 final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
2260                 for (int i=0; i < N; i++) {
2261                     final NotificationRecord r = snoozedRecords.get(i);
2262                     if (r == null) continue;
2263                     StatusBarNotification sbn = r.sbn;
2264                     if (!isVisibleToListener(sbn, info)) continue;
2265                     StatusBarNotification sbnToSend =
2266                             (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2267                     list.add(sbnToSend);
2268                 }
2269                 return new ParceledListSlice<>(list);
2270             }
2271         }
2272
2273         @Override
2274         public void requestHintsFromListener(INotificationListener token, int hints) {
2275             final long identity = Binder.clearCallingIdentity();
2276             try {
2277                 synchronized (mNotificationLock) {
2278                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2279                     final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
2280                             | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
2281                             | HINT_HOST_DISABLE_CALL_EFFECTS;
2282                     final boolean disableEffects = (hints & disableEffectsMask) != 0;
2283                     if (disableEffects) {
2284                         addDisabledHints(info, hints);
2285                     } else {
2286                         removeDisabledHints(info, hints);
2287                     }
2288                     updateListenerHintsLocked();
2289                     updateEffectsSuppressorLocked();
2290                 }
2291             } finally {
2292                 Binder.restoreCallingIdentity(identity);
2293             }
2294         }
2295
2296         @Override
2297         public int getHintsFromListener(INotificationListener token) {
2298             synchronized (mNotificationLock) {
2299                 return mListenerHints;
2300             }
2301         }
2302
2303         @Override
2304         public void requestInterruptionFilterFromListener(INotificationListener token,
2305                 int interruptionFilter) throws RemoteException {
2306             final long identity = Binder.clearCallingIdentity();
2307             try {
2308                 synchronized (mNotificationLock) {
2309                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2310                     mZenModeHelper.requestFromListener(info.component, interruptionFilter);
2311                     updateInterruptionFilterLocked();
2312                 }
2313             } finally {
2314                 Binder.restoreCallingIdentity(identity);
2315             }
2316         }
2317
2318         @Override
2319         public int getInterruptionFilterFromListener(INotificationListener token)
2320                 throws RemoteException {
2321             synchronized (mNotificationLight) {
2322                 return mInterruptionFilter;
2323             }
2324         }
2325
2326         @Override
2327         public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
2328                 throws RemoteException {
2329             synchronized (mNotificationLock) {
2330                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2331                 if (info == null) return;
2332                 mListeners.setOnNotificationPostedTrimLocked(info, trim);
2333             }
2334         }
2335
2336         @Override
2337         public int getZenMode() {
2338             return mZenModeHelper.getZenMode();
2339         }
2340
2341         @Override
2342         public ZenModeConfig getZenModeConfig() {
2343             enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
2344             return mZenModeHelper.getConfig();
2345         }
2346
2347         @Override
2348         public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
2349             enforceSystemOrSystemUI("INotificationManager.setZenMode");
2350             final long identity = Binder.clearCallingIdentity();
2351             try {
2352                 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
2353             } finally {
2354                 Binder.restoreCallingIdentity(identity);
2355             }
2356         }
2357
2358         @Override
2359         public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
2360             enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
2361             return mZenModeHelper.getZenRules();
2362         }
2363
2364         @Override
2365         public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
2366             Preconditions.checkNotNull(id, "Id is null");
2367             enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
2368             return mZenModeHelper.getAutomaticZenRule(id);
2369         }
2370
2371         @Override
2372         public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
2373                 throws RemoteException {
2374             Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2375             Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2376             Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2377             Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2378             enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
2379
2380             return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
2381                     "addAutomaticZenRule");
2382         }
2383
2384         @Override
2385         public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
2386                 throws RemoteException {
2387             Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2388             Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2389             Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2390             Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2391             enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
2392
2393             return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
2394                     "updateAutomaticZenRule");
2395         }
2396
2397         @Override
2398         public boolean removeAutomaticZenRule(String id) throws RemoteException {
2399             Preconditions.checkNotNull(id, "Id is null");
2400             // Verify that they can modify zen rules.
2401             enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
2402
2403             return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
2404         }
2405
2406         @Override
2407         public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
2408             Preconditions.checkNotNull(packageName, "Package name is null");
2409             enforceSystemOrSystemUI("removeAutomaticZenRules");
2410
2411             return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
2412         }
2413
2414         @Override
2415         public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
2416             Preconditions.checkNotNull(owner, "Owner is null");
2417             enforceSystemOrSystemUI("getRuleInstanceCount");
2418
2419             return mZenModeHelper.getCurrentInstanceCount(owner);
2420         }
2421
2422         @Override
2423         public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
2424             enforcePolicyAccess(pkg, "setInterruptionFilter");
2425             final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
2426             if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
2427             final long identity = Binder.clearCallingIdentity();
2428             try {
2429                 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
2430             } finally {
2431                 Binder.restoreCallingIdentity(identity);
2432             }
2433         }
2434
2435         @Override
2436         public void notifyConditions(final String pkg, IConditionProvider provider,
2437                 final Condition[] conditions) {
2438             final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2439             checkCallerIsSystemOrSameApp(pkg);
2440             mHandler.post(new Runnable() {
2441                 @Override
2442                 public void run() {
2443                     mConditionProviders.notifyConditions(pkg, info, conditions);
2444                 }
2445             });
2446         }
2447
2448         @Override
2449         public void requestUnbindProvider(IConditionProvider provider) {
2450             long identity = Binder.clearCallingIdentity();
2451             try {
2452                 // allow bound services to disable themselves
2453                 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2454                 info.getOwner().setComponentState(info.component, false);
2455             } finally {
2456                 Binder.restoreCallingIdentity(identity);
2457             }
2458         }
2459
2460         @Override
2461         public void requestBindProvider(ComponentName component) {
2462             checkCallerIsSystemOrSameApp(component.getPackageName());
2463             long identity = Binder.clearCallingIdentity();
2464             try {
2465                 mConditionProviders.setComponentState(component, true);
2466             } finally {
2467                 Binder.restoreCallingIdentity(identity);
2468             }
2469         }
2470
2471         private void enforceSystemOrSystemUI(String message) {
2472             if (isCallerSystemOrPhone()) return;
2473             getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
2474                     message);
2475         }
2476
2477         private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
2478             try {
2479                 checkCallerIsSystemOrSameApp(pkg);
2480             } catch (SecurityException e) {
2481                 getContext().enforceCallingPermission(
2482                         android.Manifest.permission.STATUS_BAR_SERVICE,
2483                         message);
2484             }
2485         }
2486
2487         private void enforcePolicyAccess(int uid, String method) {
2488             if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2489                     android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2490                 return;
2491             }
2492             boolean accessAllowed = false;
2493             String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
2494             final int packageCount = packages.length;
2495             for (int i = 0; i < packageCount; i++) {
2496                 if (checkPolicyAccess(packages[i])) {
2497                     accessAllowed = true;
2498                 }
2499             }
2500             if (!accessAllowed) {
2501                 Slog.w(TAG, "Notification policy access denied calling " + method);
2502                 throw new SecurityException("Notification policy access denied");
2503             }
2504         }
2505
2506         private void enforcePolicyAccess(String pkg, String method) {
2507             if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2508                     android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2509                 return;
2510             }
2511             checkCallerIsSameApp(pkg);
2512             if (!checkPolicyAccess(pkg)) {
2513                 Slog.w(TAG, "Notification policy access denied calling " + method);
2514                 throw new SecurityException("Notification policy access denied");
2515             }
2516         }
2517
2518         private boolean checkPackagePolicyAccess(String pkg) {
2519             return mPolicyAccess.isPackageGranted(pkg);
2520         }
2521
2522         private boolean checkPolicyAccess(String pkg) {
2523             try {
2524                 int uid = getContext().getPackageManager().getPackageUidAsUser(
2525                         pkg, UserHandle.getCallingUserId());
2526                 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
2527                         android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
2528                         -1, true)) {
2529                     return true;
2530                 }
2531             } catch (NameNotFoundException e) {
2532                 return false;
2533             }
2534             return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
2535         }
2536
2537         @Override
2538         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2539             if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
2540             final DumpFilter filter = DumpFilter.parseFromArguments(args);
2541             if (filter != null && filter.stats) {
2542                 dumpJson(pw, filter);
2543             } else if (filter != null && filter.proto) {
2544                 dumpProto(fd, filter);
2545             } else {
2546                 dumpImpl(pw, filter);
2547             }
2548         }
2549
2550         @Override
2551         public ComponentName getEffectsSuppressor() {
2552             return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
2553         }
2554
2555         @Override
2556         public boolean matchesCallFilter(Bundle extras) {
2557             enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
2558             return mZenModeHelper.matchesCallFilter(
2559                     Binder.getCallingUserHandle(),
2560                     extras,
2561                     mRankingHelper.findExtractor(ValidateNotificationPeople.class),
2562                     MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
2563                     MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
2564         }
2565
2566         @Override
2567         public boolean isSystemConditionProviderEnabled(String path) {
2568             enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
2569             return mConditionProviders.isSystemProviderEnabled(path);
2570         }
2571
2572         // Backup/restore interface
2573         @Override
2574         public byte[] getBackupPayload(int user) {
2575             if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
2576             //TODO: http://b/22388012
2577             if (user != UserHandle.USER_SYSTEM) {
2578                 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
2579                 return null;
2580             }
2581             synchronized(mPolicyFile) {
2582                 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
2583                 try {
2584                     writePolicyXml(baos, true /*forBackup*/);
2585                     return baos.toByteArray();
2586                 } catch (IOException e) {
2587                     Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
2588                 }
2589             }
2590             return null;
2591         }
2592
2593         @Override
2594         public void applyRestore(byte[] payload, int user) {
2595             if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
2596                     + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
2597             if (payload == null) {
2598                 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
2599                 return;
2600             }
2601             //TODO: http://b/22388012
2602             if (user != UserHandle.USER_SYSTEM) {
2603                 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
2604                 return;
2605             }
2606             synchronized(mPolicyFile) {
2607                 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
2608                 try {
2609                     readPolicyXml(bais, true /*forRestore*/);
2610                     savePolicyFile();
2611                 } catch (NumberFormatException | XmlPullParserException | IOException e) {
2612                     Slog.w(TAG, "applyRestore: error reading payload", e);
2613                 }
2614             }
2615         }
2616
2617         @Override
2618         public boolean isNotificationPolicyAccessGranted(String pkg) {
2619             return checkPolicyAccess(pkg);
2620         }
2621
2622         @Override
2623         public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
2624             enforceSystemOrSystemUIOrSamePackage(pkg,
2625                     "request policy access status for another package");
2626             return checkPolicyAccess(pkg);
2627         }
2628
2629         @Override
2630         public String[] getPackagesRequestingNotificationPolicyAccess()
2631                 throws RemoteException {
2632             enforceSystemOrSystemUI("request policy access packages");
2633             final long identity = Binder.clearCallingIdentity();
2634             try {
2635                 return mPolicyAccess.getRequestingPackages();
2636             } finally {
2637                 Binder.restoreCallingIdentity(identity);
2638             }
2639         }
2640
2641         @Override
2642         public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
2643                 throws RemoteException {
2644             enforceSystemOrSystemUI("grant notification policy access");
2645             final long identity = Binder.clearCallingIdentity();
2646             try {
2647                 synchronized (mNotificationLock) {
2648                     mPolicyAccess.put(pkg, granted);
2649                 }
2650             } finally {
2651                 Binder.restoreCallingIdentity(identity);
2652             }
2653         }
2654
2655         @Override
2656         public Policy getNotificationPolicy(String pkg) {
2657             enforcePolicyAccess(pkg, "getNotificationPolicy");
2658             final long identity = Binder.clearCallingIdentity();
2659             try {
2660                 return mZenModeHelper.getNotificationPolicy();
2661             } finally {
2662                 Binder.restoreCallingIdentity(identity);
2663             }
2664         }
2665
2666         @Override
2667         public void setNotificationPolicy(String pkg, Policy policy) {
2668             enforcePolicyAccess(pkg, "setNotificationPolicy");
2669             final long identity = Binder.clearCallingIdentity();
2670             try {
2671                 mZenModeHelper.setNotificationPolicy(policy);
2672             } finally {
2673                 Binder.restoreCallingIdentity(identity);
2674             }
2675         }
2676
2677         @Override
2678         public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
2679                 Adjustment adjustment) throws RemoteException {
2680             final long identity = Binder.clearCallingIdentity();
2681             try {
2682                 synchronized (mNotificationLock) {
2683                     mNotificationAssistants.checkServiceTokenLocked(token);
2684                     int N = mEnqueuedNotifications.size();
2685                     for (int i = 0; i < N; i++) {
2686                         final NotificationRecord n = mEnqueuedNotifications.get(i);
2687                         if (Objects.equals(adjustment.getKey(), n.getKey())
2688                                 && Objects.equals(adjustment.getUser(), n.getUserId())) {
2689                             applyAdjustment(n, adjustment);
2690                             break;
2691                         }
2692                     }
2693                 }
2694             } finally {
2695                 Binder.restoreCallingIdentity(identity);
2696             }
2697         }
2698
2699         @Override
2700         public void applyAdjustmentFromAssistant(INotificationListener token,
2701                 Adjustment adjustment) throws RemoteException {
2702             final long identity = Binder.clearCallingIdentity();
2703             try {
2704                 synchronized (mNotificationLock) {
2705                     mNotificationAssistants.checkServiceTokenLocked(token);
2706                     NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2707                     applyAdjustment(n, adjustment);
2708                 }
2709                 mRankingHandler.requestSort(true);
2710             } finally {
2711                 Binder.restoreCallingIdentity(identity);
2712             }
2713         }
2714
2715         @Override
2716         public void applyAdjustmentsFromAssistant(INotificationListener token,
2717                 List<Adjustment> adjustments) throws RemoteException {
2718
2719             final long identity = Binder.clearCallingIdentity();
2720             try {
2721                 synchronized (mNotificationLock) {
2722                     mNotificationAssistants.checkServiceTokenLocked(token);
2723                     for (Adjustment adjustment : adjustments) {
2724                         NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2725                         applyAdjustment(n, adjustment);
2726                     }
2727                 }
2728                 mRankingHandler.requestSort(true);
2729             } finally {
2730                 Binder.restoreCallingIdentity(identity);
2731             }
2732         }
2733
2734         @Override
2735         public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
2736                 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
2737             Preconditions.checkNotNull(channel);
2738             Preconditions.checkNotNull(pkg);
2739             Preconditions.checkNotNull(user);
2740
2741             verifyPrivilegedListener(token, user);
2742             updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
2743         }
2744
2745         @Override
2746         public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
2747                 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
2748             Preconditions.checkNotNull(pkg);
2749             Preconditions.checkNotNull(user);
2750             verifyPrivilegedListener(token, user);
2751
2752             return mRankingHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user),
2753                     false /* includeDeleted */);
2754         }
2755
2756         @Override
2757         public ParceledListSlice<NotificationChannelGroup>
2758                 getNotificationChannelGroupsFromPrivilegedListener(
2759                 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
2760             Preconditions.checkNotNull(pkg);
2761             Preconditions.checkNotNull(user);
2762             verifyPrivilegedListener(token, user);
2763
2764             List<NotificationChannelGroup> groups = new ArrayList<>();
2765             groups.addAll(mRankingHelper.getNotificationChannelGroups(
2766                     pkg, getUidForPackageAndUser(pkg, user)));
2767             return new ParceledListSlice<>(groups);
2768         }
2769
2770         private void verifyPrivilegedListener(INotificationListener token, UserHandle user) {
2771             ManagedServiceInfo info;
2772             synchronized (mNotificationLock) {
2773                 info = mListeners.checkServiceTokenLocked(token);
2774             }
2775             if (!hasCompanionDevice(info)) {
2776                 throw new SecurityException(info + " does not have access");
2777             }
2778             if (!info.enabledAndUserMatches(user.getIdentifier())) {
2779                 throw new SecurityException(info + " does not have access");
2780             }
2781         }
2782
2783         private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
2784             int uid = 0;
2785             long identity = Binder.clearCallingIdentity();
2786             try {
2787                 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
2788             } finally {
2789                 Binder.restoreCallingIdentity(identity);
2790             }
2791             return uid;
2792         }
2793     };
2794
2795     private void applyAdjustment(NotificationRecord n, Adjustment adjustment) {
2796         if (n == null) {
2797             return;
2798         }
2799         if (adjustment.getSignals() != null) {
2800             Bundle.setDefusable(adjustment.getSignals(), true);
2801             final ArrayList<String> people =
2802                     adjustment.getSignals().getStringArrayList(Adjustment.KEY_PEOPLE);
2803             final ArrayList<SnoozeCriterion> snoozeCriterionList =
2804                     adjustment.getSignals().getParcelableArrayList(Adjustment.KEY_SNOOZE_CRITERIA);
2805             n.setPeopleOverride(people);
2806             n.setSnoozeCriteria(snoozeCriterionList);
2807         }
2808     }
2809
2810     @GuardedBy("mNotificationLock")
2811     private void addAutogroupKeyLocked(String key) {
2812         NotificationRecord n = mNotificationsByKey.get(key);
2813         if (n == null) {
2814             return;
2815         }
2816         n.setOverrideGroupKey(GroupHelper.AUTOGROUP_KEY);
2817         EventLogTags.writeNotificationAutogrouped(key);
2818     }
2819
2820     @GuardedBy("mNotificationLock")
2821     private void removeAutogroupKeyLocked(String key) {
2822         NotificationRecord n = mNotificationsByKey.get(key);
2823         if (n == null) {
2824             return;
2825         }
2826         n.setOverrideGroupKey(null);
2827         EventLogTags.writeNotificationUnautogrouped(key);
2828     }
2829
2830     // Clears the 'fake' auto-group summary.
2831     @GuardedBy("mNotificationLock")
2832     private void clearAutogroupSummaryLocked(int userId, String pkg) {
2833         ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
2834         if (summaries != null && summaries.containsKey(pkg)) {
2835             // Clear summary.
2836             final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
2837             if (removed != null) {
2838                 boolean wasPosted = removeFromNotificationListsLocked(removed);
2839                 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED, wasPosted);
2840             }
2841         }
2842     }
2843
2844     // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
2845     private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
2846         NotificationRecord summaryRecord = null;
2847         synchronized (mNotificationLock) {
2848             NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
2849             if (notificationRecord == null) {
2850                 // The notification could have been cancelled again already. A successive
2851                 // adjustment will post a summary if needed.
2852                 return;
2853             }
2854             final StatusBarNotification adjustedSbn = notificationRecord.sbn;
2855             userId = adjustedSbn.getUser().getIdentifier();
2856             ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
2857             if (summaries == null) {
2858                 summaries = new ArrayMap<>();
2859             }
2860             mAutobundledSummaries.put(userId, summaries);
2861             if (!summaries.containsKey(pkg)) {
2862                 // Add summary
2863                 final ApplicationInfo appInfo =
2864                        adjustedSbn.getNotification().extras.getParcelable(
2865                                Notification.EXTRA_BUILDER_APPLICATION_INFO);
2866                 final Bundle extras = new Bundle();
2867                 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
2868                 final String channelId = notificationRecord.getChannel().getId();
2869                 final Notification summaryNotification =
2870                         new Notification.Builder(getContext(), channelId)
2871                                 .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
2872                                 .setGroupSummary(true)
2873                                 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN)
2874                                 .setGroup(GroupHelper.AUTOGROUP_KEY)
2875                                 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
2876                                 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
2877                                 .setColor(adjustedSbn.getNotification().color)
2878                                 .setLocalOnly(true)
2879                                 .build();
2880                 summaryNotification.extras.putAll(extras);
2881                 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
2882                 if (appIntent != null) {
2883                     summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
2884                             getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
2885                 }
2886                 final StatusBarNotification summarySbn =
2887                         new StatusBarNotification(adjustedSbn.getPackageName(),
2888                                 adjustedSbn.getOpPkg(),
2889                                 Integer.MAX_VALUE,
2890                                 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
2891                                 adjustedSbn.getInitialPid(), summaryNotification,
2892                                 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
2893                                 System.currentTimeMillis());
2894                 summaryRecord = new NotificationRecord(getContext(), summarySbn,
2895                         notificationRecord.getChannel());
2896                 summaries.put(pkg, summarySbn.getKey());
2897             }
2898         }
2899         if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
2900                 summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord)) {
2901             mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
2902         }
2903     }
2904
2905     private String disableNotificationEffects(NotificationRecord record) {
2906         if (mDisableNotificationEffects) {
2907             return "booleanState";
2908         }
2909         if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
2910             return "listenerHints";
2911         }
2912         if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
2913             return "callState";
2914         }
2915         return null;
2916     };
2917
2918     private void dumpJson(PrintWriter pw, DumpFilter filter) {
2919         JSONObject dump = new JSONObject();
2920         try {
2921             dump.put("service", "Notification Manager");
2922             dump.put("bans", mRankingHelper.dumpBansJson(filter));
2923             dump.put("ranking", mRankingHelper.dumpJson(filter));
2924             dump.put("stats", mUsageStats.dumpJson(filter));
2925             dump.put("channels", mRankingHelper.dumpChannelsJson(filter));
2926         } catch (JSONException e) {
2927             e.printStackTrace();
2928         }
2929         pw.println(dump);
2930     }
2931
2932     private void dumpProto(FileDescriptor fd, DumpFilter filter) {
2933         final ProtoOutputStream proto = new ProtoOutputStream(fd);
2934         synchronized (mNotificationLock) {
2935             long records = proto.start(NotificationServiceDumpProto.RECORDS);
2936             int N = mNotificationList.size();
2937             if (N > 0) {
2938                 for (int i = 0; i < N; i++) {
2939                     final NotificationRecord nr = mNotificationList.get(i);
2940                     if (filter.filtered && !filter.matches(nr.sbn)) continue;
2941                     nr.dump(proto, filter.redact);
2942                     proto.write(NotificationRecordProto.STATE, NotificationServiceProto.POSTED);
2943                 }
2944             }
2945             N = mEnqueuedNotifications.size();
2946             if (N > 0) {
2947                 for (int i = 0; i < N; i++) {
2948                     final NotificationRecord nr = mEnqueuedNotifications.get(i);
2949                     if (filter.filtered && !filter.matches(nr.sbn)) continue;
2950                     nr.dump(proto, filter.redact);
2951                     proto.write(NotificationRecordProto.STATE, NotificationServiceProto.ENQUEUED);
2952                 }
2953             }
2954             List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
2955             N = snoozed.size();
2956             if (N > 0) {
2957                 for (int i = 0; i < N; i++) {
2958                     final NotificationRecord nr = snoozed.get(i);
2959                     if (filter.filtered && !filter.matches(nr.sbn)) continue;
2960                     nr.dump(proto, filter.redact);
2961                     proto.write(NotificationRecordProto.STATE, NotificationServiceProto.SNOOZED);
2962                 }
2963             }
2964             proto.end(records);
2965         }
2966
2967         long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
2968         mZenModeHelper.dump(proto);
2969         for (ComponentName suppressor : mEffectsSuppressors) {
2970             proto.write(ZenModeProto.SUPPRESSORS, suppressor.toString());
2971         }
2972         proto.end(zenLog);
2973
2974         proto.flush();
2975     }
2976
2977     void dumpImpl(PrintWriter pw, DumpFilter filter) {
2978         pw.print("Current Notification Manager state");
2979         if (filter.filtered) {
2980             pw.print(" (filtered to "); pw.print(filter); pw.print(")");
2981         }
2982         pw.println(':');
2983         int N;
2984         final boolean zenOnly = filter.filtered && filter.zen;
2985
2986         if (!zenOnly) {
2987             synchronized (mToastQueue) {
2988                 N = mToastQueue.size();
2989                 if (N > 0) {
2990                     pw.println("  Toast Queue:");
2991                     for (int i=0; i<N; i++) {
2992                         mToastQueue.get(i).dump(pw, "    ", filter);
2993                     }
2994                     pw.println("  ");
2995                 }
2996             }
2997         }
2998
2999         synchronized (mNotificationLock) {
3000             if (!zenOnly) {
3001                 N = mNotificationList.size();
3002                 if (N > 0) {
3003                     pw.println("  Notification List:");
3004                     for (int i=0; i<N; i++) {
3005                         final NotificationRecord nr = mNotificationList.get(i);
3006                         if (filter.filtered && !filter.matches(nr.sbn)) continue;
3007                         nr.dump(pw, "    ", getContext(), filter.redact);
3008                     }
3009                     pw.println("  ");
3010                 }
3011
3012                 if (!filter.filtered) {
3013                     N = mLights.size();
3014                     if (N > 0) {
3015                         pw.println("  Lights List:");
3016                         for (int i=0; i<N; i++) {
3017                             if (i == N - 1) {
3018                                 pw.print("  > ");
3019                             } else {
3020                                 pw.print("    ");
3021                             }
3022                             pw.println(mLights.get(i));
3023                         }
3024                         pw.println("  ");
3025                     }
3026                     pw.println("  mUseAttentionLight=" + mUseAttentionLight);
3027                     pw.println("  mNotificationPulseEnabled=" + mNotificationPulseEnabled);
3028                     pw.println("  mSoundNotificationKey=" + mSoundNotificationKey);
3029                     pw.println("  mVibrateNotificationKey=" + mVibrateNotificationKey);
3030                     pw.println("  mDisableNotificationEffects=" + mDisableNotificationEffects);
3031                     pw.println("  mCallState=" + callStateToString(mCallState));
3032                     pw.println("  mSystemReady=" + mSystemReady);
3033                     pw.println("  mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
3034                 }
3035                 pw.println("  mArchive=" + mArchive.toString());
3036                 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
3037                 int j=0;
3038                 while (iter.hasNext()) {
3039                     final StatusBarNotification sbn = iter.next();
3040                     if (filter != null && !filter.matches(sbn)) continue;
3041                     pw.println("    " + sbn);
3042                     if (++j >= 5) {
3043                         if (iter.hasNext()) pw.println("    ...");
3044                         break;
3045                     }
3046                 }
3047
3048                 if (!zenOnly) {
3049                     N = mEnqueuedNotifications.size();
3050                     if (N > 0) {
3051                         pw.println("  Enqueued Notification List:");
3052                         for (int i = 0; i < N; i++) {
3053                             final NotificationRecord nr = mEnqueuedNotifications.get(i);
3054                             if (filter.filtered && !filter.matches(nr.sbn)) continue;
3055                             nr.dump(pw, "    ", getContext(), filter.redact);
3056                         }
3057                         pw.println("  ");
3058                     }
3059
3060                     mSnoozeHelper.dump(pw, filter);
3061                 }
3062             }
3063
3064             if (!zenOnly) {
3065                 pw.println("\n  Ranking Config:");
3066                 mRankingHelper.dump(pw, "    ", filter);
3067
3068                 pw.println("\n  Notification listeners:");
3069                 mListeners.dump(pw, filter);
3070                 pw.print("    mListenerHints: "); pw.println(mListenerHints);
3071                 pw.print("    mListenersDisablingEffects: (");
3072                 N = mListenersDisablingEffects.size();
3073                 for (int i = 0; i < N; i++) {
3074                     final int hint = mListenersDisablingEffects.keyAt(i);
3075                     if (i > 0) pw.print(';');
3076                     pw.print("hint[" + hint + "]:");
3077
3078                     final ArraySet<ManagedServiceInfo> listeners =
3079                             mListenersDisablingEffects.valueAt(i);
3080                     final int listenerSize = listeners.size();
3081
3082                     for (int j = 0; j < listenerSize; j++) {
3083                         if (i > 0) pw.print(',');
3084                         final ManagedServiceInfo listener = listeners.valueAt(i);
3085                         pw.print(listener.component);
3086                     }
3087                 }
3088                 pw.println(')');
3089                 pw.println("\n  Notification assistant services:");
3090                 mNotificationAssistants.dump(pw, filter);
3091             }
3092
3093             if (!filter.filtered || zenOnly) {
3094                 pw.println("\n  Zen Mode:");
3095                 pw.print("    mInterruptionFilter="); pw.println(mInterruptionFilter);
3096                 mZenModeHelper.dump(pw, "    ");
3097
3098                 pw.println("\n  Zen Log:");
3099                 ZenLog.dump(pw, "    ");
3100             }
3101
3102             pw.println("\n  Policy access:");
3103             pw.print("    mPolicyAccess: "); pw.println(mPolicyAccess);
3104
3105             pw.println("\n  Condition providers:");
3106             mConditionProviders.dump(pw, filter);
3107
3108             pw.println("\n  Group summaries:");
3109             for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
3110                 NotificationRecord r = entry.getValue();
3111                 pw.println("    " + entry.getKey() + " -> " + r.getKey());
3112                 if (mNotificationsByKey.get(r.getKey()) != r) {
3113                     pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
3114                     r.dump(pw, "      ", getContext(), filter.redact);
3115                 }
3116             }
3117
3118             if (!zenOnly) {
3119                 pw.println("\n  Usage Stats:");
3120                 mUsageStats.dump(pw, "    ", filter);
3121             }
3122         }
3123     }
3124
3125     /**
3126      * The private API only accessible to the system process.
3127      */
3128     private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
3129         @Override
3130         public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
3131                 String tag, int id, Notification notification, int userId) {
3132             enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
3133                     userId);
3134         }
3135
3136         @Override
3137         public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
3138                 int userId) {
3139             checkCallerIsSystem();
3140             mHandler.post(new Runnable() {
3141                 @Override
3142                 public void run() {
3143                     synchronized (mNotificationLock) {
3144                         removeForegroundServiceFlagByListLocked(
3145                                 mEnqueuedNotifications, pkg, notificationId, userId);
3146                         removeForegroundServiceFlagByListLocked(
3147                                 mNotificationList, pkg, notificationId, userId);
3148                     }
3149                 }
3150             });
3151         }
3152
3153         @GuardedBy("mNotificationLock")
3154         private void removeForegroundServiceFlagByListLocked(
3155                 ArrayList<NotificationRecord> notificationList, String pkg, int notificationId,
3156                 int userId) {
3157             NotificationRecord r = findNotificationByListLocked(
3158                     notificationList, pkg, null, notificationId, userId);
3159             if (r == null) {
3160                 return;
3161             }
3162             StatusBarNotification sbn = r.sbn;
3163             // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
3164             // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
3165             // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
3166             // initially *and* force remove FLAG_FOREGROUND_SERVICE.
3167             sbn.getNotification().flags =
3168                     (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
3169             mRankingHelper.sort(mNotificationList);
3170             mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
3171             mGroupHelper.onNotificationPosted(sbn);
3172         }
3173     };
3174
3175     void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
3176             final int callingPid, final String tag, final int id, final Notification notification,
3177             int incomingUserId) {
3178         if (DBG) {
3179             Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
3180                     + " notification=" + notification);
3181         }
3182         checkCallerIsSystemOrSameApp(pkg);
3183
3184         final int userId = ActivityManager.handleIncomingUser(callingPid,
3185                 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
3186         final UserHandle user = new UserHandle(userId);
3187
3188         if (pkg == null || notification == null) {
3189             throw new IllegalArgumentException("null not allowed: pkg=" + pkg
3190                     + " id=" + id + " notification=" + notification);
3191         }
3192
3193         // The system can post notifications for any package, let us resolve that.
3194         final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);
3195
3196         // Fix the notification as best we can.
3197         try {
3198             final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
3199                     pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
3200                     (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
3201             Notification.addFieldsFromContext(ai, notification);
3202         } catch (NameNotFoundException e) {
3203             Slog.e(TAG, "Cannot create a context for sending app", e);
3204             return;
3205         }
3206
3207         mUsageStats.registerEnqueuedByApp(pkg);
3208
3209         // setup local book-keeping
3210         String channelId = notification.getChannelId();
3211         if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
3212             channelId = (new Notification.TvExtender(notification)).getChannelId();
3213         }
3214         final NotificationChannel channel = mRankingHelper.getNotificationChannel(pkg,
3215                 notificationUid, channelId, false /* includeDeleted */);
3216         if (channel == null) {
3217             final String noChannelStr = "No Channel found for "
3218                     + "pkg=" + pkg
3219                     + ", channelId=" + channelId
3220                     + ", id=" + id
3221                     + ", tag=" + tag
3222                     + ", opPkg=" + opPkg
3223                     + ", callingUid=" + callingUid
3224                     + ", userId=" + userId
3225                     + ", incomingUserId=" + incomingUserId
3226                     + ", notificationUid=" + notificationUid
3227                     + ", notification=" + notification;
3228             Log.e(TAG, noChannelStr);
3229             doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
3230                     "Failed to post notification on channel \"" + channelId + "\"\n" +
3231                     "See log for more details");
3232             return;
3233         }
3234
3235         final StatusBarNotification n = new StatusBarNotification(
3236                 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
3237                 user, null, System.currentTimeMillis());
3238         final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
3239
3240         if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r)) {
3241             return;
3242         }
3243
3244         // Whitelist pending intents.
3245         if (notification.allPendingIntents != null) {
3246             final int intentCount = notification.allPendingIntents.size();
3247             if (intentCount > 0) {
3248                 final ActivityManagerInternal am = LocalServices
3249                         .getService(ActivityManagerInternal.class);
3250                 final long duration = LocalServices.getService(
3251                         DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
3252                 for (int i = 0; i < intentCount; i++) {
3253                     PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
3254                     if (pendingIntent != null) {
3255                         am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
3256                                 WHITELIST_TOKEN, duration);
3257                     }
3258                 }
3259             }
3260         }
3261
3262         mHandler.post(new EnqueueNotificationRunnable(userId, r));
3263     }
3264
3265     private void doChannelWarningToast(CharSequence toastText) {
3266         final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
3267         final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
3268                 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
3269         if (warningEnabled) {
3270             Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
3271                     Toast.LENGTH_SHORT);
3272             toast.show();
3273         }
3274     }
3275
3276     private int resolveNotificationUid(String opPackageName, int callingUid, int userId) {
3277         // The system can post notifications on behalf of any package it wants
3278         if (isCallerSystemOrPhone() && opPackageName != null && !"android".equals(opPackageName)) {
3279             try {
3280                 return getContext().getPackageManager()
3281                         .getPackageUidAsUser(opPackageName, userId);
3282             } catch (NameNotFoundException e) {
3283                 /* ignore */
3284             }
3285         }
3286         return callingUid;
3287     }
3288
3289     /**
3290      * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
3291      *
3292      * Has side effects.
3293      */
3294     private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag,
3295             NotificationRecord r) {
3296         final String pkg = r.sbn.getPackageName();
3297         final boolean isSystemNotification =
3298                 isUidSystemOrPhone(callingUid) || ("android".equals(pkg));
3299         final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
3300
3301         // Limit the number of notifications that any given package except the android
3302         // package or a registered listener can enqueue.  Prevents DOS attacks and deals with leaks.
3303         if (!isSystemNotification && !isNotificationFromListener) {
3304             synchronized (mNotificationLock) {
3305                 if (mNotificationsByKey.get(r.sbn.getKey()) != null) {
3306                     // this is an update, rate limit updates only
3307                     final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
3308                     if (appEnqueueRate > mMaxPackageEnqueueRate) {
3309                         mUsageStats.registerOverRateQuota(pkg);
3310                         final long now = SystemClock.elapsedRealtime();
3311                         if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
3312                             Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
3313                                     + ". Shedding events. package=" + pkg);
3314                             mLastOverRateLogTime = now;
3315                         }
3316                         return false;
3317                     }
3318                 } else if (isCallerInstantApp(pkg)) {
3319                     // Ephemeral apps have some special constraints for notifications.
3320                     // They are not allowed to create new notifications however they are allowed to
3321                     // update notifications created by the system (e.g. a foreground service
3322                     // notification).
3323                     throw new SecurityException("Instant app " + pkg
3324                             + " cannot create notifications");
3325                 }
3326
3327                 int count = 0;
3328                 final int N = mNotificationList.size();
3329                 for (int i=0; i<N; i++) {
3330                     final NotificationRecord existing = mNotificationList.get(i);
3331                     if (existing.sbn.getPackageName().equals(pkg)
3332                             && existing.sbn.getUserId() == userId) {
3333                         if (existing.sbn.getId() == id
3334                                 && TextUtils.equals(existing.sbn.getTag(), tag)) {
3335                             break;  // Allow updating existing notification
3336                         }
3337                         count++;
3338                         if (count >= MAX_PACKAGE_NOTIFICATIONS) {
3339                             mUsageStats.registerOverCountQuota(pkg);
3340                             Slog.e(TAG, "Package has already posted " + count
3341                                     + " notifications.  Not showing more.  package=" + pkg);
3342                             return false;
3343                         }
3344                     }
3345                 }
3346             }
3347         }
3348
3349         // snoozed apps
3350         if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
3351             MetricsLogger.action(r.getLogMaker()
3352                     .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
3353                     .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
3354             if (DBG) {
3355                 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
3356             }
3357             mSnoozeHelper.update(userId, r);
3358             savePolicyFile();
3359             return false;
3360         }
3361
3362
3363         // blocked apps
3364         if (isBlocked(r, mUsageStats)) {
3365             return false;
3366         }
3367
3368         return true;
3369     }
3370
3371     protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
3372         final String pkg = r.sbn.getPackageName();
3373         final int callingUid = r.sbn.getUid();
3374
3375         final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
3376         if (isPackageSuspended) {
3377             Slog.e(TAG, "Suppressing notification from package due to package "
3378                     + "suspended by administrator.");
3379             usageStats.registerSuspendedByAdmin(r);
3380             return isPackageSuspended;
3381         }
3382
3383         final boolean isBlocked =
3384                 mRankingHelper.getImportance(pkg, callingUid) == NotificationManager.IMPORTANCE_NONE
3385                 || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE;
3386         if (isBlocked) {
3387             Slog.e(TAG, "Suppressing notification from package by user request.");
3388             usageStats.registerBlocked(r);
3389         }
3390         return isBlocked;
3391     }
3392
3393     protected class SnoozeNotificationRunnable implements Runnable {
3394         private final String mKey;
3395         private final long mDuration;
3396         private final String mSnoozeCriterionId;
3397
3398         SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) {
3399             mKey = key;
3400             mDuration = duration;
3401             mSnoozeCriterionId = snoozeCriterionId;
3402         }
3403
3404         @Override
3405         public void run() {
3406             synchronized (mNotificationLock) {
3407                 final NotificationRecord r = findNotificationByKeyLocked(mKey);
3408                 if (r != null) {
3409                     snoozeLocked(r);
3410                 }
3411             }
3412         }
3413
3414         @GuardedBy("mNotificationLock")
3415         void snoozeLocked(NotificationRecord r) {
3416             if (r.sbn.isGroup()) {
3417                 final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked(
3418                         r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId());
3419                 if (r.getNotification().isGroupSummary()) {
3420                     // snooze summary and all children
3421                     for (int i = 0; i < groupNotifications.size(); i++) {
3422                         snoozeNotificationLocked(groupNotifications.get(i));
3423                     }
3424                 } else {
3425                     // if there is a valid summary for this group, and we are snoozing the only
3426                     // child, also snooze the summary
3427                     if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) {
3428                         if (groupNotifications.size() != 2) {
3429                             snoozeNotificationLocked(r);
3430                         } else {
3431                             // snooze summary and the one child
3432                             for (int i = 0; i < groupNotifications.size(); i++) {
3433                                 snoozeNotificationLocked(groupNotifications.get(i));
3434                             }
3435                         }
3436                     } else {
3437                         snoozeNotificationLocked(r);
3438                     }
3439                 }
3440             } else {
3441                 // just snooze the one notification
3442                 snoozeNotificationLocked(r);
3443             }
3444         }
3445
3446         @GuardedBy("mNotificationLock")
3447         void snoozeNotificationLocked(NotificationRecord r) {
3448             MetricsLogger.action(r.getLogMaker()
3449                     .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
3450                     .setType(MetricsEvent.TYPE_CLOSE)
3451                     .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
3452                             mSnoozeCriterionId == null ? 0 : 1));
3453             boolean wasPosted = removeFromNotificationListsLocked(r);
3454             cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted);
3455             updateLightsLocked();
3456             if (mSnoozeCriterionId != null) {
3457                 mNotificationAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
3458                 mSnoozeHelper.snooze(r);
3459             } else {
3460                 mSnoozeHelper.snooze(r, mDuration);
3461             }
3462             savePolicyFile();
3463         }
3464     }
3465
3466     protected class EnqueueNotificationRunnable implements Runnable {
3467         private final NotificationRecord r;
3468         private final int userId;
3469
3470         EnqueueNotificationRunnable(int userId, NotificationRecord r) {
3471             this.userId = userId;
3472             this.r = r;
3473         };
3474
3475         @Override
3476         public void run() {
3477             synchronized (mNotificationLock) {
3478                 mEnqueuedNotifications.add(r);
3479                 scheduleTimeoutLocked(r);
3480
3481                 final StatusBarNotification n = r.sbn;
3482                 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
3483                 NotificationRecord old = mNotificationsByKey.get(n.getKey());
3484                 if (old != null) {
3485                     // Retain ranking information from previous record
3486                     r.copyRankingInformation(old);
3487                 }
3488
3489                 final int callingUid = n.getUid();
3490                 final int callingPid = n.getInitialPid();
3491                 final Notification notification = n.getNotification();
3492                 final String pkg = n.getPackageName();
3493                 final int id = n.getId();
3494                 final String tag = n.getTag();
3495
3496                 // Handle grouped notifications and bail out early if we
3497                 // can to avoid extracting signals.
3498                 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
3499
3500                 // if this is a group child, unsnooze parent summary
3501                 if (n.isGroup() && notification.isGroupChild()) {
3502                     mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
3503                 }
3504
3505                 // This conditional is a dirty hack to limit the logging done on
3506                 //     behalf of the download manager without affecting other apps.
3507                 if (!pkg.equals("com.android.providers.downloads")
3508                         || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
3509                     int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
3510                     if (old != null) {
3511                         enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
3512                     }
3513                     EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
3514                             pkg, id, tag, userId, notification.toString(),
3515                             enqueueStatus);
3516                 }
3517
3518                 mRankingHelper.extractSignals(r);
3519
3520                 // tell the assistant service about the notification
3521                 if (mNotificationAssistants.isEnabled()) {
3522                     mNotificationAssistants.onNotificationEnqueued(r);
3523                     mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
3524                             DELAY_FOR_ASSISTANT_TIME);
3525                 } else {
3526                     mHandler.post(new PostNotificationRunnable(r.getKey()));
3527                 }
3528             }
3529         }
3530     }
3531
3532     protected class PostNotificationRunnable implements Runnable {
3533         private final String key;
3534
3535         PostNotificationRunnable(String key) {
3536             this.key = key;
3537         }
3538
3539         @Override
3540         public void run() {
3541             synchronized (mNotificationLock) {
3542                 try {
3543                     NotificationRecord r = null;
3544                     int N = mEnqueuedNotifications.size();
3545                     for (int i = 0; i < N; i++) {
3546                         final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
3547                         if (Objects.equals(key, enqueued.getKey())) {
3548                             r = enqueued;
3549                             break;
3550                         }
3551                     }
3552                     if (r == null) {
3553                         Slog.i(TAG, "Cannot find enqueued record for key: " + key);
3554                         return;
3555                     }
3556                     NotificationRecord old = mNotificationsByKey.get(key);
3557                     final StatusBarNotification n = r.sbn;
3558                     final Notification notification = n.getNotification();
3559                     int index = indexOfNotificationLocked(n.getKey());
3560                     if (index < 0) {
3561                         mNotificationList.add(r);
3562                         mUsageStats.registerPostedByApp(r);
3563                     } else {
3564                         old = mNotificationList.get(index);
3565                         mNotificationList.set(index, r);
3566                         mUsageStats.registerUpdatedByApp(r, old);
3567                         // Make sure we don't lose the foreground service state.
3568                         notification.flags |=
3569                                 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
3570                         r.isUpdate = true;
3571                     }
3572
3573                     mNotificationsByKey.put(n.getKey(), r);
3574
3575                     // Ensure if this is a foreground service that the proper additional
3576                     // flags are set.
3577                     if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
3578                         notification.flags |= Notification.FLAG_ONGOING_EVENT
3579                                 | Notification.FLAG_NO_CLEAR;
3580                     }
3581
3582                     applyZenModeLocked(r);
3583                     mRankingHelper.sort(mNotificationList);
3584
3585                     if (notification.getSmallIcon() != null) {
3586                         StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
3587                         mListeners.notifyPostedLocked(n, oldSbn);
3588                         mHandler.post(new Runnable() {
3589                             @Override
3590                             public void run() {
3591                                 mGroupHelper.onNotificationPosted(n);
3592                             }
3593                         });
3594                     } else {
3595                         Slog.e(TAG, "Not posting notification without small icon: " + notification);
3596                         if (old != null && !old.isCanceled) {
3597                             mListeners.notifyRemovedLocked(n,
3598                                     NotificationListenerService.REASON_ERROR);
3599                             mHandler.post(new Runnable() {
3600                                 @Override
3601                                 public void run() {
3602                                     mGroupHelper.onNotificationRemoved(n);
3603                                 }
3604                             });
3605                         }
3606                         // ATTENTION: in a future release we will bail out here
3607                         // so that we do not play sounds, show lights, etc. for invalid
3608                         // notifications
3609                         Slog.e(TAG, "WARNING: In a future release this will crash the app: "
3610                                 + n.getPackageName());
3611                     }
3612
3613                     buzzBeepBlinkLocked(r);
3614                 } finally {
3615                     int N = mEnqueuedNotifications.size();
3616                     for (int i = 0; i < N; i++) {
3617                         final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
3618                         if (Objects.equals(key, enqueued.getKey())) {
3619                             mEnqueuedNotifications.remove(i);
3620                             break;
3621                         }
3622                     }
3623                 }
3624             }
3625         }
3626     }
3627
3628     /**
3629      * Ensures that grouped notification receive their special treatment.
3630      *
3631      * <p>Cancels group children if the new notification causes a group to lose
3632      * its summary.</p>
3633      *
3634      * <p>Updates mSummaryByGroupKey.</p>
3635      */
3636     @GuardedBy("mNotificationLock")
3637     private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
3638             int callingUid, int callingPid) {
3639         StatusBarNotification sbn = r.sbn;
3640         Notification n = sbn.getNotification();
3641         if (n.isGroupSummary() && !sbn.isAppGroup())  {
3642             // notifications without a group shouldn't be a summary, otherwise autobundling can
3643             // lead to bugs
3644             n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
3645         }
3646
3647         String group = sbn.getGroupKey();
3648         boolean isSummary = n.isGroupSummary();
3649
3650         Notification oldN = old != null ? old.sbn.getNotification() : null;
3651         String oldGroup = old != null ? old.sbn.getGroupKey() : null;
3652         boolean oldIsSummary = old != null && oldN.isGroupSummary();
3653
3654         if (oldIsSummary) {
3655             NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
3656             if (removedSummary != old) {
3657                 String removedKey =
3658                         removedSummary != null ? removedSummary.getKey() : "<null>";
3659                 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
3660                         ", removed=" + removedKey);
3661             }
3662         }
3663         if (isSummary) {
3664             mSummaryByGroupKey.put(group, r);
3665         }
3666
3667         // Clear out group children of the old notification if the update
3668         // causes the group summary to go away. This happens when the old
3669         // notification was a summary and the new one isn't, or when the old
3670         // notification was a summary and its group key changed.
3671         if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
3672             cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */);
3673         }
3674     }
3675
3676     @VisibleForTesting
3677     @GuardedBy("mNotificationLock")
3678     void scheduleTimeoutLocked(NotificationRecord record) {
3679         if (record.getNotification().getTimeoutAfter() > 0) {
3680             final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
3681                     REQUEST_CODE_TIMEOUT,
3682                     new Intent(ACTION_NOTIFICATION_TIMEOUT)
3683                             .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
3684                                     .appendPath(record.getKey()).build())
3685                             .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
3686                             .putExtra(EXTRA_KEY, record.getKey()),
3687                     PendingIntent.FLAG_UPDATE_CURRENT);
3688             mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
3689                     SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
3690         }
3691     }
3692
3693     @VisibleForTesting
3694     @GuardedBy("mNotificationLock")
3695     void buzzBeepBlinkLocked(NotificationRecord record) {
3696         boolean buzz = false;
3697         boolean beep = false;
3698         boolean blink = false;
3699
3700         final Notification notification = record.sbn.getNotification();
3701         final String key = record.getKey();
3702
3703         // Should this notification make noise, vibe, or use the LED?
3704         final boolean aboveThreshold =
3705                 record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
3706         final boolean canInterrupt = aboveThreshold && !record.isIntercepted();
3707         if (DBG)
3708             Slog.v(TAG,
3709                     "pkg=" + record.sbn.getPackageName() + " canInterrupt=" + canInterrupt +
3710                             " intercept=" + record.isIntercepted()
3711             );
3712
3713         // If we're not supposed to beep, vibrate, etc. then don't.
3714         final String disableEffects = disableNotificationEffects(record);
3715         if (disableEffects != null) {
3716             ZenLog.traceDisableEffects(record, disableEffects);
3717         }
3718
3719         // Remember if this notification already owns the notification channels.
3720         boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
3721         boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
3722         // These are set inside the conditional if the notification is allowed to make noise.
3723         boolean hasValidVibrate = false;
3724         boolean hasValidSound = false;
3725
3726         if (isNotificationForCurrentUser(record)) {
3727             // If the notification will appear in the status bar, it should send an accessibility
3728             // event
3729             if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) {
3730                 sendAccessibilityEvent(notification, record.sbn.getPackageName());
3731             }
3732
3733             if (disableEffects == null
3734                     && canInterrupt
3735                     && mSystemReady
3736                     && mAudioManager != null) {
3737                 if (DBG) Slog.v(TAG, "Interrupting!");
3738                 Uri soundUri = record.getSound();
3739                 hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
3740                 long[] vibration = record.getVibration();
3741                 // Demote sound to vibration if vibration missing & phone in vibration mode.
3742                 if (vibration == null
3743                         && hasValidSound
3744                         && (mAudioManager.getRingerModeInternal()
3745                         == AudioManager.RINGER_MODE_VIBRATE)) {
3746                     vibration = mFallbackVibrationPattern;
3747                 }
3748                 hasValidVibrate = vibration != null;
3749
3750                 if (!shouldMuteNotificationLocked(record)) {
3751                     if (hasValidSound) {
3752                         mSoundNotificationKey = key;
3753                         if (mInCall) {
3754                             playInCallNotification();
3755                             beep = true;
3756                         } else {
3757                             beep = playSound(record, soundUri);
3758                         }
3759                     }
3760
3761                     final boolean ringerModeSilent =
3762                             mAudioManager.getRingerModeInternal()
3763                                     == AudioManager.RINGER_MODE_SILENT;
3764                     if (!mInCall && hasValidVibrate && !ringerModeSilent) {
3765                         mVibrateNotificationKey = key;
3766
3767                         buzz = playVibration(record, vibration, hasValidSound);
3768                     }
3769                 }
3770             }
3771         }
3772         // If a notification is updated to remove the actively playing sound or vibrate,
3773         // cancel that feedback now
3774         if (wasBeep && !hasValidSound) {
3775             clearSoundLocked();
3776         }
3777         if (wasBuzz && !hasValidVibrate) {
3778             clearVibrateLocked();
3779         }
3780
3781         // light
3782         // release the light
3783         boolean wasShowLights = mLights.remove(key);
3784         if (record.getLight() != null && aboveThreshold
3785                 && ((record.getSuppressedVisualEffects()
3786                 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
3787             mLights.add(key);
3788             updateLightsLocked();
3789             if (mUseAttentionLight) {
3790                 mAttentionLight.pulse();
3791             }
3792             blink = true;
3793         } else if (wasShowLights) {
3794             updateLightsLocked();
3795         }
3796         if (buzz || beep || blink) {
3797             MetricsLogger.action(record.getLogMaker()
3798                     .setCategory(MetricsEvent.NOTIFICATION_ALERT)
3799                     .setType(MetricsEvent.TYPE_OPEN)
3800                     .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
3801             EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
3802         }
3803     }
3804
3805     @GuardedBy("mNotificationLock")
3806     boolean shouldMuteNotificationLocked(final NotificationRecord record) {
3807         final Notification notification = record.getNotification();
3808         if(record.isUpdate
3809                 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
3810             return true;
3811         }
3812         if (record.sbn.isGroup()) {
3813             return notification.suppressAlertingDueToGrouping();
3814         }
3815         return false;
3816     }
3817
3818     private boolean playSound(final NotificationRecord record, Uri soundUri) {
3819         boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
3820         // do not play notifications if there is a user of exclusive audio focus
3821         // or the device is in vibrate mode
3822         if (!mAudioManager.isAudioFocusExclusive() && mAudioManager.getRingerModeInternal()
3823                 != AudioManager.RINGER_MODE_VIBRATE) {
3824             final long identity = Binder.clearCallingIdentity();
3825             try {
3826                 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
3827                 if (player != null) {
3828                     if (DBG) Slog.v(TAG, "Playing sound " + soundUri
3829                             + " with attributes " + record.getAudioAttributes());
3830                     player.playAsync(soundUri, record.sbn.getUser(), looping,
3831                             record.getAudioAttributes());
3832                     return true;
3833                 }
3834             } catch (RemoteException e) {
3835             } finally {
3836                 Binder.restoreCallingIdentity(identity);
3837             }
3838         }
3839         return false;
3840     }
3841
3842     private boolean playVibration(final NotificationRecord record, long[] vibration,
3843             boolean delayVibForSound) {
3844         // Escalate privileges so we can use the vibrator even if the
3845         // notifying app does not have the VIBRATE permission.
3846         long identity = Binder.clearCallingIdentity();
3847         try {
3848             final VibrationEffect effect;
3849             try {
3850                 final boolean insistent =
3851                         (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
3852                 effect = VibrationEffect.createWaveform(
3853                         vibration, insistent ? 0 : -1 /*repeatIndex*/);
3854             } catch (IllegalArgumentException e) {
3855                 Slog.e(TAG, "Error creating vibration waveform with pattern: " +
3856                         Arrays.toString(vibration));
3857                 return false;
3858             }
3859             if (delayVibForSound) {
3860                 new Thread(() -> {
3861                     // delay the vibration by the same amount as the notification sound
3862                     final int waitMs = mAudioManager.getFocusRampTimeMs(
3863                             AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
3864                             record.getAudioAttributes());
3865                     if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms");
3866                     try {
3867                         Thread.sleep(waitMs);
3868                     } catch (InterruptedException e) { }
3869                     mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
3870                             effect, record.getAudioAttributes());
3871                 }).start();
3872             } else {
3873                 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
3874                         effect, record.getAudioAttributes());
3875             }
3876             return true;
3877         } finally{
3878             Binder.restoreCallingIdentity(identity);
3879         }
3880     }
3881
3882     private boolean isNotificationForCurrentUser(NotificationRecord record) {
3883         final int currentUser;
3884         final long token = Binder.clearCallingIdentity();
3885         try {
3886             currentUser = ActivityManager.getCurrentUser();
3887         } finally {
3888             Binder.restoreCallingIdentity(token);
3889         }
3890         return (record.getUserId() == UserHandle.USER_ALL ||
3891                 record.getUserId() == currentUser ||
3892                 mUserProfiles.isCurrentProfile(record.getUserId()));
3893     }
3894
3895     private void playInCallNotification() {
3896         new Thread() {
3897             @Override
3898             public void run() {
3899                 // If toneGenerator creation fails, just continue the call
3900                 // without playing the notification sound.
3901                 try {
3902                     synchronized (mInCallToneGeneratorLock) {
3903                         if (mInCallToneGenerator != null) {
3904                             // limit this tone to 1 second; BEEP2 should in fact be much shorter
3905                             mInCallToneGenerator.startTone(ToneGenerator.TONE_PROP_BEEP2, 1000);
3906                         }
3907                     }
3908                 } catch (RuntimeException e) {
3909                     Log.w(TAG, "Exception from ToneGenerator: " + e);
3910                 }
3911             }
3912         }.start();
3913     }
3914
3915     @GuardedBy("mToastQueue")
3916     void showNextToastLocked() {
3917         ToastRecord record = mToastQueue.get(0);
3918         while (record != null) {
3919             if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
3920             try {
3921                 record.callback.show(record.token);
3922                 scheduleTimeoutLocked(record);
3923                 return;
3924             } catch (RemoteException e) {
3925                 Slog.w(TAG, "Object died trying to show notification " + record.callback
3926                         + " in package " + record.pkg);
3927                 // remove it from the list and let the process die
3928                 int index = mToastQueue.indexOf(record);
3929                 if (index >= 0) {
3930                     mToastQueue.remove(index);
3931                 }
3932                 keepProcessAliveIfNeededLocked(record.pid);
3933                 if (mToastQueue.size() > 0) {
3934                     record = mToastQueue.get(0);
3935                 } else {
3936                     record = null;
3937                 }
3938             }
3939         }
3940     }
3941
3942     @GuardedBy("mToastQueue")
3943     void cancelToastLocked(int index) {
3944         ToastRecord record = mToastQueue.get(index);
3945         try {
3946             record.callback.hide();
3947         } catch (RemoteException e) {
3948             Slog.w(TAG, "Object died trying to hide notification " + record.callback
3949                     + " in package " + record.pkg);
3950             // don't worry about this, we're about to remove it from
3951             // the list anyway
3952         }
3953
3954         ToastRecord lastToast = mToastQueue.remove(index);
3955         mWindowManagerInternal.removeWindowToken(lastToast.token, true, DEFAULT_DISPLAY);
3956
3957         keepProcessAliveIfNeededLocked(record.pid);
3958         if (mToastQueue.size() > 0) {
3959             // Show the next one. If the callback fails, this will remove
3960             // it from the list, so don't assume that the list hasn't changed
3961             // after this point.
3962             showNextToastLocked();
3963         }
3964     }
3965
3966     @GuardedBy("mToastQueue")
3967     private void scheduleTimeoutLocked(ToastRecord r)
3968     {
3969         mHandler.removeCallbacksAndMessages(r);
3970         Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
3971         long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
3972         mHandler.sendMessageDelayed(m, delay);
3973     }
3974
3975     private void handleTimeout(ToastRecord record)
3976     {
3977         if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
3978         synchronized (mToastQueue) {
3979             int index = indexOfToastLocked(record.pkg, record.callback);
3980             if (index >= 0) {
3981                 cancelToastLocked(index);
3982             }
3983         }
3984     }
3985
3986     @GuardedBy("mToastQueue")
3987     int indexOfToastLocked(String pkg, ITransientNotification callback)
3988     {
3989         IBinder cbak = callback.asBinder();
3990         ArrayList<ToastRecord> list = mToastQueue;
3991         int len = list.size();
3992         for (int i=0; i<len; i++) {
3993             ToastRecord r = list.get(i);
3994             if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
3995                 return i;
3996             }
3997         }
3998         return -1;
3999     }
4000
4001     @GuardedBy("mToastQueue")
4002     void keepProcessAliveIfNeededLocked(int pid)
4003     {
4004         int toastCount = 0; // toasts from this pid
4005         ArrayList<ToastRecord> list = mToastQueue;
4006         int N = list.size();
4007         for (int i=0; i<N; i++) {
4008             ToastRecord r = list.get(i);
4009             if (r.pid == pid) {
4010                 toastCount++;
4011             }
4012         }
4013         try {
4014             mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
4015         } catch (RemoteException e) {
4016             // Shouldn't happen.
4017         }
4018     }
4019
4020     private void handleRankingReconsideration(Message message) {
4021         if (!(message.obj instanceof RankingReconsideration)) return;
4022         RankingReconsideration recon = (RankingReconsideration) message.obj;
4023         recon.run();
4024         boolean changed;
4025         synchronized (mNotificationLock) {
4026             final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
4027             if (record == null) {
4028                 return;
4029             }
4030             int indexBefore = findNotificationRecordIndexLocked(record);
4031             boolean interceptBefore = record.isIntercepted();
4032             int visibilityBefore = record.getPackageVisibilityOverride();
4033             recon.applyChangesLocked(record);
4034             applyZenModeLocked(record);
4035             mRankingHelper.sort(mNotificationList);
4036             int indexAfter = findNotificationRecordIndexLocked(record);
4037             boolean interceptAfter = record.isIntercepted();
4038             int visibilityAfter = record.getPackageVisibilityOverride();
4039             changed = indexBefore != indexAfter || interceptBefore != interceptAfter
4040                     || visibilityBefore != visibilityAfter;
4041             if (interceptBefore && !interceptAfter) {
4042                 buzzBeepBlinkLocked(record);
4043             }
4044         }
4045         if (changed) {
4046             scheduleSendRankingUpdate();
4047         }
4048     }
4049
4050     private void handleRankingSort(Message msg) {
4051         if (!(msg.obj instanceof Boolean)) return;
4052         if (mRankingHelper == null) return;
4053         boolean forceUpdate = ((Boolean) msg.obj == null) ? false : (boolean) msg.obj;
4054         synchronized (mNotificationLock) {
4055             final int N = mNotificationList.size();
4056             // Any field that can change via one of the extractors or by the assistant
4057             // needs to be added here.
4058             ArrayList<String> orderBefore = new ArrayList<String>(N);
4059             ArrayList<String> groupOverrideBefore = new ArrayList<>(N);
4060             int[] visibilities = new int[N];
4061             boolean[] showBadges = new boolean[N];
4062             for (int i = 0; i < N; i++) {
4063                 final NotificationRecord r = mNotificationList.get(i);
4064                 orderBefore.add(r.getKey());
4065                 groupOverrideBefore.add(r.sbn.getGroupKey());
4066                 visibilities[i] = r.getPackageVisibilityOverride();
4067                 showBadges[i] = r.canShowBadge();
4068                 mRankingHelper.extractSignals(r);
4069             }
4070             mRankingHelper.sort(mNotificationList);
4071             for (int i = 0; i < N; i++) {
4072                 final NotificationRecord r = mNotificationList.get(i);
4073                 if (forceUpdate
4074                         || !orderBefore.get(i).equals(r.getKey())
4075                         || visibilities[i] != r.getPackageVisibilityOverride()
4076                         || !groupOverrideBefore.get(i).equals(r.sbn.getGroupKey())
4077                         || showBadges[i] != r.canShowBadge()) {
4078                     scheduleSendRankingUpdate();
4079                     return;
4080                 }
4081             }
4082         }
4083     }
4084
4085     @GuardedBy("mNotificationLock")
4086     private void recordCallerLocked(NotificationRecord record) {
4087         if (mZenModeHelper.isCall(record)) {
4088             mZenModeHelper.recordCaller(record);
4089         }
4090     }
4091
4092     // let zen mode evaluate this record
4093     @GuardedBy("mNotificationLock")
4094     private void applyZenModeLocked(NotificationRecord record) {
4095         record.setIntercepted(mZenModeHelper.shouldIntercept(record));
4096         if (record.isIntercepted()) {
4097             int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
4098                     ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
4099                     | (mZenModeHelper.shouldSuppressWhenScreenOn()
4100                     ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
4101             record.setSuppressedVisualEffects(suppressed);
4102         } else {
4103             record.setSuppressedVisualEffects(0);
4104         }
4105     }
4106
4107     @GuardedBy("mNotificationLock")
4108     private int findNotificationRecordIndexLocked(NotificationRecord target) {
4109         return mRankingHelper.indexOf(mNotificationList, target);
4110     }
4111
4112     private void scheduleSendRankingUpdate() {
4113         if (!mHandler.hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
4114             Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE);
4115             mHandler.sendMessage(m);
4116         }
4117     }
4118
4119     private void handleSendRankingUpdate() {
4120         synchronized (mNotificationLock) {
4121             mListeners.notifyRankingUpdateLocked();
4122         }
4123     }
4124
4125     private void scheduleListenerHintsChanged(int state) {
4126         mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
4127         mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
4128     }
4129
4130     private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
4131         mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
4132         mHandler.obtainMessage(
4133                 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
4134                 listenerInterruptionFilter,
4135                 0).sendToTarget();
4136     }
4137
4138     private void handleListenerHintsChanged(int hints) {
4139         synchronized (mNotificationLock) {
4140             mListeners.notifyListenerHintsChangedLocked(hints);
4141         }
4142     }
4143
4144     private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
4145         synchronized (mNotificationLock) {
4146             mListeners.notifyInterruptionFilterChanged(interruptionFilter);
4147         }
4148     }
4149
4150     private final class WorkerHandler extends Handler
4151     {
4152         public WorkerHandler(Looper looper) {
4153             super(looper);
4154         }
4155
4156         @Override
4157         public void handleMessage(Message msg)
4158         {
4159             switch (msg.what)
4160             {
4161                 case MESSAGE_TIMEOUT:
4162                     handleTimeout((ToastRecord)msg.obj);
4163                     break;
4164                 case MESSAGE_SAVE_POLICY_FILE:
4165                     handleSavePolicyFile();
4166                     break;
4167                 case MESSAGE_SEND_RANKING_UPDATE:
4168                     handleSendRankingUpdate();
4169                     break;
4170                 case MESSAGE_LISTENER_HINTS_CHANGED:
4171                     handleListenerHintsChanged(msg.arg1);
4172                     break;
4173                 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
4174                     handleListenerInterruptionFilterChanged(msg.arg1);
4175                     break;
4176             }
4177         }
4178
4179     }
4180
4181     private final class RankingHandlerWorker extends Handler implements RankingHandler
4182     {
4183         public RankingHandlerWorker(Looper looper) {
4184             super(looper);
4185         }
4186
4187         @Override
4188         public void handleMessage(Message msg) {
4189             switch (msg.what) {
4190                 case MESSAGE_RECONSIDER_RANKING:
4191                     handleRankingReconsideration(msg);
4192                     break;
4193                 case MESSAGE_RANKING_SORT:
4194                     handleRankingSort(msg);
4195                     break;
4196             }
4197         }
4198
4199         public void requestSort(boolean forceUpdate) {
4200             removeMessages(MESSAGE_RANKING_SORT);
4201             Message msg = Message.obtain();
4202             msg.what = MESSAGE_RANKING_SORT;
4203             msg.obj = forceUpdate;
4204             sendMessage(msg);
4205         }
4206
4207         public void requestReconsideration(RankingReconsideration recon) {
4208             Message m = Message.obtain(this,
4209                     NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
4210             long delay = recon.getDelay(TimeUnit.MILLISECONDS);
4211             sendMessageDelayed(m, delay);
4212         }
4213     }
4214
4215     // Notifications
4216     // ============================================================================
4217     static int clamp(int x, int low, int high) {
4218         return (x < low) ? low : ((x > high) ? high : x);
4219     }
4220
4221     void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
4222         AccessibilityManager manager = AccessibilityManager.getInstance(getContext());
4223         if (!manager.isEnabled()) {
4224             return;
4225         }
4226
4227         AccessibilityEvent event =
4228             AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
4229         event.setPackageName(packageName);
4230         event.setClassName(Notification.class.getName());
4231         event.setParcelableData(notification);
4232         CharSequence tickerText = notification.tickerText;
4233         if (!TextUtils.isEmpty(tickerText)) {
4234             event.getText().add(tickerText);
4235         }
4236
4237         manager.sendAccessibilityEvent(event);
4238     }
4239
4240     /**
4241      * Removes all NotificationsRecords with the same key as the given notification record
4242      * from both lists. Do not call this method while iterating over either list.
4243      */
4244     @GuardedBy("mNotificationLock")
4245     private boolean removeFromNotificationListsLocked(NotificationRecord r) {
4246         // Remove from both lists, either list could have a separate Record for what is
4247         // effectively the same notification.
4248         boolean wasPosted = false;
4249         NotificationRecord recordInList = null;
4250         if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))
4251                 != null) {
4252             mNotificationList.remove(recordInList);
4253             mNotificationsByKey.remove(recordInList.sbn.getKey());
4254             wasPosted = true;
4255         }
4256         while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
4257                 != null) {
4258             mEnqueuedNotifications.remove(recordInList);
4259         }
4260         return wasPosted;
4261     }
4262
4263     @GuardedBy("mNotificationLock")
4264     private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
4265             boolean wasPosted) {
4266         final String canceledKey = r.getKey();
4267
4268         // Record caller.
4269         recordCallerLocked(r);
4270
4271         // tell the app
4272         if (sendDelete) {
4273             if (r.getNotification().deleteIntent != null) {
4274                 try {
4275                     r.getNotification().deleteIntent.send();
4276                 } catch (PendingIntent.CanceledException ex) {
4277                     // do nothing - there's no relevant way to recover, and
4278                     //     no reason to let this propagate
4279                     Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
4280                 }
4281             }
4282         }
4283
4284         // Only cancel these if this notification actually got to be posted.
4285         if (wasPosted) {
4286             // status bar
4287             if (r.getNotification().getSmallIcon() != null) {
4288                 if (reason != REASON_SNOOZED) {
4289                     r.isCanceled = true;
4290                 }
4291                 mListeners.notifyRemovedLocked(r.sbn, reason);
4292                 mHandler.post(new Runnable() {
4293                     @Override
4294                     public void run() {
4295                         mGroupHelper.onNotificationRemoved(r.sbn);
4296                     }
4297                 });
4298             }
4299
4300             // sound
4301             if (canceledKey.equals(mSoundNotificationKey)) {
4302                 mSoundNotificationKey = null;
4303                 final long identity = Binder.clearCallingIdentity();
4304                 try {
4305                     final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4306                     if (player != null) {
4307                         player.stopAsync();
4308                     }
4309                 } catch (RemoteException e) {
4310                 } finally {
4311                     Binder.restoreCallingIdentity(identity);
4312                 }
4313             }
4314
4315             // vibrate
4316             if (canceledKey.equals(mVibrateNotificationKey)) {
4317                 mVibrateNotificationKey = null;
4318                 long identity = Binder.clearCallingIdentity();
4319                 try {
4320                     mVibrator.cancel();
4321                 }
4322                 finally {
4323                     Binder.restoreCallingIdentity(identity);
4324                 }
4325             }
4326
4327             // light
4328             mLights.remove(canceledKey);
4329         }
4330
4331         // Record usage stats
4332         // TODO: add unbundling stats?
4333         switch (reason) {
4334             case REASON_CANCEL:
4335             case REASON_CANCEL_ALL:
4336             case REASON_LISTENER_CANCEL:
4337             case REASON_LISTENER_CANCEL_ALL:
4338                 mUsageStats.registerDismissedByUser(r);
4339                 break;
4340             case REASON_APP_CANCEL:
4341             case REASON_APP_CANCEL_ALL:
4342                 mUsageStats.registerRemovedByApp(r);
4343                 break;
4344         }
4345
4346         String groupKey = r.getGroupKey();
4347         NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
4348         if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
4349             mSummaryByGroupKey.remove(groupKey);
4350         }
4351         final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
4352         if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
4353             summaries.remove(r.sbn.getPackageName());
4354         }
4355
4356         // Save it for users of getHistoricalNotifications()
4357         mArchive.record(r.sbn);
4358
4359         final long now = System.currentTimeMillis();
4360         MetricsLogger.action(r.getLogMaker(now)
4361                 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
4362                 .setType(MetricsEvent.TYPE_DISMISS)
4363                 .setSubtype(reason));
4364         EventLogTags.writeNotificationCanceled(canceledKey, reason,
4365                 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
4366     }
4367
4368     /**
4369      * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
4370      * and none of the {@code mustNotHaveFlags}.
4371      */
4372     void cancelNotification(final int callingUid, final int callingPid,
4373             final String pkg, final String tag, final int id,
4374             final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
4375             final int userId, final int reason, final ManagedServiceInfo listener) {
4376         // In enqueueNotificationInternal notifications are added by scheduling the
4377         // work on the worker handler. Hence, we also schedule the cancel on this
4378         // handler to avoid a scenario where an add notification call followed by a
4379         // remove notification call ends up in not removing the notification.
4380         mHandler.post(new Runnable() {
4381             @Override
4382             public void run() {
4383                 String listenerName = listener == null ? null : listener.component.toShortString();
4384                 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
4385                         userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
4386
4387                 synchronized (mNotificationLock) {
4388                     // Look for the notification, searching both the posted and enqueued lists.
4389                     NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
4390                     if (r != null) {
4391                         // The notification was found, check if it should be removed.
4392
4393                         // Ideally we'd do this in the caller of this method. However, that would
4394                         // require the caller to also find the notification.
4395                         if (reason == REASON_CLICK) {
4396                             mUsageStats.registerClickedByUser(r);
4397                         }
4398
4399                         if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
4400                             return;
4401                         }
4402                         if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
4403                             return;
4404                         }
4405
4406                         // Cancel the notification.
4407                         boolean wasPosted = removeFromNotificationListsLocked(r);
4408                         cancelNotificationLocked(r, sendDelete, reason, wasPosted);
4409                         cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
4410                                 sendDelete);
4411                         updateLightsLocked();
4412                     } else {
4413                         // No notification was found, assume that it is snoozed and cancel it.
4414                         if (reason != REASON_SNOOZED) {
4415                             final boolean wasSnoozed = mSnoozeHelper.cancel(userId, pkg, tag, id);
4416                             if (wasSnoozed) {
4417                                 savePolicyFile();
4418                             }
4419                         }
4420                     }
4421                 }
4422             }
4423         });
4424     }
4425
4426     /**
4427      * Determine whether the userId applies to the notification in question, either because
4428      * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
4429      */
4430     private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
4431         return
4432                 // looking for USER_ALL notifications? match everything
4433                    userId == UserHandle.USER_ALL
4434                 // a notification sent to USER_ALL matches any query
4435                 || r.getUserId() == UserHandle.USER_ALL
4436                 // an exact user match
4437                 || r.getUserId() == userId;
4438     }
4439
4440     /**
4441      * Determine whether the userId applies to the notification in question, either because
4442      * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
4443      * because it matches one of the users profiles.
4444      */
4445     private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
4446         return notificationMatchesUserId(r, userId)
4447                 || mUserProfiles.isCurrentProfile(r.getUserId());
4448     }
4449
4450     /**
4451      * Cancels all notifications from a given package that have all of the
4452      * {@code mustHaveFlags}.
4453      */
4454     void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
4455             int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
4456             ManagedServiceInfo listener) {
4457         mHandler.post(new Runnable() {
4458             @Override
4459             public void run() {
4460                 String listenerName = listener == null ? null : listener.component.toShortString();
4461                 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
4462                         pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
4463                         listenerName);
4464
4465                 // Why does this parameter exist? Do we actually want to execute the above if doit
4466                 // is false?
4467                 if (!doit) {
4468                     return;
4469                 }
4470
4471                 synchronized (mNotificationLock) {
4472                     FlagChecker flagChecker = (int flags) -> {
4473                         if ((flags & mustHaveFlags) != mustHaveFlags) {
4474                             return false;
4475                         }
4476                         if ((flags & mustNotHaveFlags) != 0) {
4477                             return false;
4478                         }
4479                         return true;
4480                     };
4481
4482                     cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
4483                             pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
4484                             false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
4485                             listenerName, true /* wasPosted */);
4486                     cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
4487                             callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
4488                             flagChecker, false /*includeCurrentProfiles*/, userId,
4489                             false /*sendDelete*/, reason, listenerName, false /* wasPosted */);
4490                     mSnoozeHelper.cancel(userId, pkg);
4491                 }
4492             }
4493         });
4494     }
4495
4496     private interface FlagChecker {
4497         // Returns false if these flags do not pass the defined flag test.
4498         public boolean apply(int flags);
4499     }
4500
4501     @GuardedBy("mNotificationLock")
4502     private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
4503             int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
4504             String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
4505             boolean sendDelete, int reason, String listenerName, boolean wasPosted) {
4506         ArrayList<NotificationRecord> canceledNotifications = null;
4507         for (int i = notificationList.size() - 1; i >= 0; --i) {
4508             NotificationRecord r = notificationList.get(i);
4509             if (includeCurrentProfiles) {
4510                 if (!notificationMatchesCurrentProfiles(r, userId)) {
4511                     continue;
4512                 }
4513             } else if (!notificationMatchesUserId(r, userId)) {
4514                 continue;
4515             }
4516             // Don't remove notifications to all, if there's no package name specified
4517             if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
4518                 continue;
4519             }
4520             if (!flagChecker.apply(r.getFlags())) {
4521                 continue;
4522             }
4523             if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
4524                 continue;
4525             }
4526             if (channelId != null && !channelId.equals(r.getChannel().getId())) {
4527                 continue;
4528             }
4529
4530             if (canceledNotifications == null) {
4531                 canceledNotifications = new ArrayList<>();
4532             }
4533             notificationList.remove(i);
4534             mNotificationsByKey.remove(r.getKey());
4535             canceledNotifications.add(r);
4536             cancelNotificationLocked(r, sendDelete, reason, wasPosted);
4537         }
4538         if (canceledNotifications != null) {
4539             final int M = canceledNotifications.size();
4540             for (int i = 0; i < M; i++) {
4541                 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
4542                         listenerName, false /* sendDelete */);
4543             }
4544             updateLightsLocked();
4545         }
4546     }
4547
4548     void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
4549             ManagedServiceInfo listener) {
4550         String listenerName = listener == null ? null : listener.component.toShortString();
4551         if (duration <= 0 && snoozeCriterionId == null || key == null) {
4552             return;
4553         }
4554
4555         if (DBG) {
4556             Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
4557                     snoozeCriterionId, listenerName));
4558         }
4559         // Needs to post so that it can cancel notifications not yet enqueued.
4560         mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
4561     }
4562
4563     void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
4564         String listenerName = listener == null ? null : listener.component.toShortString();
4565         if (DBG) {
4566             Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
4567         }
4568         mSnoozeHelper.repost(key);
4569         savePolicyFile();
4570     }
4571
4572     @GuardedBy("mNotificationLock")
4573     void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
4574             ManagedServiceInfo listener, boolean includeCurrentProfiles) {
4575         mHandler.post(new Runnable() {
4576             @Override
4577             public void run() {
4578                 synchronized (mNotificationLock) {
4579                     String listenerName =
4580                             listener == null ? null : listener.component.toShortString();
4581                     EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
4582                             null, userId, 0, 0, reason, listenerName);
4583
4584                     FlagChecker flagChecker = (int flags) -> {
4585                         if ((flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR))
4586                                 != 0) {
4587                             return false;
4588                         }
4589                         return true;
4590                     };
4591
4592                     cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
4593                             null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
4594                             includeCurrentProfiles, userId, true /*sendDelete*/, reason,
4595                             listenerName, true);
4596                     cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
4597                             callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
4598                             flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
4599                             reason, listenerName, false);
4600                     mSnoozeHelper.cancel(userId, includeCurrentProfiles);
4601                 }
4602             }
4603         });
4604     }
4605
4606     // Warning: The caller is responsible for invoking updateLightsLocked().
4607     @GuardedBy("mNotificationLock")
4608     private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
4609             String listenerName, boolean sendDelete) {
4610         Notification n = r.getNotification();
4611         if (!n.isGroupSummary()) {
4612             return;
4613         }
4614
4615         String pkg = r.sbn.getPackageName();
4616
4617         if (pkg == null) {
4618             if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
4619             return;
4620         }
4621
4622         cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
4623                 sendDelete, true);
4624         cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
4625                 listenerName, sendDelete, false);
4626     }
4627
4628     @GuardedBy("mNotificationLock")
4629     private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
4630             NotificationRecord parentNotification, int callingUid, int callingPid,
4631             String listenerName, boolean sendDelete, boolean wasPosted) {
4632         final String pkg = parentNotification.sbn.getPackageName();
4633         final int userId = parentNotification.getUserId();
4634         final int reason = REASON_GROUP_SUMMARY_CANCELED;
4635         for (int i = notificationList.size() - 1; i >= 0; i--) {
4636             final NotificationRecord childR = notificationList.get(i);
4637             final StatusBarNotification childSbn = childR.sbn;
4638             if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
4639                     childR.getGroupKey().equals(parentNotification.getGroupKey())
4640                     && (childR.getFlags() & Notification.FLAG_FOREGROUND_SERVICE) == 0) {
4641                 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
4642                         childSbn.getTag(), userId, 0, 0, reason, listenerName);
4643                 notificationList.remove(i);
4644                 mNotificationsByKey.remove(childR.getKey());
4645                 cancelNotificationLocked(childR, sendDelete, reason, wasPosted);
4646             }
4647         }
4648     }
4649
4650     @GuardedBy("mNotificationLock")
4651     void updateLightsLocked()
4652     {
4653         // handle notification lights
4654         NotificationRecord ledNotification = null;
4655         while (ledNotification == null && !mLights.isEmpty()) {
4656             final String owner = mLights.get(mLights.size() - 1);
4657             ledNotification = mNotificationsByKey.get(owner);
4658             if (ledNotification == null) {
4659                 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
4660                 mLights.remove(owner);
4661             }
4662         }
4663
4664         // Don't flash while we are in a call or screen is on
4665         if (ledNotification == null || mInCall || mScreenOn) {
4666             mNotificationLight.turnOff();
4667         } else {
4668             NotificationRecord.Light light = ledNotification.getLight();
4669             if (light != null && mNotificationPulseEnabled) {
4670                 // pulse repeatedly
4671                 mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
4672                         light.onMs, light.offMs);
4673             }
4674         }
4675     }
4676
4677     @GuardedBy("mNotificationLock")
4678     @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
4679             String groupKey, int userId) {
4680         List<NotificationRecord> records = new ArrayList<>();
4681         records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
4682         records.addAll(
4683                 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
4684         return records;
4685     }
4686
4687
4688     @GuardedBy("mNotificationLock")
4689     private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
4690             ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
4691         List<NotificationRecord> records = new ArrayList<>();
4692         final int len = list.size();
4693         for (int i = 0; i < len; i++) {
4694             NotificationRecord r = list.get(i);
4695             if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey)
4696                     && r.sbn.getPackageName().equals(pkg)) {
4697                 records.add(r);
4698             }
4699         }
4700         return records;
4701     }
4702
4703     // Searches both enqueued and posted notifications by key.
4704     // TODO: need to combine a bunch of these getters with slightly different behavior.
4705     // TODO: Should enqueuing just add to mNotificationsByKey instead?
4706     @GuardedBy("mNotificationLock")
4707     private NotificationRecord findNotificationByKeyLocked(String key) {
4708         NotificationRecord r;
4709         if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
4710             return r;
4711         }
4712         if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
4713             return r;
4714         }
4715         return null;
4716     }
4717
4718     @GuardedBy("mNotificationLock")
4719     NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
4720         NotificationRecord r;
4721         if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
4722             return r;
4723         }
4724         if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
4725                 != null) {
4726             return r;
4727         }
4728         return null;
4729     }
4730
4731     @GuardedBy("mNotificationLock")
4732     private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
4733             String pkg, String tag, int id, int userId) {
4734         final int len = list.size();
4735         for (int i = 0; i < len; i++) {
4736             NotificationRecord r = list.get(i);
4737             if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
4738                     TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
4739                 return r;
4740             }
4741         }
4742         return null;
4743     }
4744
4745     @GuardedBy("mNotificationLock")
4746     private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
4747             String key) {
4748         final int N = list.size();
4749         for (int i = 0; i < N; i++) {
4750             if (key.equals(list.get(i).getKey())) {
4751                 return list.get(i);
4752             }
4753         }
4754         return null;
4755     }
4756
4757     @GuardedBy("mNotificationLock")
4758     int indexOfNotificationLocked(String key) {
4759         final int N = mNotificationList.size();
4760         for (int i = 0; i < N; i++) {
4761             if (key.equals(mNotificationList.get(i).getKey())) {
4762                 return i;
4763             }
4764         }
4765         return -1;
4766     }
4767
4768     private void updateNotificationPulse() {
4769         synchronized (mNotificationLock) {
4770             updateLightsLocked();
4771         }
4772     }
4773
4774     protected boolean isCallingUidSystem() {
4775         final int uid = Binder.getCallingUid();
4776         return uid == Process.SYSTEM_UID;
4777     }
4778
4779     protected boolean isUidSystemOrPhone(int uid) {
4780         final int appid = UserHandle.getAppId(uid);
4781         return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
4782     }
4783
4784     // TODO: Most calls should probably move to isCallerSystem.
4785     protected boolean isCallerSystemOrPhone() {
4786         return isUidSystemOrPhone(Binder.getCallingUid());
4787     }
4788
4789     private void checkCallerIsSystem() {
4790         if (isCallerSystemOrPhone()) {
4791             return;
4792         }
4793         throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
4794     }
4795
4796     private void checkCallerIsSystemOrSameApp(String pkg) {
4797         if (isCallerSystemOrPhone()) {
4798             return;
4799         }
4800         checkCallerIsSameApp(pkg);
4801     }
4802
4803     private boolean isCallerInstantApp(String pkg) {
4804         // System is always allowed to act for ephemeral apps.
4805         if (isCallerSystemOrPhone()) {
4806             return false;
4807         }
4808
4809         mAppOps.checkPackage(Binder.getCallingUid(), pkg);
4810
4811         try {
4812             ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0,
4813                     UserHandle.getCallingUserId());
4814             if (ai == null) {
4815                 throw new SecurityException("Unknown package " + pkg);
4816             }
4817             return ai.isInstantApp();
4818         } catch (RemoteException re) {
4819             throw new SecurityException("Unknown package " + pkg, re);
4820         }
4821
4822     }
4823
4824     private void checkCallerIsSameApp(String pkg) {
4825         final int uid = Binder.getCallingUid();
4826         try {
4827             ApplicationInfo ai = mPackageManager.getApplicationInfo(
4828                     pkg, 0, UserHandle.getCallingUserId());
4829             if (ai == null) {
4830                 throw new SecurityException("Unknown package " + pkg);
4831             }
4832             if (!UserHandle.isSameApp(ai.uid, uid)) {
4833                 throw new SecurityException("Calling uid " + uid + " gave package "
4834                         + pkg + " which is owned by uid " + ai.uid);
4835             }
4836         } catch (RemoteException re) {
4837             throw new SecurityException("Unknown package " + pkg + "\n" + re);
4838         }
4839     }
4840
4841     private static String callStateToString(int state) {
4842         switch (state) {
4843             case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
4844             case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
4845             case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
4846             default: return "CALL_STATE_UNKNOWN_" + state;
4847         }
4848     }
4849
4850     private void listenForCallState() {
4851         TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
4852             @Override
4853             public void onCallStateChanged(int state, String incomingNumber) {
4854                 if (mCallState == state) return;
4855                 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
4856                 mCallState = state;
4857             }
4858         }, PhoneStateListener.LISTEN_CALL_STATE);
4859     }
4860
4861     /**
4862      * Generates a NotificationRankingUpdate from 'sbns', considering only
4863      * notifications visible to the given listener.
4864      */
4865     @GuardedBy("mNotificationLock")
4866     private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
4867         final int N = mNotificationList.size();
4868         ArrayList<String> keys = new ArrayList<String>(N);
4869         ArrayList<String> interceptedKeys = new ArrayList<String>(N);
4870         ArrayList<Integer> importance = new ArrayList<>(N);
4871         Bundle overrideGroupKeys = new Bundle();
4872         Bundle visibilityOverrides = new Bundle();
4873         Bundle suppressedVisualEffects = new Bundle();
4874         Bundle explanation = new Bundle();
4875         Bundle channels = new Bundle();
4876         Bundle overridePeople = new Bundle();
4877         Bundle snoozeCriteria = new Bundle();
4878         Bundle showBadge = new Bundle();
4879         for (int i = 0; i < N; i++) {
4880             NotificationRecord record = mNotificationList.get(i);
4881             if (!isVisibleToListener(record.sbn, info)) {
4882                 continue;
4883             }
4884             final String key = record.sbn.getKey();
4885             keys.add(key);
4886             importance.add(record.getImportance());
4887             if (record.getImportanceExplanation() != null) {
4888                 explanation.putCharSequence(key, record.getImportanceExplanation());
4889             }
4890             if (record.isIntercepted()) {
4891                 interceptedKeys.add(key);
4892
4893             }
4894             suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
4895             if (record.getPackageVisibilityOverride()
4896                     != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
4897                 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
4898             }
4899             overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
4900             channels.putParcelable(key, record.getChannel());
4901             overridePeople.putStringArrayList(key, record.getPeopleOverride());
4902             snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria());
4903             showBadge.putBoolean(key, record.canShowBadge());
4904         }
4905         final int M = keys.size();
4906         String[] keysAr = keys.toArray(new String[M]);
4907         String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
4908         int[] importanceAr = new int[M];
4909         for (int i = 0; i < M; i++) {
4910             importanceAr[i] = importance.get(i);
4911         }
4912         return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
4913                 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
4914                 channels, overridePeople, snoozeCriteria, showBadge);
4915     }
4916
4917     boolean hasCompanionDevice(ManagedServiceInfo info) {
4918         if (mCompanionManager == null) {
4919             mCompanionManager = getCompanionManager();
4920         }
4921         // Companion mgr doesn't exist on all device types
4922         if (mCompanionManager == null) {
4923             return false;
4924         }
4925         long identity = Binder.clearCallingIdentity();
4926         try {
4927             List<String> associations = mCompanionManager.getAssociations(
4928                     info.component.getPackageName(), info.userid);
4929             if (!ArrayUtils.isEmpty(associations)) {
4930                 return true;
4931             }
4932         } catch (SecurityException se) {
4933             // Not a privileged listener
4934         } catch (RemoteException re) {
4935             Slog.e(TAG, "Cannot reach companion device service", re);
4936         } catch (Exception e) {
4937             Slog.e(TAG, "Cannot verify listener " + info, e);
4938         } finally {
4939             Binder.restoreCallingIdentity(identity);
4940         }
4941         return false;
4942     }
4943
4944     protected ICompanionDeviceManager getCompanionManager() {
4945         return ICompanionDeviceManager.Stub.asInterface(
4946                 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
4947     }
4948
4949     private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
4950         if (!listener.enabledAndUserMatches(sbn.getUserId())) {
4951             return false;
4952         }
4953         // TODO: remove this for older listeners.
4954         return true;
4955     }
4956
4957     private boolean isPackageSuspendedForUser(String pkg, int uid) {
4958         int userId = UserHandle.getUserId(uid);
4959         try {
4960             return mPackageManager.isPackageSuspendedForUser(pkg, userId);
4961         } catch (RemoteException re) {
4962             throw new SecurityException("Could not talk to package manager service");
4963         } catch (IllegalArgumentException ex) {
4964             // Package not found.
4965             return false;
4966         }
4967     }
4968
4969     private class TrimCache {
4970         StatusBarNotification heavy;
4971         StatusBarNotification sbnClone;
4972         StatusBarNotification sbnCloneLight;
4973
4974         TrimCache(StatusBarNotification sbn) {
4975             heavy = sbn;
4976         }
4977
4978         StatusBarNotification ForListener(ManagedServiceInfo info) {
4979             if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
4980                 if (sbnCloneLight == null) {
4981                     sbnCloneLight = heavy.cloneLight();
4982                 }
4983                 return sbnCloneLight;
4984             } else {
4985                 if (sbnClone == null) {
4986                     sbnClone = heavy.clone();
4987                 }
4988                 return sbnClone;
4989             }
4990         }
4991     }
4992
4993     public class NotificationAssistants extends ManagedServices {
4994
4995         public NotificationAssistants() {
4996             super(getContext(), mHandler, mNotificationLock, mUserProfiles);
4997         }
4998
4999         @Override
5000         protected Config getConfig() {
5001             Config c = new Config();
5002             c.caption = "notification assistant service";
5003             c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
5004             c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
5005             c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
5006             c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
5007             c.clientLabel = R.string.notification_ranker_binding_label;
5008             return c;
5009         }
5010
5011         @Override
5012         protected IInterface asInterface(IBinder binder) {
5013             return INotificationListener.Stub.asInterface(binder);
5014         }
5015
5016         @Override
5017         protected boolean checkType(IInterface service) {
5018             return service instanceof INotificationListener;
5019         }
5020
5021         @Override
5022         protected void onServiceAdded(ManagedServiceInfo info) {
5023             mListeners.registerGuestService(info);
5024         }
5025
5026         @Override
5027         @GuardedBy("mNotificationLock")
5028         protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
5029             mListeners.unregisterService(removed.service, removed.userid);
5030         }
5031
5032         public void onNotificationEnqueued(final NotificationRecord r) {
5033             final StatusBarNotification sbn = r.sbn;
5034             TrimCache trimCache = new TrimCache(sbn);
5035
5036             // There should be only one, but it's a list, so while we enforce
5037             // singularity elsewhere, we keep it general here, to avoid surprises.
5038             for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
5039                 boolean sbnVisible = isVisibleToListener(sbn, info);
5040                 if (!sbnVisible) {
5041                     continue;
5042                 }
5043
5044                 final int importance = r.getImportance();
5045                 final boolean fromUser = r.isImportanceFromUser();
5046                 final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
5047                 mHandler.post(new Runnable() {
5048                     @Override
5049                     public void run() {
5050                         notifyEnqueued(info, sbnToPost);
5051                     }
5052                 });
5053             }
5054         }
5055
5056         private void notifyEnqueued(final ManagedServiceInfo info,
5057                 final StatusBarNotification sbn) {
5058             final INotificationListener assistant = (INotificationListener) info.service;
5059             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5060             try {
5061                 assistant.onNotificationEnqueued(sbnHolder);
5062             } catch (RemoteException ex) {
5063                 Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
5064             }
5065         }
5066
5067         /**
5068          * asynchronously notify the assistant that a notification has been snoozed until a
5069          * context
5070          */
5071         @GuardedBy("mNotificationLock")
5072         public void notifyAssistantSnoozedLocked(final StatusBarNotification sbn,
5073                 final String snoozeCriterionId) {
5074             TrimCache trimCache = new TrimCache(sbn);
5075             for (final ManagedServiceInfo info : getServices()) {
5076                 final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
5077                 mHandler.post(new Runnable() {
5078                     @Override
5079                     public void run() {
5080                         final INotificationListener assistant =
5081                                 (INotificationListener) info.service;
5082                         StatusBarNotificationHolder sbnHolder
5083                                 = new StatusBarNotificationHolder(sbnToPost);
5084                         try {
5085                             assistant.onNotificationSnoozedUntilContext(
5086                                     sbnHolder, snoozeCriterionId);
5087                         } catch (RemoteException ex) {
5088                             Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
5089                         }
5090                     }
5091                 });
5092             }
5093         }
5094
5095         public boolean isEnabled() {
5096             return !getServices().isEmpty();
5097         }
5098     }
5099
5100     public class NotificationListeners extends ManagedServices {
5101
5102         private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
5103
5104         public NotificationListeners() {
5105             super(getContext(), mHandler, mNotificationLock, mUserProfiles);
5106         }
5107
5108         @Override
5109         protected Config getConfig() {
5110             Config c = new Config();
5111             c.caption = "notification listener";
5112             c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
5113             c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
5114             c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
5115             c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
5116             c.clientLabel = R.string.notification_listener_binding_label;
5117             return c;
5118         }
5119
5120         @Override
5121         protected IInterface asInterface(IBinder binder) {
5122             return INotificationListener.Stub.asInterface(binder);
5123         }
5124
5125         @Override
5126         protected boolean checkType(IInterface service) {
5127             return service instanceof INotificationListener;
5128         }
5129
5130         @Override
5131         public void onServiceAdded(ManagedServiceInfo info) {
5132             final INotificationListener listener = (INotificationListener) info.service;
5133             final NotificationRankingUpdate update;
5134             synchronized (mNotificationLock) {
5135                 update = makeRankingUpdateLocked(info);
5136             }
5137             try {
5138                 listener.onListenerConnected(update);
5139             } catch (RemoteException e) {
5140                 // we tried
5141             }
5142         }
5143
5144         @Override
5145         @GuardedBy("mNotificationLock")
5146         protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
5147             if (removeDisabledHints(removed)) {
5148                 updateListenerHintsLocked();
5149                 updateEffectsSuppressorLocked();
5150             }
5151             mLightTrimListeners.remove(removed);
5152         }
5153
5154         @GuardedBy("mNotificationLock")
5155         public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
5156             if (trim == TRIM_LIGHT) {
5157                 mLightTrimListeners.add(info);
5158             } else {
5159                 mLightTrimListeners.remove(info);
5160             }
5161         }
5162
5163         public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
5164             return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
5165         }
5166
5167         /**
5168          * asynchronously notify all listeners about a new notification
5169          *
5170          * <p>
5171          * Also takes care of removing a notification that has been visible to a listener before,
5172          * but isn't anymore.
5173          */
5174         @GuardedBy("mNotificationLock")
5175         public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
5176             // Lazily initialized snapshots of the notification.
5177             TrimCache trimCache = new TrimCache(sbn);
5178
5179             for (final ManagedServiceInfo info : getServices()) {
5180                 boolean sbnVisible = isVisibleToListener(sbn, info);
5181                 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
5182                 // This notification hasn't been and still isn't visible -> ignore.
5183                 if (!oldSbnVisible && !sbnVisible) {
5184                     continue;
5185                 }
5186                 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
5187
5188                 // This notification became invisible -> remove the old one.
5189                 if (oldSbnVisible && !sbnVisible) {
5190                     final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
5191                     mHandler.post(new Runnable() {
5192                         @Override
5193                         public void run() {
5194                             notifyRemoved(info, oldSbnLightClone, update, REASON_USER_STOPPED);
5195                         }
5196                     });
5197                     continue;
5198                 }
5199
5200                 final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
5201                 mHandler.post(new Runnable() {
5202                     @Override
5203                     public void run() {
5204                         notifyPosted(info, sbnToPost, update);
5205                     }
5206                 });
5207             }
5208         }
5209
5210         /**
5211          * asynchronously notify all listeners about a removed notification
5212          */
5213         @GuardedBy("mNotificationLock")
5214         public void notifyRemovedLocked(StatusBarNotification sbn, int reason) {
5215             // make a copy in case changes are made to the underlying Notification object
5216             // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
5217             // notification
5218             final StatusBarNotification sbnLight = sbn.cloneLight();
5219             for (final ManagedServiceInfo info : getServices()) {
5220                 if (!isVisibleToListener(sbn, info)) {
5221                     continue;
5222                 }
5223                 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
5224                 mHandler.post(new Runnable() {
5225                     @Override
5226                     public void run() {
5227                         notifyRemoved(info, sbnLight, update, reason);
5228                     }
5229                 });
5230             }
5231         }
5232
5233         /**
5234          * asynchronously notify all listeners about a reordering of notifications
5235          */
5236         @GuardedBy("mNotificationLock")
5237         public void notifyRankingUpdateLocked() {
5238             for (final ManagedServiceInfo serviceInfo : getServices()) {
5239                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5240                     continue;
5241                 }
5242                 final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
5243                 mHandler.post(new Runnable() {
5244                     @Override
5245                     public void run() {
5246                         notifyRankingUpdate(serviceInfo, update);
5247                     }
5248                 });
5249             }
5250         }
5251
5252         @GuardedBy("mNotificationLock")
5253         public void notifyListenerHintsChangedLocked(final int hints) {
5254             for (final ManagedServiceInfo serviceInfo : getServices()) {
5255                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5256                     continue;
5257                 }
5258                 mHandler.post(new Runnable() {
5259                     @Override
5260                     public void run() {
5261                         notifyListenerHintsChanged(serviceInfo, hints);
5262                     }
5263                 });
5264             }
5265         }
5266
5267         public void notifyInterruptionFilterChanged(final int interruptionFilter) {
5268             for (final ManagedServiceInfo serviceInfo : getServices()) {
5269                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5270                     continue;
5271                 }
5272                 mHandler.post(new Runnable() {
5273                     @Override
5274                     public void run() {
5275                         notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
5276                     }
5277                 });
5278             }
5279         }
5280
5281         protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user,
5282                 final NotificationChannel channel, final int modificationType) {
5283             if (channel == null) {
5284                 return;
5285             }
5286             for (final ManagedServiceInfo serviceInfo : getServices()) {
5287                 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
5288                     continue;
5289                 }
5290
5291                 mHandler.post(new Runnable() {
5292                     @Override
5293                     public void run() {
5294                         if (hasCompanionDevice(serviceInfo)) {
5295                             notifyNotificationChannelChanged(
5296                                     serviceInfo, pkg, user, channel, modificationType);
5297                         }
5298                     }
5299                 });
5300             }
5301         }
5302
5303         protected void notifyNotificationChannelGroupChanged(
5304                 final String pkg, final UserHandle user, final NotificationChannelGroup group,
5305                 final int modificationType) {
5306             if (group == null) {
5307                 return;
5308             }
5309             for (final ManagedServiceInfo serviceInfo : getServices()) {
5310                 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
5311                     continue;
5312                 }
5313
5314                 mHandler.post(new Runnable() {
5315                     @Override
5316                     public void run() {
5317                         if (hasCompanionDevice(serviceInfo)) {
5318                             notifyNotificationChannelGroupChanged(
5319                                     serviceInfo, pkg, user, group, modificationType);
5320                         }
5321                     }
5322                 });
5323             }
5324         }
5325
5326         private void notifyPosted(final ManagedServiceInfo info,
5327                 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
5328             final INotificationListener listener = (INotificationListener) info.service;
5329             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5330             try {
5331                 listener.onNotificationPosted(sbnHolder, rankingUpdate);
5332             } catch (RemoteException ex) {
5333                 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
5334             }
5335         }
5336
5337         private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
5338                 NotificationRankingUpdate rankingUpdate, int reason) {
5339             if (!info.enabledAndUserMatches(sbn.getUserId())) {
5340                 return;
5341             }
5342             final INotificationListener listener = (INotificationListener) info.service;
5343             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5344             try {
5345                 listener.onNotificationRemoved(sbnHolder, rankingUpdate, reason);
5346             } catch (RemoteException ex) {
5347                 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
5348             }
5349         }
5350
5351         private void notifyRankingUpdate(ManagedServiceInfo info,
5352                                          NotificationRankingUpdate rankingUpdate) {
5353             final INotificationListener listener = (INotificationListener) info.service;
5354             try {
5355                 listener.onNotificationRankingUpdate(rankingUpdate);
5356             } catch (RemoteException ex) {
5357                 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
5358             }
5359         }
5360
5361         private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
5362             final INotificationListener listener = (INotificationListener) info.service;
5363             try {
5364                 listener.onListenerHintsChanged(hints);
5365             } catch (RemoteException ex) {
5366                 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
5367             }
5368         }
5369
5370         private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
5371                 int interruptionFilter) {
5372             final INotificationListener listener = (INotificationListener) info.service;
5373             try {
5374                 listener.onInterruptionFilterChanged(interruptionFilter);
5375             } catch (RemoteException ex) {
5376                 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
5377             }
5378         }
5379
5380         void notifyNotificationChannelChanged(ManagedServiceInfo info,
5381                 final String pkg, final UserHandle user, final NotificationChannel channel,
5382                 final int modificationType) {
5383             final INotificationListener listener = (INotificationListener) info.service;
5384             try {
5385                 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
5386             } catch (RemoteException ex) {
5387                 Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
5388             }
5389         }
5390
5391         private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
5392                 final String pkg, final UserHandle user, final NotificationChannelGroup group,
5393                 final int modificationType) {
5394             final INotificationListener listener = (INotificationListener) info.service;
5395             try {
5396                 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
5397             } catch (RemoteException ex) {
5398                 Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
5399             }
5400         }
5401
5402         public boolean isListenerPackage(String packageName) {
5403             if (packageName == null) {
5404                 return false;
5405             }
5406             // TODO: clean up locking object later
5407             synchronized (mNotificationLock) {
5408                 for (final ManagedServiceInfo serviceInfo : getServices()) {
5409                     if (packageName.equals(serviceInfo.component.getPackageName())) {
5410                         return true;
5411                     }
5412                 }
5413             }
5414             return false;
5415         }
5416     }
5417
5418     public static final class DumpFilter {
5419         public boolean filtered = false;
5420         public String pkgFilter;
5421         public boolean zen;
5422         public long since;
5423         public boolean stats;
5424         public boolean redact = true;
5425         public boolean proto = false;
5426
5427         public static DumpFilter parseFromArguments(String[] args) {
5428             final DumpFilter filter = new DumpFilter();
5429             for (int ai = 0; ai < args.length; ai++) {
5430                 final String a = args[ai];
5431                 if ("--proto".equals(args[0])) {
5432                     filter.proto = true;
5433                 }
5434                 if ("--noredact".equals(a) || "--reveal".equals(a)) {
5435                     filter.redact = false;
5436                 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
5437                     if (ai < args.length-1) {
5438                         ai++;
5439                         filter.pkgFilter = args[ai].trim().toLowerCase();
5440                         if (filter.pkgFilter.isEmpty()) {
5441                             filter.pkgFilter = null;
5442                         } else {
5443                             filter.filtered = true;
5444                         }
5445                     }
5446                 } else if ("--zen".equals(a) || "zen".equals(a)) {
5447                     filter.filtered = true;
5448                     filter.zen = true;
5449                 } else if ("--stats".equals(a)) {
5450                     filter.stats = true;
5451                     if (ai < args.length-1) {
5452                         ai++;
5453                         filter.since = Long.parseLong(args[ai]);
5454                     } else {
5455                         filter.since = 0;
5456                     }
5457                 }
5458             }
5459             return filter;
5460         }
5461
5462         public boolean matches(StatusBarNotification sbn) {
5463             if (!filtered) return true;
5464             return zen ? true : sbn != null
5465                     && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
5466         }
5467
5468         public boolean matches(ComponentName component) {
5469             if (!filtered) return true;
5470             return zen ? true : component != null && matches(component.getPackageName());
5471         }
5472
5473         public boolean matches(String pkg) {
5474             if (!filtered) return true;
5475             return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
5476         }
5477
5478         @Override
5479         public String toString() {
5480             return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
5481         }
5482     }
5483
5484     /**
5485      * Wrapper for a StatusBarNotification object that allows transfer across a oneway
5486      * binder without sending large amounts of data over a oneway transaction.
5487      */
5488     private static final class StatusBarNotificationHolder
5489             extends IStatusBarNotificationHolder.Stub {
5490         private StatusBarNotification mValue;
5491
5492         public StatusBarNotificationHolder(StatusBarNotification value) {
5493             mValue = value;
5494         }
5495
5496         /** Get the held value and clear it. This function should only be called once per holder */
5497         @Override
5498         public StatusBarNotification get() {
5499             StatusBarNotification value = mValue;
5500             mValue = null;
5501             return value;
5502         }
5503     }
5504
5505     private final class PolicyAccess {
5506         private static final String SEPARATOR = ":";
5507         private final String[] PERM = {
5508             android.Manifest.permission.ACCESS_NOTIFICATION_POLICY
5509         };
5510
5511         public boolean isPackageGranted(String pkg) {
5512             return pkg != null && getGrantedPackages().contains(pkg);
5513         }
5514
5515         public void put(String pkg, boolean granted) {
5516             if (pkg == null) return;
5517             final ArraySet<String> pkgs = getGrantedPackages();
5518             boolean changed;
5519             if (granted) {
5520                 changed = pkgs.add(pkg);
5521             } else {
5522                 changed = pkgs.remove(pkg);
5523             }
5524             if (!changed) return;
5525             final String setting = TextUtils.join(SEPARATOR, pkgs);
5526             final int currentUser = ActivityManager.getCurrentUser();
5527             Settings.Secure.putStringForUser(getContext().getContentResolver(),
5528                     Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
5529                     setting,
5530                     currentUser);
5531             getContext().sendBroadcastAsUser(new Intent(NotificationManager
5532                     .ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
5533                 .setPackage(pkg)
5534                 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), new UserHandle(currentUser), null);
5535         }
5536
5537         public ArraySet<String> getGrantedPackages() {
5538             final ArraySet<String> pkgs = new ArraySet<>();
5539
5540             long identity = Binder.clearCallingIdentity();
5541             try {
5542                 final String setting = Settings.Secure.getStringForUser(
5543                         getContext().getContentResolver(),
5544                         Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
5545                         ActivityManager.getCurrentUser());
5546                 if (setting != null) {
5547                     final String[] tokens = setting.split(SEPARATOR);
5548                     for (int i = 0; i < tokens.length; i++) {
5549                         String token = tokens[i];
5550                         if (token != null) {
5551                             token = token.trim();
5552                         }
5553                         if (TextUtils.isEmpty(token)) {
5554                             continue;
5555                         }
5556                         pkgs.add(token);
5557                     }
5558                 }
5559             } finally {
5560                 Binder.restoreCallingIdentity(identity);
5561             }
5562             return pkgs;
5563         }
5564
5565         public String[] getRequestingPackages() throws RemoteException {
5566             final ParceledListSlice list = mPackageManager
5567                     .getPackagesHoldingPermissions(PERM, 0 /*flags*/,
5568                             ActivityManager.getCurrentUser());
5569             final List<PackageInfo> pkgs = list.getList();
5570             if (pkgs == null || pkgs.isEmpty()) return new String[0];
5571             final int N = pkgs.size();
5572             final String[] rt = new String[N];
5573             for (int i = 0; i < N; i++) {
5574                 rt[i] = pkgs.get(i).packageName;
5575             }
5576             return rt;
5577         }
5578     }
5579 }