OSDN Git Service

Clearing up invalid entries when SyncStorageEngine starts am: 271702fc28 am: 8b438236...
[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
1635             return mRankingHelper.getImportance(pkg, uid) != IMPORTANCE_NONE;
1636         }
1637
1638         @Override
1639         public int getPackageImportance(String pkg) {
1640             checkCallerIsSystemOrSameApp(pkg);
1641             return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
1642         }
1643
1644         @Override
1645         public boolean canShowBadge(String pkg, int uid) {
1646             checkCallerIsSystem();
1647             return mRankingHelper.canShowBadge(pkg, uid);
1648         }
1649
1650         @Override
1651         public void setShowBadge(String pkg, int uid, boolean showBadge) {
1652             checkCallerIsSystem();
1653             mRankingHelper.setShowBadge(pkg, uid, showBadge);
1654             savePolicyFile();
1655         }
1656
1657         @Override
1658         public void createNotificationChannelGroups(String pkg,
1659                 ParceledListSlice channelGroupList) throws RemoteException {
1660             checkCallerIsSystemOrSameApp(pkg);
1661             List<NotificationChannelGroup> groups = channelGroupList.getList();
1662             final int groupSize = groups.size();
1663             for (int i = 0; i < groupSize; i++) {
1664                 final NotificationChannelGroup group = groups.get(i);
1665                 Preconditions.checkNotNull(group, "group in list is null");
1666                 mRankingHelper.createNotificationChannelGroup(pkg, Binder.getCallingUid(), group,
1667                         true /* fromTargetApp */);
1668                 mListeners.notifyNotificationChannelGroupChanged(pkg,
1669                         UserHandle.of(UserHandle.getCallingUserId()), group,
1670                         NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1671             }
1672             savePolicyFile();
1673         }
1674
1675         private void createNotificationChannelsImpl(String pkg, int uid,
1676                 ParceledListSlice channelsList) {
1677             List<NotificationChannel> channels = channelsList.getList();
1678             final int channelsSize = channels.size();
1679             for (int i = 0; i < channelsSize; i++) {
1680                 final NotificationChannel channel = channels.get(i);
1681                 Preconditions.checkNotNull(channel, "channel in list is null");
1682                 mRankingHelper.createNotificationChannel(pkg, uid, channel,
1683                         true /* fromTargetApp */);
1684                 mListeners.notifyNotificationChannelChanged(pkg,
1685                         UserHandle.getUserHandleForUid(uid),
1686                         mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false),
1687                         NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1688             }
1689             savePolicyFile();
1690         }
1691
1692         @Override
1693         public void createNotificationChannels(String pkg,
1694                 ParceledListSlice channelsList) throws RemoteException {
1695             checkCallerIsSystemOrSameApp(pkg);
1696             createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList);
1697         }
1698
1699         @Override
1700         public void createNotificationChannelsForPackage(String pkg, int uid,
1701                 ParceledListSlice channelsList) throws RemoteException {
1702             checkCallerIsSystem();
1703             createNotificationChannelsImpl(pkg, uid, channelsList);
1704         }
1705
1706         @Override
1707         public NotificationChannel getNotificationChannel(String pkg, String channelId) {
1708             checkCallerIsSystemOrSameApp(pkg);
1709             return mRankingHelper.getNotificationChannel(
1710                     pkg, Binder.getCallingUid(), channelId, false /* includeDeleted */);
1711         }
1712
1713         @Override
1714         public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
1715                 String channelId, boolean includeDeleted) {
1716             checkCallerIsSystem();
1717             return mRankingHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted);
1718         }
1719
1720         @Override
1721         public void deleteNotificationChannel(String pkg, String channelId) {
1722             checkCallerIsSystemOrSameApp(pkg);
1723             final int callingUid = Binder.getCallingUid();
1724             if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
1725                 throw new IllegalArgumentException("Cannot delete default channel");
1726             }
1727             cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
1728                     UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
1729             mRankingHelper.deleteNotificationChannel(pkg, callingUid, channelId);
1730             mListeners.notifyNotificationChannelChanged(pkg,
1731                     UserHandle.getUserHandleForUid(callingUid),
1732                     mRankingHelper.getNotificationChannel(pkg, callingUid, channelId, true),
1733                     NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1734             savePolicyFile();
1735         }
1736
1737         @Override
1738         public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
1739                 String pkg) {
1740             checkCallerIsSystemOrSameApp(pkg);
1741             return new ParceledListSlice<>(new ArrayList(
1742                     mRankingHelper.getNotificationChannelGroups(pkg, Binder.getCallingUid())));
1743         }
1744
1745         @Override
1746         public void deleteNotificationChannelGroup(String pkg, String groupId) {
1747             checkCallerIsSystemOrSameApp(pkg);
1748
1749             final int callingUid = Binder.getCallingUid();
1750             NotificationChannelGroup groupToDelete =
1751                     mRankingHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
1752             if (groupToDelete != null) {
1753                 List<NotificationChannel> deletedChannels =
1754                         mRankingHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
1755                 for (int i = 0; i < deletedChannels.size(); i++) {
1756                     final NotificationChannel deletedChannel = deletedChannels.get(i);
1757                     cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
1758                             true,
1759                             UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
1760                             null);
1761                     mListeners.notifyNotificationChannelChanged(pkg,
1762                             UserHandle.getUserHandleForUid(callingUid),
1763                             deletedChannel,
1764                             NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1765                 }
1766                 mListeners.notifyNotificationChannelGroupChanged(
1767                         pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete,
1768                         NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1769                 savePolicyFile();
1770             }
1771         }
1772
1773         @Override
1774         public void updateNotificationChannelForPackage(String pkg, int uid,
1775                 NotificationChannel channel) {
1776             enforceSystemOrSystemUI("Caller not system or systemui");
1777             Preconditions.checkNotNull(channel);
1778             updateNotificationChannelInt(pkg, uid, channel, false);
1779         }
1780
1781         @Override
1782         public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
1783                 int uid, boolean includeDeleted) {
1784             enforceSystemOrSystemUI("getNotificationChannelsForPackage");
1785             return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted);
1786         }
1787
1788         @Override
1789         public int getNumNotificationChannelsForPackage(String pkg, int uid,
1790                 boolean includeDeleted) {
1791             enforceSystemOrSystemUI("getNumNotificationChannelsForPackage");
1792             return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted)
1793                     .getList().size();
1794         }
1795
1796         @Override
1797         public boolean onlyHasDefaultChannel(String pkg, int uid) {
1798             enforceSystemOrSystemUI("onlyHasDefaultChannel");
1799             return mRankingHelper.onlyHasDefaultChannel(pkg, uid);
1800         }
1801
1802         @Override
1803         public int getDeletedChannelCount(String pkg, int uid) {
1804             enforceSystemOrSystemUI("getDeletedChannelCount");
1805             return mRankingHelper.getDeletedChannelCount(pkg, uid);
1806         }
1807
1808         @Override
1809         public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
1810                 String pkg, int uid, boolean includeDeleted) {
1811             checkCallerIsSystem();
1812             return mRankingHelper.getNotificationChannelGroups(pkg, uid, includeDeleted);
1813         }
1814
1815         @Override
1816         public NotificationChannelGroup getNotificationChannelGroupForPackage(
1817                 String groupId, String pkg, int uid) {
1818             enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
1819             return mRankingHelper.getNotificationChannelGroup(groupId, pkg, uid);
1820         }
1821
1822         @Override
1823         public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
1824             checkCallerIsSystemOrSameApp(pkg);
1825             return mRankingHelper.getNotificationChannels(
1826                     pkg, Binder.getCallingUid(), false /* includeDeleted */);
1827         }
1828
1829         @Override
1830         public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
1831             checkCallerIsSystem();
1832
1833             // Cancel posted notifications
1834             cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true,
1835                     UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
1836
1837             // Listener & assistant
1838             mListeners.onPackagesChanged(true, new String[] {packageName});
1839             mNotificationAssistants.onPackagesChanged(true, new String[] {packageName});
1840
1841             // Zen
1842             mConditionProviders.onPackagesChanged(true, new String[] {packageName});
1843
1844             // Reset notification preferences
1845             if (!fromApp) {
1846                 mRankingHelper.onPackagesChanged(true, UserHandle.getCallingUserId(),
1847                         new String[]{packageName}, new int[]{uid});
1848             }
1849
1850             savePolicyFile();
1851         }
1852
1853
1854         /**
1855          * System-only API for getting a list of current (i.e. not cleared) notifications.
1856          *
1857          * Requires ACCESS_NOTIFICATIONS which is signature|system.
1858          * @returns A list of all the notifications, in natural order.
1859          */
1860         @Override
1861         public StatusBarNotification[] getActiveNotifications(String callingPkg) {
1862             // enforce() will ensure the calling uid has the correct permission
1863             getContext().enforceCallingOrSelfPermission(
1864                     android.Manifest.permission.ACCESS_NOTIFICATIONS,
1865                     "NotificationManagerService.getActiveNotifications");
1866
1867             StatusBarNotification[] tmp = null;
1868             int uid = Binder.getCallingUid();
1869
1870             // noteOp will check to make sure the callingPkg matches the uid
1871             if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1872                     == AppOpsManager.MODE_ALLOWED) {
1873                 synchronized (mNotificationLock) {
1874                     tmp = new StatusBarNotification[mNotificationList.size()];
1875                     final int N = mNotificationList.size();
1876                     for (int i=0; i<N; i++) {
1877                         tmp[i] = mNotificationList.get(i).sbn;
1878                     }
1879                 }
1880             }
1881             return tmp;
1882         }
1883
1884         /**
1885          * Public API for getting a list of current notifications for the calling package/uid.
1886          *
1887          * Note that since notification posting is done asynchronously, this will not return
1888          * notifications that are in the process of being posted.
1889          *
1890          * @returns A list of all the package's notifications, in natural order.
1891          */
1892         @Override
1893         public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
1894                 int incomingUserId) {
1895             checkCallerIsSystemOrSameApp(pkg);
1896             int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1897                     Binder.getCallingUid(), incomingUserId, true, false,
1898                     "getAppActiveNotifications", pkg);
1899             synchronized (mNotificationLock) {
1900                 final ArrayMap<String, StatusBarNotification> map
1901                         = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
1902                 final int N = mNotificationList.size();
1903                 for (int i = 0; i < N; i++) {
1904                     StatusBarNotification sbn = sanitizeSbn(pkg, userId,
1905                             mNotificationList.get(i).sbn);
1906                     if (sbn != null) {
1907                         map.put(sbn.getKey(), sbn);
1908                     }
1909                 }
1910                 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
1911                     StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn);
1912                     if (sbn != null) {
1913                         map.put(sbn.getKey(), sbn);
1914                     }
1915                 }
1916                 final int M = mEnqueuedNotifications.size();
1917                 for (int i = 0; i < M; i++) {
1918                     StatusBarNotification sbn = sanitizeSbn(pkg, userId,
1919                             mEnqueuedNotifications.get(i).sbn);
1920                     if (sbn != null) {
1921                         map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
1922                     }
1923                 }
1924                 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
1925                 list.addAll(map.values());
1926                 return new ParceledListSlice<StatusBarNotification>(list);
1927             }
1928         }
1929
1930         private StatusBarNotification sanitizeSbn(String pkg, int userId,
1931                 StatusBarNotification sbn) {
1932             if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId
1933                     && (sbn.getNotification().flags
1934                     & Notification.FLAG_AUTOGROUP_SUMMARY) == 0) {
1935                 // We could pass back a cloneLight() but clients might get confused and
1936                 // try to send this thing back to notify() again, which would not work
1937                 // very well.
1938                 return new StatusBarNotification(
1939                         sbn.getPackageName(),
1940                         sbn.getOpPkg(),
1941                         sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
1942                         sbn.getNotification().clone(),
1943                         sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
1944             }
1945             return null;
1946         }
1947
1948         /**
1949          * System-only API for getting a list of recent (cleared, no longer shown) notifications.
1950          *
1951          * Requires ACCESS_NOTIFICATIONS which is signature|system.
1952          */
1953         @Override
1954         public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
1955             // enforce() will ensure the calling uid has the correct permission
1956             getContext().enforceCallingOrSelfPermission(
1957                     android.Manifest.permission.ACCESS_NOTIFICATIONS,
1958                     "NotificationManagerService.getHistoricalNotifications");
1959
1960             StatusBarNotification[] tmp = null;
1961             int uid = Binder.getCallingUid();
1962
1963             // noteOp will check to make sure the callingPkg matches the uid
1964             if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1965                     == AppOpsManager.MODE_ALLOWED) {
1966                 synchronized (mArchive) {
1967                     tmp = mArchive.getArray(count);
1968                 }
1969             }
1970             return tmp;
1971         }
1972
1973         /**
1974          * Register a listener binder directly with the notification manager.
1975          *
1976          * Only works with system callers. Apps should extend
1977          * {@link android.service.notification.NotificationListenerService}.
1978          */
1979         @Override
1980         public void registerListener(final INotificationListener listener,
1981                 final ComponentName component, final int userid) {
1982             enforceSystemOrSystemUI("INotificationManager.registerListener");
1983             mListeners.registerService(listener, component, userid);
1984         }
1985
1986         /**
1987          * Remove a listener binder directly
1988          */
1989         @Override
1990         public void unregisterListener(INotificationListener token, int userid) {
1991             mListeners.unregisterService(token, userid);
1992         }
1993
1994         /**
1995          * Allow an INotificationListener to simulate a "clear all" operation.
1996          *
1997          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
1998          *
1999          * @param token The binder for the listener, to check that the caller is allowed
2000          */
2001         @Override
2002         public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
2003             final int callingUid = Binder.getCallingUid();
2004             final int callingPid = Binder.getCallingPid();
2005             long identity = Binder.clearCallingIdentity();
2006             try {
2007                 synchronized (mNotificationLock) {
2008                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2009                     if (keys != null) {
2010                         final int N = keys.length;
2011                         for (int i = 0; i < N; i++) {
2012                             NotificationRecord r = mNotificationsByKey.get(keys[i]);
2013                             if (r == null) continue;
2014                             final int userId = r.sbn.getUserId();
2015                             if (userId != info.userid && userId != UserHandle.USER_ALL &&
2016                                     !mUserProfiles.isCurrentProfile(userId)) {
2017                                 throw new SecurityException("Disallowed call from listener: "
2018                                         + info.service);
2019                             }
2020                             cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2021                                     r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
2022                                     userId);
2023                         }
2024                     } else {
2025                         cancelAllLocked(callingUid, callingPid, info.userid,
2026                                 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
2027                     }
2028                 }
2029             } finally {
2030                 Binder.restoreCallingIdentity(identity);
2031             }
2032         }
2033
2034         /**
2035          * Handle request from an approved listener to re-enable itself.
2036          *
2037          * @param component The componenet to be re-enabled, caller must match package.
2038          */
2039         @Override
2040         public void requestBindListener(ComponentName component) {
2041             checkCallerIsSystemOrSameApp(component.getPackageName());
2042             long identity = Binder.clearCallingIdentity();
2043             try {
2044                 ManagedServices manager =
2045                         mNotificationAssistants.isComponentEnabledForCurrentProfiles(component)
2046                         ? mNotificationAssistants
2047                         : mListeners;
2048                 manager.setComponentState(component, true);
2049             } finally {
2050                 Binder.restoreCallingIdentity(identity);
2051             }
2052         }
2053
2054         @Override
2055         public void requestUnbindListener(INotificationListener token) {
2056             long identity = Binder.clearCallingIdentity();
2057             try {
2058                 // allow bound services to disable themselves
2059                 synchronized (mNotificationLock) {
2060                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2061                     info.getOwner().setComponentState(info.component, false);
2062                 }
2063             } finally {
2064                 Binder.restoreCallingIdentity(identity);
2065             }
2066         }
2067
2068         @Override
2069         public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
2070             long identity = Binder.clearCallingIdentity();
2071             try {
2072                 synchronized (mNotificationLock) {
2073                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2074                     if (keys != null) {
2075                         final int N = keys.length;
2076                         for (int i = 0; i < N; i++) {
2077                             NotificationRecord r = mNotificationsByKey.get(keys[i]);
2078                             if (r == null) continue;
2079                             final int userId = r.sbn.getUserId();
2080                             if (userId != info.userid && userId != UserHandle.USER_ALL &&
2081                                     !mUserProfiles.isCurrentProfile(userId)) {
2082                                 throw new SecurityException("Disallowed call from listener: "
2083                                         + info.service);
2084                             }
2085                             if (!r.isSeen()) {
2086                                 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
2087                                 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
2088                                         userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM
2089                                                 : userId,
2090                                         UsageEvents.Event.USER_INTERACTION);
2091                                 r.setSeen();
2092                             }
2093                         }
2094                     }
2095                 }
2096             } finally {
2097                 Binder.restoreCallingIdentity(identity);
2098             }
2099         }
2100
2101         /**
2102          * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2103          *
2104          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2105          *
2106          * @param info The binder for the listener, to check that the caller is allowed
2107          */
2108         @GuardedBy("mNotificationLock")
2109         private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
2110                 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
2111             cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
2112                     Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
2113                     true,
2114                     userId, REASON_LISTENER_CANCEL, info);
2115         }
2116
2117         /**
2118          * Allow an INotificationListener to snooze a single notification until a context.
2119          *
2120          * @param token The binder for the listener, to check that the caller is allowed
2121          */
2122         @Override
2123         public void snoozeNotificationUntilContextFromListener(INotificationListener token,
2124                 String key, String snoozeCriterionId) {
2125             long identity = Binder.clearCallingIdentity();
2126             try {
2127                 synchronized (mNotificationLock) {
2128                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2129                     snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info);
2130                 }
2131             } finally {
2132                 Binder.restoreCallingIdentity(identity);
2133             }
2134         }
2135
2136         /**
2137          * Allow an INotificationListener to snooze a single notification until a time.
2138          *
2139          * @param token The binder for the listener, to check that the caller is allowed
2140          */
2141         @Override
2142         public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
2143                 long duration) {
2144             long identity = Binder.clearCallingIdentity();
2145             try {
2146                 synchronized (mNotificationLock) {
2147                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2148                     snoozeNotificationInt(key, duration, null, info);
2149                 }
2150             } finally {
2151                 Binder.restoreCallingIdentity(identity);
2152             }
2153         }
2154
2155         /**
2156          * Allows the notification assistant to un-snooze a single notification.
2157          *
2158          * @param token The binder for the assistant, to check that the caller is allowed
2159          */
2160         @Override
2161         public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
2162             long identity = Binder.clearCallingIdentity();
2163             try {
2164                 synchronized (mNotificationLock) {
2165                     final ManagedServiceInfo info =
2166                             mNotificationAssistants.checkServiceTokenLocked(token);
2167                     unsnoozeNotificationInt(key, info);
2168                 }
2169             } finally {
2170                 Binder.restoreCallingIdentity(identity);
2171             }
2172         }
2173
2174         /**
2175          * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2176          *
2177          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2178          *
2179          * @param token The binder for the listener, to check that the caller is allowed
2180          */
2181         @Override
2182         public void cancelNotificationFromListener(INotificationListener token, String pkg,
2183                 String tag, int id) {
2184             final int callingUid = Binder.getCallingUid();
2185             final int callingPid = Binder.getCallingPid();
2186             long identity = Binder.clearCallingIdentity();
2187             try {
2188                 synchronized (mNotificationLock) {
2189                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2190                     if (info.supportsProfiles()) {
2191                         Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
2192                                 + "from " + info.component
2193                                 + " use cancelNotification(key) instead.");
2194                     } else {
2195                         cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2196                                 pkg, tag, id, info.userid);
2197                     }
2198                 }
2199             } finally {
2200                 Binder.restoreCallingIdentity(identity);
2201             }
2202         }
2203
2204         /**
2205          * Allow an INotificationListener to request the list of outstanding notifications seen by
2206          * the current user. Useful when starting up, after which point the listener callbacks
2207          * should be used.
2208          *
2209          * @param token The binder for the listener, to check that the caller is allowed
2210          * @param keys An array of notification keys to fetch, or null to fetch everything
2211          * @returns The return value will contain the notifications specified in keys, in that
2212          *      order, or if keys is null, all the notifications, in natural order.
2213          */
2214         @Override
2215         public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
2216                 INotificationListener token, String[] keys, int trim) {
2217             synchronized (mNotificationLock) {
2218                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2219                 final boolean getKeys = keys != null;
2220                 final int N = getKeys ? keys.length : mNotificationList.size();
2221                 final ArrayList<StatusBarNotification> list
2222                         = new ArrayList<StatusBarNotification>(N);
2223                 for (int i=0; i<N; i++) {
2224                     final NotificationRecord r = getKeys
2225                             ? mNotificationsByKey.get(keys[i])
2226                             : mNotificationList.get(i);
2227                     if (r == null) continue;
2228                     StatusBarNotification sbn = r.sbn;
2229                     if (!isVisibleToListener(sbn, info)) continue;
2230                     StatusBarNotification sbnToSend =
2231                             (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2232                     list.add(sbnToSend);
2233                 }
2234                 return new ParceledListSlice<StatusBarNotification>(list);
2235             }
2236         }
2237
2238         /**
2239          * Allow an INotificationListener to request the list of outstanding snoozed notifications
2240          * seen by the current user. Useful when starting up, after which point the listener
2241          * callbacks should be used.
2242          *
2243          * @param token The binder for the listener, to check that the caller is allowed
2244          * @returns The return value will contain the notifications specified in keys, in that
2245          *      order, or if keys is null, all the notifications, in natural order.
2246          */
2247         @Override
2248         public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
2249                 INotificationListener token, int trim) {
2250             synchronized (mNotificationLock) {
2251                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2252                 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
2253                 final int N = snoozedRecords.size();
2254                 final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
2255                 for (int i=0; i < N; i++) {
2256                     final NotificationRecord r = snoozedRecords.get(i);
2257                     if (r == null) continue;
2258                     StatusBarNotification sbn = r.sbn;
2259                     if (!isVisibleToListener(sbn, info)) continue;
2260                     StatusBarNotification sbnToSend =
2261                             (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2262                     list.add(sbnToSend);
2263                 }
2264                 return new ParceledListSlice<>(list);
2265             }
2266         }
2267
2268         @Override
2269         public void requestHintsFromListener(INotificationListener token, int hints) {
2270             final long identity = Binder.clearCallingIdentity();
2271             try {
2272                 synchronized (mNotificationLock) {
2273                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2274                     final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
2275                             | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
2276                             | HINT_HOST_DISABLE_CALL_EFFECTS;
2277                     final boolean disableEffects = (hints & disableEffectsMask) != 0;
2278                     if (disableEffects) {
2279                         addDisabledHints(info, hints);
2280                     } else {
2281                         removeDisabledHints(info, hints);
2282                     }
2283                     updateListenerHintsLocked();
2284                     updateEffectsSuppressorLocked();
2285                 }
2286             } finally {
2287                 Binder.restoreCallingIdentity(identity);
2288             }
2289         }
2290
2291         @Override
2292         public int getHintsFromListener(INotificationListener token) {
2293             synchronized (mNotificationLock) {
2294                 return mListenerHints;
2295             }
2296         }
2297
2298         @Override
2299         public void requestInterruptionFilterFromListener(INotificationListener token,
2300                 int interruptionFilter) throws RemoteException {
2301             final long identity = Binder.clearCallingIdentity();
2302             try {
2303                 synchronized (mNotificationLock) {
2304                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2305                     mZenModeHelper.requestFromListener(info.component, interruptionFilter);
2306                     updateInterruptionFilterLocked();
2307                 }
2308             } finally {
2309                 Binder.restoreCallingIdentity(identity);
2310             }
2311         }
2312
2313         @Override
2314         public int getInterruptionFilterFromListener(INotificationListener token)
2315                 throws RemoteException {
2316             synchronized (mNotificationLight) {
2317                 return mInterruptionFilter;
2318             }
2319         }
2320
2321         @Override
2322         public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
2323                 throws RemoteException {
2324             synchronized (mNotificationLock) {
2325                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2326                 if (info == null) return;
2327                 mListeners.setOnNotificationPostedTrimLocked(info, trim);
2328             }
2329         }
2330
2331         @Override
2332         public int getZenMode() {
2333             return mZenModeHelper.getZenMode();
2334         }
2335
2336         @Override
2337         public ZenModeConfig getZenModeConfig() {
2338             enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
2339             return mZenModeHelper.getConfig();
2340         }
2341
2342         @Override
2343         public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
2344             enforceSystemOrSystemUI("INotificationManager.setZenMode");
2345             final long identity = Binder.clearCallingIdentity();
2346             try {
2347                 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
2348             } finally {
2349                 Binder.restoreCallingIdentity(identity);
2350             }
2351         }
2352
2353         @Override
2354         public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
2355             enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
2356             return mZenModeHelper.getZenRules();
2357         }
2358
2359         @Override
2360         public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
2361             Preconditions.checkNotNull(id, "Id is null");
2362             enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
2363             return mZenModeHelper.getAutomaticZenRule(id);
2364         }
2365
2366         @Override
2367         public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
2368                 throws RemoteException {
2369             Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2370             Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2371             Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2372             Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2373             enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
2374
2375             return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
2376                     "addAutomaticZenRule");
2377         }
2378
2379         @Override
2380         public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
2381                 throws RemoteException {
2382             Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2383             Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2384             Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2385             Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2386             enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
2387
2388             return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
2389                     "updateAutomaticZenRule");
2390         }
2391
2392         @Override
2393         public boolean removeAutomaticZenRule(String id) throws RemoteException {
2394             Preconditions.checkNotNull(id, "Id is null");
2395             // Verify that they can modify zen rules.
2396             enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
2397
2398             return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
2399         }
2400
2401         @Override
2402         public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
2403             Preconditions.checkNotNull(packageName, "Package name is null");
2404             enforceSystemOrSystemUI("removeAutomaticZenRules");
2405
2406             return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
2407         }
2408
2409         @Override
2410         public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
2411             Preconditions.checkNotNull(owner, "Owner is null");
2412             enforceSystemOrSystemUI("getRuleInstanceCount");
2413
2414             return mZenModeHelper.getCurrentInstanceCount(owner);
2415         }
2416
2417         @Override
2418         public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
2419             enforcePolicyAccess(pkg, "setInterruptionFilter");
2420             final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
2421             if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
2422             final long identity = Binder.clearCallingIdentity();
2423             try {
2424                 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
2425             } finally {
2426                 Binder.restoreCallingIdentity(identity);
2427             }
2428         }
2429
2430         @Override
2431         public void notifyConditions(final String pkg, IConditionProvider provider,
2432                 final Condition[] conditions) {
2433             final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2434             checkCallerIsSystemOrSameApp(pkg);
2435             mHandler.post(new Runnable() {
2436                 @Override
2437                 public void run() {
2438                     mConditionProviders.notifyConditions(pkg, info, conditions);
2439                 }
2440             });
2441         }
2442
2443         @Override
2444         public void requestUnbindProvider(IConditionProvider provider) {
2445             long identity = Binder.clearCallingIdentity();
2446             try {
2447                 // allow bound services to disable themselves
2448                 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2449                 info.getOwner().setComponentState(info.component, false);
2450             } finally {
2451                 Binder.restoreCallingIdentity(identity);
2452             }
2453         }
2454
2455         @Override
2456         public void requestBindProvider(ComponentName component) {
2457             checkCallerIsSystemOrSameApp(component.getPackageName());
2458             long identity = Binder.clearCallingIdentity();
2459             try {
2460                 mConditionProviders.setComponentState(component, true);
2461             } finally {
2462                 Binder.restoreCallingIdentity(identity);
2463             }
2464         }
2465
2466         private void enforceSystemOrSystemUI(String message) {
2467             if (isCallerSystemOrPhone()) return;
2468             getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
2469                     message);
2470         }
2471
2472         private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
2473             try {
2474                 checkCallerIsSystemOrSameApp(pkg);
2475             } catch (SecurityException e) {
2476                 getContext().enforceCallingPermission(
2477                         android.Manifest.permission.STATUS_BAR_SERVICE,
2478                         message);
2479             }
2480         }
2481
2482         private void enforcePolicyAccess(int uid, String method) {
2483             if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2484                     android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2485                 return;
2486             }
2487             boolean accessAllowed = false;
2488             String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
2489             final int packageCount = packages.length;
2490             for (int i = 0; i < packageCount; i++) {
2491                 if (checkPolicyAccess(packages[i])) {
2492                     accessAllowed = true;
2493                 }
2494             }
2495             if (!accessAllowed) {
2496                 Slog.w(TAG, "Notification policy access denied calling " + method);
2497                 throw new SecurityException("Notification policy access denied");
2498             }
2499         }
2500
2501         private void enforcePolicyAccess(String pkg, String method) {
2502             if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2503                     android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2504                 return;
2505             }
2506             checkCallerIsSameApp(pkg);
2507             if (!checkPolicyAccess(pkg)) {
2508                 Slog.w(TAG, "Notification policy access denied calling " + method);
2509                 throw new SecurityException("Notification policy access denied");
2510             }
2511         }
2512
2513         private boolean checkPackagePolicyAccess(String pkg) {
2514             return mPolicyAccess.isPackageGranted(pkg);
2515         }
2516
2517         private boolean checkPolicyAccess(String pkg) {
2518             try {
2519                 int uid = getContext().getPackageManager().getPackageUidAsUser(
2520                         pkg, UserHandle.getCallingUserId());
2521                 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
2522                         android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
2523                         -1, true)) {
2524                     return true;
2525                 }
2526             } catch (NameNotFoundException e) {
2527                 return false;
2528             }
2529             return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
2530         }
2531
2532         @Override
2533         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2534             if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
2535             final DumpFilter filter = DumpFilter.parseFromArguments(args);
2536             if (filter != null && filter.stats) {
2537                 dumpJson(pw, filter);
2538             } else if (filter != null && filter.proto) {
2539                 dumpProto(fd, filter);
2540             } else {
2541                 dumpImpl(pw, filter);
2542             }
2543         }
2544
2545         @Override
2546         public ComponentName getEffectsSuppressor() {
2547             return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
2548         }
2549
2550         @Override
2551         public boolean matchesCallFilter(Bundle extras) {
2552             enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
2553             return mZenModeHelper.matchesCallFilter(
2554                     Binder.getCallingUserHandle(),
2555                     extras,
2556                     mRankingHelper.findExtractor(ValidateNotificationPeople.class),
2557                     MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
2558                     MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
2559         }
2560
2561         @Override
2562         public boolean isSystemConditionProviderEnabled(String path) {
2563             enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
2564             return mConditionProviders.isSystemProviderEnabled(path);
2565         }
2566
2567         // Backup/restore interface
2568         @Override
2569         public byte[] getBackupPayload(int user) {
2570             if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
2571             //TODO: http://b/22388012
2572             if (user != UserHandle.USER_SYSTEM) {
2573                 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
2574                 return null;
2575             }
2576             synchronized(mPolicyFile) {
2577                 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
2578                 try {
2579                     writePolicyXml(baos, true /*forBackup*/);
2580                     return baos.toByteArray();
2581                 } catch (IOException e) {
2582                     Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
2583                 }
2584             }
2585             return null;
2586         }
2587
2588         @Override
2589         public void applyRestore(byte[] payload, int user) {
2590             if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
2591                     + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
2592             if (payload == null) {
2593                 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
2594                 return;
2595             }
2596             //TODO: http://b/22388012
2597             if (user != UserHandle.USER_SYSTEM) {
2598                 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
2599                 return;
2600             }
2601             synchronized(mPolicyFile) {
2602                 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
2603                 try {
2604                     readPolicyXml(bais, true /*forRestore*/);
2605                     savePolicyFile();
2606                 } catch (NumberFormatException | XmlPullParserException | IOException e) {
2607                     Slog.w(TAG, "applyRestore: error reading payload", e);
2608                 }
2609             }
2610         }
2611
2612         @Override
2613         public boolean isNotificationPolicyAccessGranted(String pkg) {
2614             return checkPolicyAccess(pkg);
2615         }
2616
2617         @Override
2618         public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
2619             enforceSystemOrSystemUIOrSamePackage(pkg,
2620                     "request policy access status for another package");
2621             return checkPolicyAccess(pkg);
2622         }
2623
2624         @Override
2625         public String[] getPackagesRequestingNotificationPolicyAccess()
2626                 throws RemoteException {
2627             enforceSystemOrSystemUI("request policy access packages");
2628             final long identity = Binder.clearCallingIdentity();
2629             try {
2630                 return mPolicyAccess.getRequestingPackages();
2631             } finally {
2632                 Binder.restoreCallingIdentity(identity);
2633             }
2634         }
2635
2636         @Override
2637         public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
2638                 throws RemoteException {
2639             enforceSystemOrSystemUI("grant notification policy access");
2640             final long identity = Binder.clearCallingIdentity();
2641             try {
2642                 synchronized (mNotificationLock) {
2643                     mPolicyAccess.put(pkg, granted);
2644                 }
2645             } finally {
2646                 Binder.restoreCallingIdentity(identity);
2647             }
2648         }
2649
2650         @Override
2651         public Policy getNotificationPolicy(String pkg) {
2652             enforcePolicyAccess(pkg, "getNotificationPolicy");
2653             final long identity = Binder.clearCallingIdentity();
2654             try {
2655                 return mZenModeHelper.getNotificationPolicy();
2656             } finally {
2657                 Binder.restoreCallingIdentity(identity);
2658             }
2659         }
2660
2661         @Override
2662         public void setNotificationPolicy(String pkg, Policy policy) {
2663             enforcePolicyAccess(pkg, "setNotificationPolicy");
2664             final long identity = Binder.clearCallingIdentity();
2665             try {
2666                 mZenModeHelper.setNotificationPolicy(policy);
2667             } finally {
2668                 Binder.restoreCallingIdentity(identity);
2669             }
2670         }
2671
2672         @Override
2673         public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
2674                 Adjustment adjustment) throws RemoteException {
2675             final long identity = Binder.clearCallingIdentity();
2676             try {
2677                 synchronized (mNotificationLock) {
2678                     mNotificationAssistants.checkServiceTokenLocked(token);
2679                     int N = mEnqueuedNotifications.size();
2680                     for (int i = 0; i < N; i++) {
2681                         final NotificationRecord n = mEnqueuedNotifications.get(i);
2682                         if (Objects.equals(adjustment.getKey(), n.getKey())
2683                                 && Objects.equals(adjustment.getUser(), n.getUserId())) {
2684                             applyAdjustment(n, adjustment);
2685                             break;
2686                         }
2687                     }
2688                 }
2689             } finally {
2690                 Binder.restoreCallingIdentity(identity);
2691             }
2692         }
2693
2694         @Override
2695         public void applyAdjustmentFromAssistant(INotificationListener token,
2696                 Adjustment adjustment) throws RemoteException {
2697             final long identity = Binder.clearCallingIdentity();
2698             try {
2699                 synchronized (mNotificationLock) {
2700                     mNotificationAssistants.checkServiceTokenLocked(token);
2701                     NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2702                     applyAdjustment(n, adjustment);
2703                 }
2704                 mRankingHandler.requestSort(true);
2705             } finally {
2706                 Binder.restoreCallingIdentity(identity);
2707             }
2708         }
2709
2710         @Override
2711         public void applyAdjustmentsFromAssistant(INotificationListener token,
2712                 List<Adjustment> adjustments) throws RemoteException {
2713
2714             final long identity = Binder.clearCallingIdentity();
2715             try {
2716                 synchronized (mNotificationLock) {
2717                     mNotificationAssistants.checkServiceTokenLocked(token);
2718                     for (Adjustment adjustment : adjustments) {
2719                         NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2720                         applyAdjustment(n, adjustment);
2721                     }
2722                 }
2723                 mRankingHandler.requestSort(true);
2724             } finally {
2725                 Binder.restoreCallingIdentity(identity);
2726             }
2727         }
2728
2729         @Override
2730         public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
2731                 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
2732             Preconditions.checkNotNull(channel);
2733             Preconditions.checkNotNull(pkg);
2734             Preconditions.checkNotNull(user);
2735
2736             verifyPrivilegedListener(token, user);
2737             updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
2738         }
2739
2740         @Override
2741         public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
2742                 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
2743             Preconditions.checkNotNull(pkg);
2744             Preconditions.checkNotNull(user);
2745             verifyPrivilegedListener(token, user);
2746
2747             return mRankingHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user),
2748                     false /* includeDeleted */);
2749         }
2750
2751         @Override
2752         public ParceledListSlice<NotificationChannelGroup>
2753                 getNotificationChannelGroupsFromPrivilegedListener(
2754                 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
2755             Preconditions.checkNotNull(pkg);
2756             Preconditions.checkNotNull(user);
2757             verifyPrivilegedListener(token, user);
2758
2759             List<NotificationChannelGroup> groups = new ArrayList<>();
2760             groups.addAll(mRankingHelper.getNotificationChannelGroups(
2761                     pkg, getUidForPackageAndUser(pkg, user)));
2762             return new ParceledListSlice<>(groups);
2763         }
2764
2765         private void verifyPrivilegedListener(INotificationListener token, UserHandle user) {
2766             ManagedServiceInfo info;
2767             synchronized (mNotificationLock) {
2768                 info = mListeners.checkServiceTokenLocked(token);
2769             }
2770             if (!hasCompanionDevice(info)) {
2771                 throw new SecurityException(info + " does not have access");
2772             }
2773             if (!info.enabledAndUserMatches(user.getIdentifier())) {
2774                 throw new SecurityException(info + " does not have access");
2775             }
2776         }
2777
2778         private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
2779             int uid = 0;
2780             long identity = Binder.clearCallingIdentity();
2781             try {
2782                 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
2783             } finally {
2784                 Binder.restoreCallingIdentity(identity);
2785             }
2786             return uid;
2787         }
2788     };
2789
2790     private void applyAdjustment(NotificationRecord n, Adjustment adjustment) {
2791         if (n == null) {
2792             return;
2793         }
2794         if (adjustment.getSignals() != null) {
2795             Bundle.setDefusable(adjustment.getSignals(), true);
2796             final ArrayList<String> people =
2797                     adjustment.getSignals().getStringArrayList(Adjustment.KEY_PEOPLE);
2798             final ArrayList<SnoozeCriterion> snoozeCriterionList =
2799                     adjustment.getSignals().getParcelableArrayList(Adjustment.KEY_SNOOZE_CRITERIA);
2800             n.setPeopleOverride(people);
2801             n.setSnoozeCriteria(snoozeCriterionList);
2802         }
2803     }
2804
2805     @GuardedBy("mNotificationLock")
2806     private void addAutogroupKeyLocked(String key) {
2807         NotificationRecord n = mNotificationsByKey.get(key);
2808         if (n == null) {
2809             return;
2810         }
2811         n.setOverrideGroupKey(GroupHelper.AUTOGROUP_KEY);
2812         EventLogTags.writeNotificationAutogrouped(key);
2813     }
2814
2815     @GuardedBy("mNotificationLock")
2816     private void removeAutogroupKeyLocked(String key) {
2817         NotificationRecord n = mNotificationsByKey.get(key);
2818         if (n == null) {
2819             return;
2820         }
2821         n.setOverrideGroupKey(null);
2822         EventLogTags.writeNotificationUnautogrouped(key);
2823     }
2824
2825     // Clears the 'fake' auto-group summary.
2826     @GuardedBy("mNotificationLock")
2827     private void clearAutogroupSummaryLocked(int userId, String pkg) {
2828         ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
2829         if (summaries != null && summaries.containsKey(pkg)) {
2830             // Clear summary.
2831             final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
2832             if (removed != null) {
2833                 boolean wasPosted = removeFromNotificationListsLocked(removed);
2834                 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED, wasPosted);
2835             }
2836         }
2837     }
2838
2839     // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
2840     private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
2841         NotificationRecord summaryRecord = null;
2842         synchronized (mNotificationLock) {
2843             NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
2844             if (notificationRecord == null) {
2845                 // The notification could have been cancelled again already. A successive
2846                 // adjustment will post a summary if needed.
2847                 return;
2848             }
2849             final StatusBarNotification adjustedSbn = notificationRecord.sbn;
2850             userId = adjustedSbn.getUser().getIdentifier();
2851             ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
2852             if (summaries == null) {
2853                 summaries = new ArrayMap<>();
2854             }
2855             mAutobundledSummaries.put(userId, summaries);
2856             if (!summaries.containsKey(pkg)) {
2857                 // Add summary
2858                 final ApplicationInfo appInfo =
2859                        adjustedSbn.getNotification().extras.getParcelable(
2860                                Notification.EXTRA_BUILDER_APPLICATION_INFO);
2861                 final Bundle extras = new Bundle();
2862                 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
2863                 final String channelId = notificationRecord.getChannel().getId();
2864                 final Notification summaryNotification =
2865                         new Notification.Builder(getContext(), channelId)
2866                                 .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
2867                                 .setGroupSummary(true)
2868                                 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN)
2869                                 .setGroup(GroupHelper.AUTOGROUP_KEY)
2870                                 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
2871                                 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
2872                                 .setColor(adjustedSbn.getNotification().color)
2873                                 .setLocalOnly(true)
2874                                 .build();
2875                 summaryNotification.extras.putAll(extras);
2876                 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
2877                 if (appIntent != null) {
2878                     summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
2879                             getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
2880                 }
2881                 final StatusBarNotification summarySbn =
2882                         new StatusBarNotification(adjustedSbn.getPackageName(),
2883                                 adjustedSbn.getOpPkg(),
2884                                 Integer.MAX_VALUE,
2885                                 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
2886                                 adjustedSbn.getInitialPid(), summaryNotification,
2887                                 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
2888                                 System.currentTimeMillis());
2889                 summaryRecord = new NotificationRecord(getContext(), summarySbn,
2890                         notificationRecord.getChannel());
2891                 summaries.put(pkg, summarySbn.getKey());
2892             }
2893         }
2894         if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
2895                 summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord)) {
2896             mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
2897         }
2898     }
2899
2900     private String disableNotificationEffects(NotificationRecord record) {
2901         if (mDisableNotificationEffects) {
2902             return "booleanState";
2903         }
2904         if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
2905             return "listenerHints";
2906         }
2907         if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
2908             return "callState";
2909         }
2910         return null;
2911     };
2912
2913     private void dumpJson(PrintWriter pw, DumpFilter filter) {
2914         JSONObject dump = new JSONObject();
2915         try {
2916             dump.put("service", "Notification Manager");
2917             dump.put("bans", mRankingHelper.dumpBansJson(filter));
2918             dump.put("ranking", mRankingHelper.dumpJson(filter));
2919             dump.put("stats", mUsageStats.dumpJson(filter));
2920             dump.put("channels", mRankingHelper.dumpChannelsJson(filter));
2921         } catch (JSONException e) {
2922             e.printStackTrace();
2923         }
2924         pw.println(dump);
2925     }
2926
2927     private void dumpProto(FileDescriptor fd, DumpFilter filter) {
2928         final ProtoOutputStream proto = new ProtoOutputStream(fd);
2929         synchronized (mNotificationLock) {
2930             long records = proto.start(NotificationServiceDumpProto.RECORDS);
2931             int N = mNotificationList.size();
2932             if (N > 0) {
2933                 for (int i = 0; i < N; i++) {
2934                     final NotificationRecord nr = mNotificationList.get(i);
2935                     if (filter.filtered && !filter.matches(nr.sbn)) continue;
2936                     nr.dump(proto, filter.redact);
2937                     proto.write(NotificationRecordProto.STATE, NotificationServiceProto.POSTED);
2938                 }
2939             }
2940             N = mEnqueuedNotifications.size();
2941             if (N > 0) {
2942                 for (int i = 0; i < N; i++) {
2943                     final NotificationRecord nr = mEnqueuedNotifications.get(i);
2944                     if (filter.filtered && !filter.matches(nr.sbn)) continue;
2945                     nr.dump(proto, filter.redact);
2946                     proto.write(NotificationRecordProto.STATE, NotificationServiceProto.ENQUEUED);
2947                 }
2948             }
2949             List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
2950             N = snoozed.size();
2951             if (N > 0) {
2952                 for (int i = 0; i < N; i++) {
2953                     final NotificationRecord nr = snoozed.get(i);
2954                     if (filter.filtered && !filter.matches(nr.sbn)) continue;
2955                     nr.dump(proto, filter.redact);
2956                     proto.write(NotificationRecordProto.STATE, NotificationServiceProto.SNOOZED);
2957                 }
2958             }
2959             proto.end(records);
2960         }
2961
2962         long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
2963         mZenModeHelper.dump(proto);
2964         for (ComponentName suppressor : mEffectsSuppressors) {
2965             proto.write(ZenModeProto.SUPPRESSORS, suppressor.toString());
2966         }
2967         proto.end(zenLog);
2968
2969         proto.flush();
2970     }
2971
2972     void dumpImpl(PrintWriter pw, DumpFilter filter) {
2973         pw.print("Current Notification Manager state");
2974         if (filter.filtered) {
2975             pw.print(" (filtered to "); pw.print(filter); pw.print(")");
2976         }
2977         pw.println(':');
2978         int N;
2979         final boolean zenOnly = filter.filtered && filter.zen;
2980
2981         if (!zenOnly) {
2982             synchronized (mToastQueue) {
2983                 N = mToastQueue.size();
2984                 if (N > 0) {
2985                     pw.println("  Toast Queue:");
2986                     for (int i=0; i<N; i++) {
2987                         mToastQueue.get(i).dump(pw, "    ", filter);
2988                     }
2989                     pw.println("  ");
2990                 }
2991             }
2992         }
2993
2994         synchronized (mNotificationLock) {
2995             if (!zenOnly) {
2996                 N = mNotificationList.size();
2997                 if (N > 0) {
2998                     pw.println("  Notification List:");
2999                     for (int i=0; i<N; i++) {
3000                         final NotificationRecord nr = mNotificationList.get(i);
3001                         if (filter.filtered && !filter.matches(nr.sbn)) continue;
3002                         nr.dump(pw, "    ", getContext(), filter.redact);
3003                     }
3004                     pw.println("  ");
3005                 }
3006
3007                 if (!filter.filtered) {
3008                     N = mLights.size();
3009                     if (N > 0) {
3010                         pw.println("  Lights List:");
3011                         for (int i=0; i<N; i++) {
3012                             if (i == N - 1) {
3013                                 pw.print("  > ");
3014                             } else {
3015                                 pw.print("    ");
3016                             }
3017                             pw.println(mLights.get(i));
3018                         }
3019                         pw.println("  ");
3020                     }
3021                     pw.println("  mUseAttentionLight=" + mUseAttentionLight);
3022                     pw.println("  mNotificationPulseEnabled=" + mNotificationPulseEnabled);
3023                     pw.println("  mSoundNotificationKey=" + mSoundNotificationKey);
3024                     pw.println("  mVibrateNotificationKey=" + mVibrateNotificationKey);
3025                     pw.println("  mDisableNotificationEffects=" + mDisableNotificationEffects);
3026                     pw.println("  mCallState=" + callStateToString(mCallState));
3027                     pw.println("  mSystemReady=" + mSystemReady);
3028                     pw.println("  mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
3029                 }
3030                 pw.println("  mArchive=" + mArchive.toString());
3031                 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
3032                 int j=0;
3033                 while (iter.hasNext()) {
3034                     final StatusBarNotification sbn = iter.next();
3035                     if (filter != null && !filter.matches(sbn)) continue;
3036                     pw.println("    " + sbn);
3037                     if (++j >= 5) {
3038                         if (iter.hasNext()) pw.println("    ...");
3039                         break;
3040                     }
3041                 }
3042
3043                 if (!zenOnly) {
3044                     N = mEnqueuedNotifications.size();
3045                     if (N > 0) {
3046                         pw.println("  Enqueued Notification List:");
3047                         for (int i = 0; i < N; i++) {
3048                             final NotificationRecord nr = mEnqueuedNotifications.get(i);
3049                             if (filter.filtered && !filter.matches(nr.sbn)) continue;
3050                             nr.dump(pw, "    ", getContext(), filter.redact);
3051                         }
3052                         pw.println("  ");
3053                     }
3054
3055                     mSnoozeHelper.dump(pw, filter);
3056                 }
3057             }
3058
3059             if (!zenOnly) {
3060                 pw.println("\n  Ranking Config:");
3061                 mRankingHelper.dump(pw, "    ", filter);
3062
3063                 pw.println("\n  Notification listeners:");
3064                 mListeners.dump(pw, filter);
3065                 pw.print("    mListenerHints: "); pw.println(mListenerHints);
3066                 pw.print("    mListenersDisablingEffects: (");
3067                 N = mListenersDisablingEffects.size();
3068                 for (int i = 0; i < N; i++) {
3069                     final int hint = mListenersDisablingEffects.keyAt(i);
3070                     if (i > 0) pw.print(';');
3071                     pw.print("hint[" + hint + "]:");
3072
3073                     final ArraySet<ManagedServiceInfo> listeners =
3074                             mListenersDisablingEffects.valueAt(i);
3075                     final int listenerSize = listeners.size();
3076
3077                     for (int j = 0; j < listenerSize; j++) {
3078                         if (i > 0) pw.print(',');
3079                         final ManagedServiceInfo listener = listeners.valueAt(i);
3080                         pw.print(listener.component);
3081                     }
3082                 }
3083                 pw.println(')');
3084                 pw.println("\n  Notification assistant services:");
3085                 mNotificationAssistants.dump(pw, filter);
3086             }
3087
3088             if (!filter.filtered || zenOnly) {
3089                 pw.println("\n  Zen Mode:");
3090                 pw.print("    mInterruptionFilter="); pw.println(mInterruptionFilter);
3091                 mZenModeHelper.dump(pw, "    ");
3092
3093                 pw.println("\n  Zen Log:");
3094                 ZenLog.dump(pw, "    ");
3095             }
3096
3097             pw.println("\n  Policy access:");
3098             pw.print("    mPolicyAccess: "); pw.println(mPolicyAccess);
3099
3100             pw.println("\n  Condition providers:");
3101             mConditionProviders.dump(pw, filter);
3102
3103             pw.println("\n  Group summaries:");
3104             for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
3105                 NotificationRecord r = entry.getValue();
3106                 pw.println("    " + entry.getKey() + " -> " + r.getKey());
3107                 if (mNotificationsByKey.get(r.getKey()) != r) {
3108                     pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
3109                     r.dump(pw, "      ", getContext(), filter.redact);
3110                 }
3111             }
3112
3113             if (!zenOnly) {
3114                 pw.println("\n  Usage Stats:");
3115                 mUsageStats.dump(pw, "    ", filter);
3116             }
3117         }
3118     }
3119
3120     /**
3121      * The private API only accessible to the system process.
3122      */
3123     private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
3124         @Override
3125         public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
3126                 String tag, int id, Notification notification, int userId) {
3127             enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
3128                     userId);
3129         }
3130
3131         @Override
3132         public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
3133                 int userId) {
3134             checkCallerIsSystem();
3135             mHandler.post(new Runnable() {
3136                 @Override
3137                 public void run() {
3138                     synchronized (mNotificationLock) {
3139                         removeForegroundServiceFlagByListLocked(
3140                                 mEnqueuedNotifications, pkg, notificationId, userId);
3141                         removeForegroundServiceFlagByListLocked(
3142                                 mNotificationList, pkg, notificationId, userId);
3143                     }
3144                 }
3145             });
3146         }
3147
3148         @GuardedBy("mNotificationLock")
3149         private void removeForegroundServiceFlagByListLocked(
3150                 ArrayList<NotificationRecord> notificationList, String pkg, int notificationId,
3151                 int userId) {
3152             NotificationRecord r = findNotificationByListLocked(
3153                     notificationList, pkg, null, notificationId, userId);
3154             if (r == null) {
3155                 return;
3156             }
3157             StatusBarNotification sbn = r.sbn;
3158             // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
3159             // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
3160             // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
3161             // initially *and* force remove FLAG_FOREGROUND_SERVICE.
3162             sbn.getNotification().flags =
3163                     (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
3164             mRankingHelper.sort(mNotificationList);
3165             mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
3166             mGroupHelper.onNotificationPosted(sbn);
3167         }
3168     };
3169
3170     void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
3171             final int callingPid, final String tag, final int id, final Notification notification,
3172             int incomingUserId) {
3173         if (DBG) {
3174             Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
3175                     + " notification=" + notification);
3176         }
3177         checkCallerIsSystemOrSameApp(pkg);
3178
3179         final int userId = ActivityManager.handleIncomingUser(callingPid,
3180                 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
3181         final UserHandle user = new UserHandle(userId);
3182
3183         if (pkg == null || notification == null) {
3184             throw new IllegalArgumentException("null not allowed: pkg=" + pkg
3185                     + " id=" + id + " notification=" + notification);
3186         }
3187
3188         // The system can post notifications for any package, let us resolve that.
3189         final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);
3190
3191         // Fix the notification as best we can.
3192         try {
3193             final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
3194                     pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
3195                     (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
3196             Notification.addFieldsFromContext(ai, notification);
3197         } catch (NameNotFoundException e) {
3198             Slog.e(TAG, "Cannot create a context for sending app", e);
3199             return;
3200         }
3201
3202         mUsageStats.registerEnqueuedByApp(pkg);
3203
3204         // setup local book-keeping
3205         String channelId = notification.getChannelId();
3206         if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
3207             channelId = (new Notification.TvExtender(notification)).getChannelId();
3208         }
3209         final NotificationChannel channel = mRankingHelper.getNotificationChannel(pkg,
3210                 notificationUid, channelId, false /* includeDeleted */);
3211         if (channel == null) {
3212             final String noChannelStr = "No Channel found for "
3213                     + "pkg=" + pkg
3214                     + ", channelId=" + channelId
3215                     + ", id=" + id
3216                     + ", tag=" + tag
3217                     + ", opPkg=" + opPkg
3218                     + ", callingUid=" + callingUid
3219                     + ", userId=" + userId
3220                     + ", incomingUserId=" + incomingUserId
3221                     + ", notificationUid=" + notificationUid
3222                     + ", notification=" + notification;
3223             Log.e(TAG, noChannelStr);
3224             doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
3225                     "Failed to post notification on channel \"" + channelId + "\"\n" +
3226                     "See log for more details");
3227             return;
3228         }
3229
3230         final StatusBarNotification n = new StatusBarNotification(
3231                 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
3232                 user, null, System.currentTimeMillis());
3233         final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
3234
3235         if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r)) {
3236             return;
3237         }
3238
3239         // Whitelist pending intents.
3240         if (notification.allPendingIntents != null) {
3241             final int intentCount = notification.allPendingIntents.size();
3242             if (intentCount > 0) {
3243                 final ActivityManagerInternal am = LocalServices
3244                         .getService(ActivityManagerInternal.class);
3245                 final long duration = LocalServices.getService(
3246                         DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
3247                 for (int i = 0; i < intentCount; i++) {
3248                     PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
3249                     if (pendingIntent != null) {
3250                         am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
3251                                 WHITELIST_TOKEN, duration);
3252                     }
3253                 }
3254             }
3255         }
3256
3257         mHandler.post(new EnqueueNotificationRunnable(userId, r));
3258     }
3259
3260     private void doChannelWarningToast(CharSequence toastText) {
3261         final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
3262         final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
3263                 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
3264         if (warningEnabled) {
3265             Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
3266                     Toast.LENGTH_SHORT);
3267             toast.show();
3268         }
3269     }
3270
3271     private int resolveNotificationUid(String opPackageName, int callingUid, int userId) {
3272         // The system can post notifications on behalf of any package it wants
3273         if (isCallerSystemOrPhone() && opPackageName != null && !"android".equals(opPackageName)) {
3274             try {
3275                 return getContext().getPackageManager()
3276                         .getPackageUidAsUser(opPackageName, userId);
3277             } catch (NameNotFoundException e) {
3278                 /* ignore */
3279             }
3280         }
3281         return callingUid;
3282     }
3283
3284     /**
3285      * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
3286      *
3287      * Has side effects.
3288      */
3289     private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag,
3290             NotificationRecord r) {
3291         final String pkg = r.sbn.getPackageName();
3292         final boolean isSystemNotification =
3293                 isUidSystemOrPhone(callingUid) || ("android".equals(pkg));
3294         final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
3295
3296         // Limit the number of notifications that any given package except the android
3297         // package or a registered listener can enqueue.  Prevents DOS attacks and deals with leaks.
3298         if (!isSystemNotification && !isNotificationFromListener) {
3299             synchronized (mNotificationLock) {
3300                 if (mNotificationsByKey.get(r.sbn.getKey()) != null) {
3301                     // this is an update, rate limit updates only
3302                     final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
3303                     if (appEnqueueRate > mMaxPackageEnqueueRate) {
3304                         mUsageStats.registerOverRateQuota(pkg);
3305                         final long now = SystemClock.elapsedRealtime();
3306                         if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
3307                             Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
3308                                     + ". Shedding events. package=" + pkg);
3309                             mLastOverRateLogTime = now;
3310                         }
3311                         return false;
3312                     }
3313                 } else if (isCallerInstantApp(pkg)) {
3314                     // Ephemeral apps have some special constraints for notifications.
3315                     // They are not allowed to create new notifications however they are allowed to
3316                     // update notifications created by the system (e.g. a foreground service
3317                     // notification).
3318                     throw new SecurityException("Instant app " + pkg
3319                             + " cannot create notifications");
3320                 }
3321
3322                 int count = 0;
3323                 final int N = mNotificationList.size();
3324                 for (int i=0; i<N; i++) {
3325                     final NotificationRecord existing = mNotificationList.get(i);
3326                     if (existing.sbn.getPackageName().equals(pkg)
3327                             && existing.sbn.getUserId() == userId) {
3328                         if (existing.sbn.getId() == id
3329                                 && TextUtils.equals(existing.sbn.getTag(), tag)) {
3330                             break;  // Allow updating existing notification
3331                         }
3332                         count++;
3333                         if (count >= MAX_PACKAGE_NOTIFICATIONS) {
3334                             mUsageStats.registerOverCountQuota(pkg);
3335                             Slog.e(TAG, "Package has already posted " + count
3336                                     + " notifications.  Not showing more.  package=" + pkg);
3337                             return false;
3338                         }
3339                     }
3340                 }
3341             }
3342         }
3343
3344         // snoozed apps
3345         if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
3346             MetricsLogger.action(r.getLogMaker()
3347                     .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
3348                     .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
3349             if (DBG) {
3350                 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
3351             }
3352             mSnoozeHelper.update(userId, r);
3353             savePolicyFile();
3354             return false;
3355         }
3356
3357
3358         // blocked apps
3359         if (isBlocked(r, mUsageStats)) {
3360             return false;
3361         }
3362
3363         return true;
3364     }
3365
3366     protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
3367         final String pkg = r.sbn.getPackageName();
3368         final int callingUid = r.sbn.getUid();
3369
3370         final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
3371         if (isPackageSuspended) {
3372             Slog.e(TAG, "Suppressing notification from package due to package "
3373                     + "suspended by administrator.");
3374             usageStats.registerSuspendedByAdmin(r);
3375             return isPackageSuspended;
3376         }
3377
3378         final boolean isBlocked =
3379                 mRankingHelper.getImportance(pkg, callingUid) == NotificationManager.IMPORTANCE_NONE
3380                 || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE;
3381         if (isBlocked) {
3382             Slog.e(TAG, "Suppressing notification from package by user request.");
3383             usageStats.registerBlocked(r);
3384         }
3385         return isBlocked;
3386     }
3387
3388     protected class SnoozeNotificationRunnable implements Runnable {
3389         private final String mKey;
3390         private final long mDuration;
3391         private final String mSnoozeCriterionId;
3392
3393         SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) {
3394             mKey = key;
3395             mDuration = duration;
3396             mSnoozeCriterionId = snoozeCriterionId;
3397         }
3398
3399         @Override
3400         public void run() {
3401             synchronized (mNotificationLock) {
3402                 final NotificationRecord r = findNotificationByKeyLocked(mKey);
3403                 if (r != null) {
3404                     snoozeLocked(r);
3405                 }
3406             }
3407         }
3408
3409         @GuardedBy("mNotificationLock")
3410         void snoozeLocked(NotificationRecord r) {
3411             if (r.sbn.isGroup()) {
3412                 final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked(
3413                         r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId());
3414                 if (r.getNotification().isGroupSummary()) {
3415                     // snooze summary and all children
3416                     for (int i = 0; i < groupNotifications.size(); i++) {
3417                         snoozeNotificationLocked(groupNotifications.get(i));
3418                     }
3419                 } else {
3420                     // if there is a valid summary for this group, and we are snoozing the only
3421                     // child, also snooze the summary
3422                     if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) {
3423                         if (groupNotifications.size() != 2) {
3424                             snoozeNotificationLocked(r);
3425                         } else {
3426                             // snooze summary and the one child
3427                             for (int i = 0; i < groupNotifications.size(); i++) {
3428                                 snoozeNotificationLocked(groupNotifications.get(i));
3429                             }
3430                         }
3431                     } else {
3432                         snoozeNotificationLocked(r);
3433                     }
3434                 }
3435             } else {
3436                 // just snooze the one notification
3437                 snoozeNotificationLocked(r);
3438             }
3439         }
3440
3441         @GuardedBy("mNotificationLock")
3442         void snoozeNotificationLocked(NotificationRecord r) {
3443             MetricsLogger.action(r.getLogMaker()
3444                     .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
3445                     .setType(MetricsEvent.TYPE_CLOSE)
3446                     .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
3447                             mSnoozeCriterionId == null ? 0 : 1));
3448             boolean wasPosted = removeFromNotificationListsLocked(r);
3449             cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted);
3450             updateLightsLocked();
3451             if (mSnoozeCriterionId != null) {
3452                 mNotificationAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
3453                 mSnoozeHelper.snooze(r);
3454             } else {
3455                 mSnoozeHelper.snooze(r, mDuration);
3456             }
3457             savePolicyFile();
3458         }
3459     }
3460
3461     protected class EnqueueNotificationRunnable implements Runnable {
3462         private final NotificationRecord r;
3463         private final int userId;
3464
3465         EnqueueNotificationRunnable(int userId, NotificationRecord r) {
3466             this.userId = userId;
3467             this.r = r;
3468         };
3469
3470         @Override
3471         public void run() {
3472             synchronized (mNotificationLock) {
3473                 mEnqueuedNotifications.add(r);
3474                 scheduleTimeoutLocked(r);
3475
3476                 final StatusBarNotification n = r.sbn;
3477                 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
3478                 NotificationRecord old = mNotificationsByKey.get(n.getKey());
3479                 if (old != null) {
3480                     // Retain ranking information from previous record
3481                     r.copyRankingInformation(old);
3482                 }
3483
3484                 final int callingUid = n.getUid();
3485                 final int callingPid = n.getInitialPid();
3486                 final Notification notification = n.getNotification();
3487                 final String pkg = n.getPackageName();
3488                 final int id = n.getId();
3489                 final String tag = n.getTag();
3490
3491                 // Handle grouped notifications and bail out early if we
3492                 // can to avoid extracting signals.
3493                 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
3494
3495                 // if this is a group child, unsnooze parent summary
3496                 if (n.isGroup() && notification.isGroupChild()) {
3497                     mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
3498                 }
3499
3500                 // This conditional is a dirty hack to limit the logging done on
3501                 //     behalf of the download manager without affecting other apps.
3502                 if (!pkg.equals("com.android.providers.downloads")
3503                         || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
3504                     int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
3505                     if (old != null) {
3506                         enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
3507                     }
3508                     EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
3509                             pkg, id, tag, userId, notification.toString(),
3510                             enqueueStatus);
3511                 }
3512
3513                 mRankingHelper.extractSignals(r);
3514
3515                 // tell the assistant service about the notification
3516                 if (mNotificationAssistants.isEnabled()) {
3517                     mNotificationAssistants.onNotificationEnqueued(r);
3518                     mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
3519                             DELAY_FOR_ASSISTANT_TIME);
3520                 } else {
3521                     mHandler.post(new PostNotificationRunnable(r.getKey()));
3522                 }
3523             }
3524         }
3525     }
3526
3527     protected class PostNotificationRunnable implements Runnable {
3528         private final String key;
3529
3530         PostNotificationRunnable(String key) {
3531             this.key = key;
3532         }
3533
3534         @Override
3535         public void run() {
3536             synchronized (mNotificationLock) {
3537                 try {
3538                     NotificationRecord r = null;
3539                     int N = mEnqueuedNotifications.size();
3540                     for (int i = 0; i < N; i++) {
3541                         final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
3542                         if (Objects.equals(key, enqueued.getKey())) {
3543                             r = enqueued;
3544                             break;
3545                         }
3546                     }
3547                     if (r == null) {
3548                         Slog.i(TAG, "Cannot find enqueued record for key: " + key);
3549                         return;
3550                     }
3551                     NotificationRecord old = mNotificationsByKey.get(key);
3552                     final StatusBarNotification n = r.sbn;
3553                     final Notification notification = n.getNotification();
3554                     int index = indexOfNotificationLocked(n.getKey());
3555                     if (index < 0) {
3556                         mNotificationList.add(r);
3557                         mUsageStats.registerPostedByApp(r);
3558                     } else {
3559                         old = mNotificationList.get(index);
3560                         mNotificationList.set(index, r);
3561                         mUsageStats.registerUpdatedByApp(r, old);
3562                         // Make sure we don't lose the foreground service state.
3563                         notification.flags |=
3564                                 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
3565                         r.isUpdate = true;
3566                     }
3567
3568                     mNotificationsByKey.put(n.getKey(), r);
3569
3570                     // Ensure if this is a foreground service that the proper additional
3571                     // flags are set.
3572                     if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
3573                         notification.flags |= Notification.FLAG_ONGOING_EVENT
3574                                 | Notification.FLAG_NO_CLEAR;
3575                     }
3576
3577                     applyZenModeLocked(r);
3578                     mRankingHelper.sort(mNotificationList);
3579
3580                     if (notification.getSmallIcon() != null) {
3581                         StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
3582                         mListeners.notifyPostedLocked(n, oldSbn);
3583                         mHandler.post(new Runnable() {
3584                             @Override
3585                             public void run() {
3586                                 mGroupHelper.onNotificationPosted(n);
3587                             }
3588                         });
3589                     } else {
3590                         Slog.e(TAG, "Not posting notification without small icon: " + notification);
3591                         if (old != null && !old.isCanceled) {
3592                             mListeners.notifyRemovedLocked(n,
3593                                     NotificationListenerService.REASON_ERROR);
3594                             mHandler.post(new Runnable() {
3595                                 @Override
3596                                 public void run() {
3597                                     mGroupHelper.onNotificationRemoved(n);
3598                                 }
3599                             });
3600                         }
3601                         // ATTENTION: in a future release we will bail out here
3602                         // so that we do not play sounds, show lights, etc. for invalid
3603                         // notifications
3604                         Slog.e(TAG, "WARNING: In a future release this will crash the app: "
3605                                 + n.getPackageName());
3606                     }
3607
3608                     buzzBeepBlinkLocked(r);
3609                 } finally {
3610                     int N = mEnqueuedNotifications.size();
3611                     for (int i = 0; i < N; i++) {
3612                         final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
3613                         if (Objects.equals(key, enqueued.getKey())) {
3614                             mEnqueuedNotifications.remove(i);
3615                             break;
3616                         }
3617                     }
3618                 }
3619             }
3620         }
3621     }
3622
3623     /**
3624      * Ensures that grouped notification receive their special treatment.
3625      *
3626      * <p>Cancels group children if the new notification causes a group to lose
3627      * its summary.</p>
3628      *
3629      * <p>Updates mSummaryByGroupKey.</p>
3630      */
3631     @GuardedBy("mNotificationLock")
3632     private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
3633             int callingUid, int callingPid) {
3634         StatusBarNotification sbn = r.sbn;
3635         Notification n = sbn.getNotification();
3636         if (n.isGroupSummary() && !sbn.isAppGroup())  {
3637             // notifications without a group shouldn't be a summary, otherwise autobundling can
3638             // lead to bugs
3639             n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
3640         }
3641
3642         String group = sbn.getGroupKey();
3643         boolean isSummary = n.isGroupSummary();
3644
3645         Notification oldN = old != null ? old.sbn.getNotification() : null;
3646         String oldGroup = old != null ? old.sbn.getGroupKey() : null;
3647         boolean oldIsSummary = old != null && oldN.isGroupSummary();
3648
3649         if (oldIsSummary) {
3650             NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
3651             if (removedSummary != old) {
3652                 String removedKey =
3653                         removedSummary != null ? removedSummary.getKey() : "<null>";
3654                 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
3655                         ", removed=" + removedKey);
3656             }
3657         }
3658         if (isSummary) {
3659             mSummaryByGroupKey.put(group, r);
3660         }
3661
3662         // Clear out group children of the old notification if the update
3663         // causes the group summary to go away. This happens when the old
3664         // notification was a summary and the new one isn't, or when the old
3665         // notification was a summary and its group key changed.
3666         if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
3667             cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */);
3668         }
3669     }
3670
3671     @VisibleForTesting
3672     @GuardedBy("mNotificationLock")
3673     void scheduleTimeoutLocked(NotificationRecord record) {
3674         if (record.getNotification().getTimeoutAfter() > 0) {
3675             final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
3676                     REQUEST_CODE_TIMEOUT,
3677                     new Intent(ACTION_NOTIFICATION_TIMEOUT)
3678                             .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
3679                                     .appendPath(record.getKey()).build())
3680                             .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
3681                             .putExtra(EXTRA_KEY, record.getKey()),
3682                     PendingIntent.FLAG_UPDATE_CURRENT);
3683             mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
3684                     SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
3685         }
3686     }
3687
3688     @VisibleForTesting
3689     @GuardedBy("mNotificationLock")
3690     void buzzBeepBlinkLocked(NotificationRecord record) {
3691         boolean buzz = false;
3692         boolean beep = false;
3693         boolean blink = false;
3694
3695         final Notification notification = record.sbn.getNotification();
3696         final String key = record.getKey();
3697
3698         // Should this notification make noise, vibe, or use the LED?
3699         final boolean aboveThreshold =
3700                 record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
3701         final boolean canInterrupt = aboveThreshold && !record.isIntercepted();
3702         if (DBG)
3703             Slog.v(TAG,
3704                     "pkg=" + record.sbn.getPackageName() + " canInterrupt=" + canInterrupt +
3705                             " intercept=" + record.isIntercepted()
3706             );
3707
3708         // If we're not supposed to beep, vibrate, etc. then don't.
3709         final String disableEffects = disableNotificationEffects(record);
3710         if (disableEffects != null) {
3711             ZenLog.traceDisableEffects(record, disableEffects);
3712         }
3713
3714         // Remember if this notification already owns the notification channels.
3715         boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
3716         boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
3717         // These are set inside the conditional if the notification is allowed to make noise.
3718         boolean hasValidVibrate = false;
3719         boolean hasValidSound = false;
3720
3721         if (isNotificationForCurrentUser(record)) {
3722             // If the notification will appear in the status bar, it should send an accessibility
3723             // event
3724             if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) {
3725                 sendAccessibilityEvent(notification, record.sbn.getPackageName());
3726             }
3727
3728             if (disableEffects == null
3729                     && canInterrupt
3730                     && mSystemReady
3731                     && mAudioManager != null) {
3732                 if (DBG) Slog.v(TAG, "Interrupting!");
3733                 Uri soundUri = record.getSound();
3734                 hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
3735                 long[] vibration = record.getVibration();
3736                 // Demote sound to vibration if vibration missing & phone in vibration mode.
3737                 if (vibration == null
3738                         && hasValidSound
3739                         && (mAudioManager.getRingerModeInternal()
3740                         == AudioManager.RINGER_MODE_VIBRATE)) {
3741                     vibration = mFallbackVibrationPattern;
3742                 }
3743                 hasValidVibrate = vibration != null;
3744
3745                 if (!shouldMuteNotificationLocked(record)) {
3746                     if (hasValidSound) {
3747                         mSoundNotificationKey = key;
3748                         if (mInCall) {
3749                             playInCallNotification();
3750                             beep = true;
3751                         } else {
3752                             beep = playSound(record, soundUri);
3753                         }
3754                     }
3755
3756                     final boolean ringerModeSilent =
3757                             mAudioManager.getRingerModeInternal()
3758                                     == AudioManager.RINGER_MODE_SILENT;
3759                     if (!mInCall && hasValidVibrate && !ringerModeSilent) {
3760                         mVibrateNotificationKey = key;
3761
3762                         buzz = playVibration(record, vibration, hasValidSound);
3763                     }
3764                 }
3765             }
3766         }
3767         // If a notification is updated to remove the actively playing sound or vibrate,
3768         // cancel that feedback now
3769         if (wasBeep && !hasValidSound) {
3770             clearSoundLocked();
3771         }
3772         if (wasBuzz && !hasValidVibrate) {
3773             clearVibrateLocked();
3774         }
3775
3776         // light
3777         // release the light
3778         boolean wasShowLights = mLights.remove(key);
3779         if (record.getLight() != null && aboveThreshold
3780                 && ((record.getSuppressedVisualEffects()
3781                 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
3782             mLights.add(key);
3783             updateLightsLocked();
3784             if (mUseAttentionLight) {
3785                 mAttentionLight.pulse();
3786             }
3787             blink = true;
3788         } else if (wasShowLights) {
3789             updateLightsLocked();
3790         }
3791         if (buzz || beep || blink) {
3792             MetricsLogger.action(record.getLogMaker()
3793                     .setCategory(MetricsEvent.NOTIFICATION_ALERT)
3794                     .setType(MetricsEvent.TYPE_OPEN)
3795                     .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
3796             EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
3797         }
3798     }
3799
3800     @GuardedBy("mNotificationLock")
3801     boolean shouldMuteNotificationLocked(final NotificationRecord record) {
3802         final Notification notification = record.getNotification();
3803         if(record.isUpdate
3804                 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
3805             return true;
3806         }
3807         if (record.sbn.isGroup()) {
3808             return notification.suppressAlertingDueToGrouping();
3809         }
3810         return false;
3811     }
3812
3813     private boolean playSound(final NotificationRecord record, Uri soundUri) {
3814         boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
3815         // do not play notifications if there is a user of exclusive audio focus
3816         // or the device is in vibrate mode
3817         if (!mAudioManager.isAudioFocusExclusive() && mAudioManager.getRingerModeInternal()
3818                 != AudioManager.RINGER_MODE_VIBRATE) {
3819             final long identity = Binder.clearCallingIdentity();
3820             try {
3821                 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
3822                 if (player != null) {
3823                     if (DBG) Slog.v(TAG, "Playing sound " + soundUri
3824                             + " with attributes " + record.getAudioAttributes());
3825                     player.playAsync(soundUri, record.sbn.getUser(), looping,
3826                             record.getAudioAttributes());
3827                     return true;
3828                 }
3829             } catch (RemoteException e) {
3830             } finally {
3831                 Binder.restoreCallingIdentity(identity);
3832             }
3833         }
3834         return false;
3835     }
3836
3837     private boolean playVibration(final NotificationRecord record, long[] vibration,
3838             boolean delayVibForSound) {
3839         // Escalate privileges so we can use the vibrator even if the
3840         // notifying app does not have the VIBRATE permission.
3841         long identity = Binder.clearCallingIdentity();
3842         try {
3843             final VibrationEffect effect;
3844             try {
3845                 final boolean insistent =
3846                         (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
3847                 effect = VibrationEffect.createWaveform(
3848                         vibration, insistent ? 0 : -1 /*repeatIndex*/);
3849             } catch (IllegalArgumentException e) {
3850                 Slog.e(TAG, "Error creating vibration waveform with pattern: " +
3851                         Arrays.toString(vibration));
3852                 return false;
3853             }
3854             if (delayVibForSound) {
3855                 new Thread(() -> {
3856                     // delay the vibration by the same amount as the notification sound
3857                     final int waitMs = mAudioManager.getFocusRampTimeMs(
3858                             AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
3859                             record.getAudioAttributes());
3860                     if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms");
3861                     try {
3862                         Thread.sleep(waitMs);
3863                     } catch (InterruptedException e) { }
3864                     mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
3865                             effect, record.getAudioAttributes());
3866                 }).start();
3867             } else {
3868                 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
3869                         effect, record.getAudioAttributes());
3870             }
3871             return true;
3872         } finally{
3873             Binder.restoreCallingIdentity(identity);
3874         }
3875     }
3876
3877     private boolean isNotificationForCurrentUser(NotificationRecord record) {
3878         final int currentUser;
3879         final long token = Binder.clearCallingIdentity();
3880         try {
3881             currentUser = ActivityManager.getCurrentUser();
3882         } finally {
3883             Binder.restoreCallingIdentity(token);
3884         }
3885         return (record.getUserId() == UserHandle.USER_ALL ||
3886                 record.getUserId() == currentUser ||
3887                 mUserProfiles.isCurrentProfile(record.getUserId()));
3888     }
3889
3890     private void playInCallNotification() {
3891         new Thread() {
3892             @Override
3893             public void run() {
3894                 // If toneGenerator creation fails, just continue the call
3895                 // without playing the notification sound.
3896                 try {
3897                     synchronized (mInCallToneGeneratorLock) {
3898                         if (mInCallToneGenerator != null) {
3899                             // limit this tone to 1 second; BEEP2 should in fact be much shorter
3900                             mInCallToneGenerator.startTone(ToneGenerator.TONE_PROP_BEEP2, 1000);
3901                         }
3902                     }
3903                 } catch (RuntimeException e) {
3904                     Log.w(TAG, "Exception from ToneGenerator: " + e);
3905                 }
3906             }
3907         }.start();
3908     }
3909
3910     @GuardedBy("mToastQueue")
3911     void showNextToastLocked() {
3912         ToastRecord record = mToastQueue.get(0);
3913         while (record != null) {
3914             if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
3915             try {
3916                 record.callback.show(record.token);
3917                 scheduleTimeoutLocked(record);
3918                 return;
3919             } catch (RemoteException e) {
3920                 Slog.w(TAG, "Object died trying to show notification " + record.callback
3921                         + " in package " + record.pkg);
3922                 // remove it from the list and let the process die
3923                 int index = mToastQueue.indexOf(record);
3924                 if (index >= 0) {
3925                     mToastQueue.remove(index);
3926                 }
3927                 keepProcessAliveIfNeededLocked(record.pid);
3928                 if (mToastQueue.size() > 0) {
3929                     record = mToastQueue.get(0);
3930                 } else {
3931                     record = null;
3932                 }
3933             }
3934         }
3935     }
3936
3937     @GuardedBy("mToastQueue")
3938     void cancelToastLocked(int index) {
3939         ToastRecord record = mToastQueue.get(index);
3940         try {
3941             record.callback.hide();
3942         } catch (RemoteException e) {
3943             Slog.w(TAG, "Object died trying to hide notification " + record.callback
3944                     + " in package " + record.pkg);
3945             // don't worry about this, we're about to remove it from
3946             // the list anyway
3947         }
3948
3949         ToastRecord lastToast = mToastQueue.remove(index);
3950         mWindowManagerInternal.removeWindowToken(lastToast.token, true, DEFAULT_DISPLAY);
3951
3952         keepProcessAliveIfNeededLocked(record.pid);
3953         if (mToastQueue.size() > 0) {
3954             // Show the next one. If the callback fails, this will remove
3955             // it from the list, so don't assume that the list hasn't changed
3956             // after this point.
3957             showNextToastLocked();
3958         }
3959     }
3960
3961     @GuardedBy("mToastQueue")
3962     private void scheduleTimeoutLocked(ToastRecord r)
3963     {
3964         mHandler.removeCallbacksAndMessages(r);
3965         Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
3966         long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
3967         mHandler.sendMessageDelayed(m, delay);
3968     }
3969
3970     private void handleTimeout(ToastRecord record)
3971     {
3972         if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
3973         synchronized (mToastQueue) {
3974             int index = indexOfToastLocked(record.pkg, record.callback);
3975             if (index >= 0) {
3976                 cancelToastLocked(index);
3977             }
3978         }
3979     }
3980
3981     @GuardedBy("mToastQueue")
3982     int indexOfToastLocked(String pkg, ITransientNotification callback)
3983     {
3984         IBinder cbak = callback.asBinder();
3985         ArrayList<ToastRecord> list = mToastQueue;
3986         int len = list.size();
3987         for (int i=0; i<len; i++) {
3988             ToastRecord r = list.get(i);
3989             if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
3990                 return i;
3991             }
3992         }
3993         return -1;
3994     }
3995
3996     @GuardedBy("mToastQueue")
3997     void keepProcessAliveIfNeededLocked(int pid)
3998     {
3999         int toastCount = 0; // toasts from this pid
4000         ArrayList<ToastRecord> list = mToastQueue;
4001         int N = list.size();
4002         for (int i=0; i<N; i++) {
4003             ToastRecord r = list.get(i);
4004             if (r.pid == pid) {
4005                 toastCount++;
4006             }
4007         }
4008         try {
4009             mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
4010         } catch (RemoteException e) {
4011             // Shouldn't happen.
4012         }
4013     }
4014
4015     private void handleRankingReconsideration(Message message) {
4016         if (!(message.obj instanceof RankingReconsideration)) return;
4017         RankingReconsideration recon = (RankingReconsideration) message.obj;
4018         recon.run();
4019         boolean changed;
4020         synchronized (mNotificationLock) {
4021             final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
4022             if (record == null) {
4023                 return;
4024             }
4025             int indexBefore = findNotificationRecordIndexLocked(record);
4026             boolean interceptBefore = record.isIntercepted();
4027             int visibilityBefore = record.getPackageVisibilityOverride();
4028             recon.applyChangesLocked(record);
4029             applyZenModeLocked(record);
4030             mRankingHelper.sort(mNotificationList);
4031             int indexAfter = findNotificationRecordIndexLocked(record);
4032             boolean interceptAfter = record.isIntercepted();
4033             int visibilityAfter = record.getPackageVisibilityOverride();
4034             changed = indexBefore != indexAfter || interceptBefore != interceptAfter
4035                     || visibilityBefore != visibilityAfter;
4036             if (interceptBefore && !interceptAfter) {
4037                 buzzBeepBlinkLocked(record);
4038             }
4039         }
4040         if (changed) {
4041             scheduleSendRankingUpdate();
4042         }
4043     }
4044
4045     private void handleRankingSort(Message msg) {
4046         if (!(msg.obj instanceof Boolean)) return;
4047         if (mRankingHelper == null) return;
4048         boolean forceUpdate = ((Boolean) msg.obj == null) ? false : (boolean) msg.obj;
4049         synchronized (mNotificationLock) {
4050             final int N = mNotificationList.size();
4051             // Any field that can change via one of the extractors or by the assistant
4052             // needs to be added here.
4053             ArrayList<String> orderBefore = new ArrayList<String>(N);
4054             ArrayList<String> groupOverrideBefore = new ArrayList<>(N);
4055             int[] visibilities = new int[N];
4056             boolean[] showBadges = new boolean[N];
4057             for (int i = 0; i < N; i++) {
4058                 final NotificationRecord r = mNotificationList.get(i);
4059                 orderBefore.add(r.getKey());
4060                 groupOverrideBefore.add(r.sbn.getGroupKey());
4061                 visibilities[i] = r.getPackageVisibilityOverride();
4062                 showBadges[i] = r.canShowBadge();
4063                 mRankingHelper.extractSignals(r);
4064             }
4065             mRankingHelper.sort(mNotificationList);
4066             for (int i = 0; i < N; i++) {
4067                 final NotificationRecord r = mNotificationList.get(i);
4068                 if (forceUpdate
4069                         || !orderBefore.get(i).equals(r.getKey())
4070                         || visibilities[i] != r.getPackageVisibilityOverride()
4071                         || !groupOverrideBefore.get(i).equals(r.sbn.getGroupKey())
4072                         || showBadges[i] != r.canShowBadge()) {
4073                     scheduleSendRankingUpdate();
4074                     return;
4075                 }
4076             }
4077         }
4078     }
4079
4080     @GuardedBy("mNotificationLock")
4081     private void recordCallerLocked(NotificationRecord record) {
4082         if (mZenModeHelper.isCall(record)) {
4083             mZenModeHelper.recordCaller(record);
4084         }
4085     }
4086
4087     // let zen mode evaluate this record
4088     @GuardedBy("mNotificationLock")
4089     private void applyZenModeLocked(NotificationRecord record) {
4090         record.setIntercepted(mZenModeHelper.shouldIntercept(record));
4091         if (record.isIntercepted()) {
4092             int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
4093                     ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
4094                     | (mZenModeHelper.shouldSuppressWhenScreenOn()
4095                     ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
4096             record.setSuppressedVisualEffects(suppressed);
4097         } else {
4098             record.setSuppressedVisualEffects(0);
4099         }
4100     }
4101
4102     @GuardedBy("mNotificationLock")
4103     private int findNotificationRecordIndexLocked(NotificationRecord target) {
4104         return mRankingHelper.indexOf(mNotificationList, target);
4105     }
4106
4107     private void scheduleSendRankingUpdate() {
4108         if (!mHandler.hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
4109             Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE);
4110             mHandler.sendMessage(m);
4111         }
4112     }
4113
4114     private void handleSendRankingUpdate() {
4115         synchronized (mNotificationLock) {
4116             mListeners.notifyRankingUpdateLocked();
4117         }
4118     }
4119
4120     private void scheduleListenerHintsChanged(int state) {
4121         mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
4122         mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
4123     }
4124
4125     private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
4126         mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
4127         mHandler.obtainMessage(
4128                 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
4129                 listenerInterruptionFilter,
4130                 0).sendToTarget();
4131     }
4132
4133     private void handleListenerHintsChanged(int hints) {
4134         synchronized (mNotificationLock) {
4135             mListeners.notifyListenerHintsChangedLocked(hints);
4136         }
4137     }
4138
4139     private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
4140         synchronized (mNotificationLock) {
4141             mListeners.notifyInterruptionFilterChanged(interruptionFilter);
4142         }
4143     }
4144
4145     private final class WorkerHandler extends Handler
4146     {
4147         public WorkerHandler(Looper looper) {
4148             super(looper);
4149         }
4150
4151         @Override
4152         public void handleMessage(Message msg)
4153         {
4154             switch (msg.what)
4155             {
4156                 case MESSAGE_TIMEOUT:
4157                     handleTimeout((ToastRecord)msg.obj);
4158                     break;
4159                 case MESSAGE_SAVE_POLICY_FILE:
4160                     handleSavePolicyFile();
4161                     break;
4162                 case MESSAGE_SEND_RANKING_UPDATE:
4163                     handleSendRankingUpdate();
4164                     break;
4165                 case MESSAGE_LISTENER_HINTS_CHANGED:
4166                     handleListenerHintsChanged(msg.arg1);
4167                     break;
4168                 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
4169                     handleListenerInterruptionFilterChanged(msg.arg1);
4170                     break;
4171             }
4172         }
4173
4174     }
4175
4176     private final class RankingHandlerWorker extends Handler implements RankingHandler
4177     {
4178         public RankingHandlerWorker(Looper looper) {
4179             super(looper);
4180         }
4181
4182         @Override
4183         public void handleMessage(Message msg) {
4184             switch (msg.what) {
4185                 case MESSAGE_RECONSIDER_RANKING:
4186                     handleRankingReconsideration(msg);
4187                     break;
4188                 case MESSAGE_RANKING_SORT:
4189                     handleRankingSort(msg);
4190                     break;
4191             }
4192         }
4193
4194         public void requestSort(boolean forceUpdate) {
4195             removeMessages(MESSAGE_RANKING_SORT);
4196             Message msg = Message.obtain();
4197             msg.what = MESSAGE_RANKING_SORT;
4198             msg.obj = forceUpdate;
4199             sendMessage(msg);
4200         }
4201
4202         public void requestReconsideration(RankingReconsideration recon) {
4203             Message m = Message.obtain(this,
4204                     NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
4205             long delay = recon.getDelay(TimeUnit.MILLISECONDS);
4206             sendMessageDelayed(m, delay);
4207         }
4208     }
4209
4210     // Notifications
4211     // ============================================================================
4212     static int clamp(int x, int low, int high) {
4213         return (x < low) ? low : ((x > high) ? high : x);
4214     }
4215
4216     void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
4217         AccessibilityManager manager = AccessibilityManager.getInstance(getContext());
4218         if (!manager.isEnabled()) {
4219             return;
4220         }
4221
4222         AccessibilityEvent event =
4223             AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
4224         event.setPackageName(packageName);
4225         event.setClassName(Notification.class.getName());
4226         event.setParcelableData(notification);
4227         CharSequence tickerText = notification.tickerText;
4228         if (!TextUtils.isEmpty(tickerText)) {
4229             event.getText().add(tickerText);
4230         }
4231
4232         manager.sendAccessibilityEvent(event);
4233     }
4234
4235     /**
4236      * Removes all NotificationsRecords with the same key as the given notification record
4237      * from both lists. Do not call this method while iterating over either list.
4238      */
4239     @GuardedBy("mNotificationLock")
4240     private boolean removeFromNotificationListsLocked(NotificationRecord r) {
4241         // Remove from both lists, either list could have a separate Record for what is
4242         // effectively the same notification.
4243         boolean wasPosted = false;
4244         NotificationRecord recordInList = null;
4245         if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))
4246                 != null) {
4247             mNotificationList.remove(recordInList);
4248             mNotificationsByKey.remove(recordInList.sbn.getKey());
4249             wasPosted = true;
4250         }
4251         while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
4252                 != null) {
4253             mEnqueuedNotifications.remove(recordInList);
4254         }
4255         return wasPosted;
4256     }
4257
4258     @GuardedBy("mNotificationLock")
4259     private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
4260             boolean wasPosted) {
4261         final String canceledKey = r.getKey();
4262
4263         // Record caller.
4264         recordCallerLocked(r);
4265
4266         // tell the app
4267         if (sendDelete) {
4268             if (r.getNotification().deleteIntent != null) {
4269                 try {
4270                     r.getNotification().deleteIntent.send();
4271                 } catch (PendingIntent.CanceledException ex) {
4272                     // do nothing - there's no relevant way to recover, and
4273                     //     no reason to let this propagate
4274                     Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
4275                 }
4276             }
4277         }
4278
4279         // Only cancel these if this notification actually got to be posted.
4280         if (wasPosted) {
4281             // status bar
4282             if (r.getNotification().getSmallIcon() != null) {
4283                 if (reason != REASON_SNOOZED) {
4284                     r.isCanceled = true;
4285                 }
4286                 mListeners.notifyRemovedLocked(r.sbn, reason);
4287                 mHandler.post(new Runnable() {
4288                     @Override
4289                     public void run() {
4290                         mGroupHelper.onNotificationRemoved(r.sbn);
4291                     }
4292                 });
4293             }
4294
4295             // sound
4296             if (canceledKey.equals(mSoundNotificationKey)) {
4297                 mSoundNotificationKey = null;
4298                 final long identity = Binder.clearCallingIdentity();
4299                 try {
4300                     final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4301                     if (player != null) {
4302                         player.stopAsync();
4303                     }
4304                 } catch (RemoteException e) {
4305                 } finally {
4306                     Binder.restoreCallingIdentity(identity);
4307                 }
4308             }
4309
4310             // vibrate
4311             if (canceledKey.equals(mVibrateNotificationKey)) {
4312                 mVibrateNotificationKey = null;
4313                 long identity = Binder.clearCallingIdentity();
4314                 try {
4315                     mVibrator.cancel();
4316                 }
4317                 finally {
4318                     Binder.restoreCallingIdentity(identity);
4319                 }
4320             }
4321
4322             // light
4323             mLights.remove(canceledKey);
4324         }
4325
4326         // Record usage stats
4327         // TODO: add unbundling stats?
4328         switch (reason) {
4329             case REASON_CANCEL:
4330             case REASON_CANCEL_ALL:
4331             case REASON_LISTENER_CANCEL:
4332             case REASON_LISTENER_CANCEL_ALL:
4333                 mUsageStats.registerDismissedByUser(r);
4334                 break;
4335             case REASON_APP_CANCEL:
4336             case REASON_APP_CANCEL_ALL:
4337                 mUsageStats.registerRemovedByApp(r);
4338                 break;
4339         }
4340
4341         String groupKey = r.getGroupKey();
4342         NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
4343         if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
4344             mSummaryByGroupKey.remove(groupKey);
4345         }
4346         final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
4347         if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
4348             summaries.remove(r.sbn.getPackageName());
4349         }
4350
4351         // Save it for users of getHistoricalNotifications()
4352         mArchive.record(r.sbn);
4353
4354         final long now = System.currentTimeMillis();
4355         MetricsLogger.action(r.getLogMaker(now)
4356                 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
4357                 .setType(MetricsEvent.TYPE_DISMISS)
4358                 .setSubtype(reason));
4359         EventLogTags.writeNotificationCanceled(canceledKey, reason,
4360                 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
4361     }
4362
4363     /**
4364      * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
4365      * and none of the {@code mustNotHaveFlags}.
4366      */
4367     void cancelNotification(final int callingUid, final int callingPid,
4368             final String pkg, final String tag, final int id,
4369             final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
4370             final int userId, final int reason, final ManagedServiceInfo listener) {
4371         // In enqueueNotificationInternal notifications are added by scheduling the
4372         // work on the worker handler. Hence, we also schedule the cancel on this
4373         // handler to avoid a scenario where an add notification call followed by a
4374         // remove notification call ends up in not removing the notification.
4375         mHandler.post(new Runnable() {
4376             @Override
4377             public void run() {
4378                 String listenerName = listener == null ? null : listener.component.toShortString();
4379                 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
4380                         userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
4381
4382                 synchronized (mNotificationLock) {
4383                     // Look for the notification, searching both the posted and enqueued lists.
4384                     NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
4385                     if (r != null) {
4386                         // The notification was found, check if it should be removed.
4387
4388                         // Ideally we'd do this in the caller of this method. However, that would
4389                         // require the caller to also find the notification.
4390                         if (reason == REASON_CLICK) {
4391                             mUsageStats.registerClickedByUser(r);
4392                         }
4393
4394                         if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
4395                             return;
4396                         }
4397                         if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
4398                             return;
4399                         }
4400
4401                         // Cancel the notification.
4402                         boolean wasPosted = removeFromNotificationListsLocked(r);
4403                         cancelNotificationLocked(r, sendDelete, reason, wasPosted);
4404                         cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
4405                                 sendDelete);
4406                         updateLightsLocked();
4407                     } else {
4408                         // No notification was found, assume that it is snoozed and cancel it.
4409                         if (reason != REASON_SNOOZED) {
4410                             final boolean wasSnoozed = mSnoozeHelper.cancel(userId, pkg, tag, id);
4411                             if (wasSnoozed) {
4412                                 savePolicyFile();
4413                             }
4414                         }
4415                     }
4416                 }
4417             }
4418         });
4419     }
4420
4421     /**
4422      * Determine whether the userId applies to the notification in question, either because
4423      * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
4424      */
4425     private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
4426         return
4427                 // looking for USER_ALL notifications? match everything
4428                    userId == UserHandle.USER_ALL
4429                 // a notification sent to USER_ALL matches any query
4430                 || r.getUserId() == UserHandle.USER_ALL
4431                 // an exact user match
4432                 || r.getUserId() == userId;
4433     }
4434
4435     /**
4436      * Determine whether the userId applies to the notification in question, either because
4437      * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
4438      * because it matches one of the users profiles.
4439      */
4440     private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
4441         return notificationMatchesUserId(r, userId)
4442                 || mUserProfiles.isCurrentProfile(r.getUserId());
4443     }
4444
4445     /**
4446      * Cancels all notifications from a given package that have all of the
4447      * {@code mustHaveFlags}.
4448      */
4449     void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
4450             int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
4451             ManagedServiceInfo listener) {
4452         mHandler.post(new Runnable() {
4453             @Override
4454             public void run() {
4455                 String listenerName = listener == null ? null : listener.component.toShortString();
4456                 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
4457                         pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
4458                         listenerName);
4459
4460                 // Why does this parameter exist? Do we actually want to execute the above if doit
4461                 // is false?
4462                 if (!doit) {
4463                     return;
4464                 }
4465
4466                 synchronized (mNotificationLock) {
4467                     FlagChecker flagChecker = (int flags) -> {
4468                         if ((flags & mustHaveFlags) != mustHaveFlags) {
4469                             return false;
4470                         }
4471                         if ((flags & mustNotHaveFlags) != 0) {
4472                             return false;
4473                         }
4474                         return true;
4475                     };
4476
4477                     cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
4478                             pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
4479                             false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
4480                             listenerName, true /* wasPosted */);
4481                     cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
4482                             callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
4483                             flagChecker, false /*includeCurrentProfiles*/, userId,
4484                             false /*sendDelete*/, reason, listenerName, false /* wasPosted */);
4485                     mSnoozeHelper.cancel(userId, pkg);
4486                 }
4487             }
4488         });
4489     }
4490
4491     private interface FlagChecker {
4492         // Returns false if these flags do not pass the defined flag test.
4493         public boolean apply(int flags);
4494     }
4495
4496     @GuardedBy("mNotificationLock")
4497     private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
4498             int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
4499             String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
4500             boolean sendDelete, int reason, String listenerName, boolean wasPosted) {
4501         ArrayList<NotificationRecord> canceledNotifications = null;
4502         for (int i = notificationList.size() - 1; i >= 0; --i) {
4503             NotificationRecord r = notificationList.get(i);
4504             if (includeCurrentProfiles) {
4505                 if (!notificationMatchesCurrentProfiles(r, userId)) {
4506                     continue;
4507                 }
4508             } else if (!notificationMatchesUserId(r, userId)) {
4509                 continue;
4510             }
4511             // Don't remove notifications to all, if there's no package name specified
4512             if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
4513                 continue;
4514             }
4515             if (!flagChecker.apply(r.getFlags())) {
4516                 continue;
4517             }
4518             if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
4519                 continue;
4520             }
4521             if (channelId != null && !channelId.equals(r.getChannel().getId())) {
4522                 continue;
4523             }
4524
4525             if (canceledNotifications == null) {
4526                 canceledNotifications = new ArrayList<>();
4527             }
4528             notificationList.remove(i);
4529             mNotificationsByKey.remove(r.getKey());
4530             canceledNotifications.add(r);
4531             cancelNotificationLocked(r, sendDelete, reason, wasPosted);
4532         }
4533         if (canceledNotifications != null) {
4534             final int M = canceledNotifications.size();
4535             for (int i = 0; i < M; i++) {
4536                 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
4537                         listenerName, false /* sendDelete */);
4538             }
4539             updateLightsLocked();
4540         }
4541     }
4542
4543     void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
4544             ManagedServiceInfo listener) {
4545         String listenerName = listener == null ? null : listener.component.toShortString();
4546         if (duration <= 0 && snoozeCriterionId == null || key == null) {
4547             return;
4548         }
4549
4550         if (DBG) {
4551             Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
4552                     snoozeCriterionId, listenerName));
4553         }
4554         // Needs to post so that it can cancel notifications not yet enqueued.
4555         mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
4556     }
4557
4558     void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
4559         String listenerName = listener == null ? null : listener.component.toShortString();
4560         if (DBG) {
4561             Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
4562         }
4563         mSnoozeHelper.repost(key);
4564         savePolicyFile();
4565     }
4566
4567     @GuardedBy("mNotificationLock")
4568     void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
4569             ManagedServiceInfo listener, boolean includeCurrentProfiles) {
4570         mHandler.post(new Runnable() {
4571             @Override
4572             public void run() {
4573                 synchronized (mNotificationLock) {
4574                     String listenerName =
4575                             listener == null ? null : listener.component.toShortString();
4576                     EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
4577                             null, userId, 0, 0, reason, listenerName);
4578
4579                     FlagChecker flagChecker = (int flags) -> {
4580                         if ((flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR))
4581                                 != 0) {
4582                             return false;
4583                         }
4584                         return true;
4585                     };
4586
4587                     cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
4588                             null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
4589                             includeCurrentProfiles, userId, true /*sendDelete*/, reason,
4590                             listenerName, true);
4591                     cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
4592                             callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
4593                             flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
4594                             reason, listenerName, false);
4595                     mSnoozeHelper.cancel(userId, includeCurrentProfiles);
4596                 }
4597             }
4598         });
4599     }
4600
4601     // Warning: The caller is responsible for invoking updateLightsLocked().
4602     @GuardedBy("mNotificationLock")
4603     private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
4604             String listenerName, boolean sendDelete) {
4605         Notification n = r.getNotification();
4606         if (!n.isGroupSummary()) {
4607             return;
4608         }
4609
4610         String pkg = r.sbn.getPackageName();
4611
4612         if (pkg == null) {
4613             if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
4614             return;
4615         }
4616
4617         cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
4618                 sendDelete, true);
4619         cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
4620                 listenerName, sendDelete, false);
4621     }
4622
4623     @GuardedBy("mNotificationLock")
4624     private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
4625             NotificationRecord parentNotification, int callingUid, int callingPid,
4626             String listenerName, boolean sendDelete, boolean wasPosted) {
4627         final String pkg = parentNotification.sbn.getPackageName();
4628         final int userId = parentNotification.getUserId();
4629         final int reason = REASON_GROUP_SUMMARY_CANCELED;
4630         for (int i = notificationList.size() - 1; i >= 0; i--) {
4631             final NotificationRecord childR = notificationList.get(i);
4632             final StatusBarNotification childSbn = childR.sbn;
4633             if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
4634                     childR.getGroupKey().equals(parentNotification.getGroupKey())
4635                     && (childR.getFlags() & Notification.FLAG_FOREGROUND_SERVICE) == 0) {
4636                 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
4637                         childSbn.getTag(), userId, 0, 0, reason, listenerName);
4638                 notificationList.remove(i);
4639                 mNotificationsByKey.remove(childR.getKey());
4640                 cancelNotificationLocked(childR, sendDelete, reason, wasPosted);
4641             }
4642         }
4643     }
4644
4645     @GuardedBy("mNotificationLock")
4646     void updateLightsLocked()
4647     {
4648         // handle notification lights
4649         NotificationRecord ledNotification = null;
4650         while (ledNotification == null && !mLights.isEmpty()) {
4651             final String owner = mLights.get(mLights.size() - 1);
4652             ledNotification = mNotificationsByKey.get(owner);
4653             if (ledNotification == null) {
4654                 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
4655                 mLights.remove(owner);
4656             }
4657         }
4658
4659         // Don't flash while we are in a call or screen is on
4660         if (ledNotification == null || mInCall || mScreenOn) {
4661             mNotificationLight.turnOff();
4662         } else {
4663             NotificationRecord.Light light = ledNotification.getLight();
4664             if (light != null && mNotificationPulseEnabled) {
4665                 // pulse repeatedly
4666                 mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
4667                         light.onMs, light.offMs);
4668             }
4669         }
4670     }
4671
4672     @GuardedBy("mNotificationLock")
4673     @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
4674             String groupKey, int userId) {
4675         List<NotificationRecord> records = new ArrayList<>();
4676         records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
4677         records.addAll(
4678                 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
4679         return records;
4680     }
4681
4682
4683     @GuardedBy("mNotificationLock")
4684     private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
4685             ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
4686         List<NotificationRecord> records = new ArrayList<>();
4687         final int len = list.size();
4688         for (int i = 0; i < len; i++) {
4689             NotificationRecord r = list.get(i);
4690             if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey)
4691                     && r.sbn.getPackageName().equals(pkg)) {
4692                 records.add(r);
4693             }
4694         }
4695         return records;
4696     }
4697
4698     // Searches both enqueued and posted notifications by key.
4699     // TODO: need to combine a bunch of these getters with slightly different behavior.
4700     // TODO: Should enqueuing just add to mNotificationsByKey instead?
4701     @GuardedBy("mNotificationLock")
4702     private NotificationRecord findNotificationByKeyLocked(String key) {
4703         NotificationRecord r;
4704         if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
4705             return r;
4706         }
4707         if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
4708             return r;
4709         }
4710         return null;
4711     }
4712
4713     @GuardedBy("mNotificationLock")
4714     NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
4715         NotificationRecord r;
4716         if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
4717             return r;
4718         }
4719         if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
4720                 != null) {
4721             return r;
4722         }
4723         return null;
4724     }
4725
4726     @GuardedBy("mNotificationLock")
4727     private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
4728             String pkg, String tag, int id, int userId) {
4729         final int len = list.size();
4730         for (int i = 0; i < len; i++) {
4731             NotificationRecord r = list.get(i);
4732             if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
4733                     TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
4734                 return r;
4735             }
4736         }
4737         return null;
4738     }
4739
4740     @GuardedBy("mNotificationLock")
4741     private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
4742             String key) {
4743         final int N = list.size();
4744         for (int i = 0; i < N; i++) {
4745             if (key.equals(list.get(i).getKey())) {
4746                 return list.get(i);
4747             }
4748         }
4749         return null;
4750     }
4751
4752     @GuardedBy("mNotificationLock")
4753     int indexOfNotificationLocked(String key) {
4754         final int N = mNotificationList.size();
4755         for (int i = 0; i < N; i++) {
4756             if (key.equals(mNotificationList.get(i).getKey())) {
4757                 return i;
4758             }
4759         }
4760         return -1;
4761     }
4762
4763     private void updateNotificationPulse() {
4764         synchronized (mNotificationLock) {
4765             updateLightsLocked();
4766         }
4767     }
4768
4769     protected boolean isCallingUidSystem() {
4770         final int uid = Binder.getCallingUid();
4771         return uid == Process.SYSTEM_UID;
4772     }
4773
4774     protected boolean isUidSystemOrPhone(int uid) {
4775         final int appid = UserHandle.getAppId(uid);
4776         return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
4777     }
4778
4779     // TODO: Most calls should probably move to isCallerSystem.
4780     protected boolean isCallerSystemOrPhone() {
4781         return isUidSystemOrPhone(Binder.getCallingUid());
4782     }
4783
4784     private void checkCallerIsSystem() {
4785         if (isCallerSystemOrPhone()) {
4786             return;
4787         }
4788         throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
4789     }
4790
4791     private void checkCallerIsSystemOrSameApp(String pkg) {
4792         if (isCallerSystemOrPhone()) {
4793             return;
4794         }
4795         checkCallerIsSameApp(pkg);
4796     }
4797
4798     private boolean isCallerInstantApp(String pkg) {
4799         // System is always allowed to act for ephemeral apps.
4800         if (isCallerSystemOrPhone()) {
4801             return false;
4802         }
4803
4804         mAppOps.checkPackage(Binder.getCallingUid(), pkg);
4805
4806         try {
4807             ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0,
4808                     UserHandle.getCallingUserId());
4809             if (ai == null) {
4810                 throw new SecurityException("Unknown package " + pkg);
4811             }
4812             return ai.isInstantApp();
4813         } catch (RemoteException re) {
4814             throw new SecurityException("Unknown package " + pkg, re);
4815         }
4816
4817     }
4818
4819     private void checkCallerIsSameApp(String pkg) {
4820         final int uid = Binder.getCallingUid();
4821         try {
4822             ApplicationInfo ai = mPackageManager.getApplicationInfo(
4823                     pkg, 0, UserHandle.getCallingUserId());
4824             if (ai == null) {
4825                 throw new SecurityException("Unknown package " + pkg);
4826             }
4827             if (!UserHandle.isSameApp(ai.uid, uid)) {
4828                 throw new SecurityException("Calling uid " + uid + " gave package "
4829                         + pkg + " which is owned by uid " + ai.uid);
4830             }
4831         } catch (RemoteException re) {
4832             throw new SecurityException("Unknown package " + pkg + "\n" + re);
4833         }
4834     }
4835
4836     private static String callStateToString(int state) {
4837         switch (state) {
4838             case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
4839             case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
4840             case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
4841             default: return "CALL_STATE_UNKNOWN_" + state;
4842         }
4843     }
4844
4845     private void listenForCallState() {
4846         TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
4847             @Override
4848             public void onCallStateChanged(int state, String incomingNumber) {
4849                 if (mCallState == state) return;
4850                 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
4851                 mCallState = state;
4852             }
4853         }, PhoneStateListener.LISTEN_CALL_STATE);
4854     }
4855
4856     /**
4857      * Generates a NotificationRankingUpdate from 'sbns', considering only
4858      * notifications visible to the given listener.
4859      */
4860     @GuardedBy("mNotificationLock")
4861     private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
4862         final int N = mNotificationList.size();
4863         ArrayList<String> keys = new ArrayList<String>(N);
4864         ArrayList<String> interceptedKeys = new ArrayList<String>(N);
4865         ArrayList<Integer> importance = new ArrayList<>(N);
4866         Bundle overrideGroupKeys = new Bundle();
4867         Bundle visibilityOverrides = new Bundle();
4868         Bundle suppressedVisualEffects = new Bundle();
4869         Bundle explanation = new Bundle();
4870         Bundle channels = new Bundle();
4871         Bundle overridePeople = new Bundle();
4872         Bundle snoozeCriteria = new Bundle();
4873         Bundle showBadge = new Bundle();
4874         for (int i = 0; i < N; i++) {
4875             NotificationRecord record = mNotificationList.get(i);
4876             if (!isVisibleToListener(record.sbn, info)) {
4877                 continue;
4878             }
4879             final String key = record.sbn.getKey();
4880             keys.add(key);
4881             importance.add(record.getImportance());
4882             if (record.getImportanceExplanation() != null) {
4883                 explanation.putCharSequence(key, record.getImportanceExplanation());
4884             }
4885             if (record.isIntercepted()) {
4886                 interceptedKeys.add(key);
4887
4888             }
4889             suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
4890             if (record.getPackageVisibilityOverride()
4891                     != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
4892                 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
4893             }
4894             overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
4895             channels.putParcelable(key, record.getChannel());
4896             overridePeople.putStringArrayList(key, record.getPeopleOverride());
4897             snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria());
4898             showBadge.putBoolean(key, record.canShowBadge());
4899         }
4900         final int M = keys.size();
4901         String[] keysAr = keys.toArray(new String[M]);
4902         String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
4903         int[] importanceAr = new int[M];
4904         for (int i = 0; i < M; i++) {
4905             importanceAr[i] = importance.get(i);
4906         }
4907         return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
4908                 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
4909                 channels, overridePeople, snoozeCriteria, showBadge);
4910     }
4911
4912     boolean hasCompanionDevice(ManagedServiceInfo info) {
4913         if (mCompanionManager == null) {
4914             mCompanionManager = getCompanionManager();
4915         }
4916         // Companion mgr doesn't exist on all device types
4917         if (mCompanionManager == null) {
4918             return false;
4919         }
4920         long identity = Binder.clearCallingIdentity();
4921         try {
4922             List<String> associations = mCompanionManager.getAssociations(
4923                     info.component.getPackageName(), info.userid);
4924             if (!ArrayUtils.isEmpty(associations)) {
4925                 return true;
4926             }
4927         } catch (SecurityException se) {
4928             // Not a privileged listener
4929         } catch (RemoteException re) {
4930             Slog.e(TAG, "Cannot reach companion device service", re);
4931         } catch (Exception e) {
4932             Slog.e(TAG, "Cannot verify listener " + info, e);
4933         } finally {
4934             Binder.restoreCallingIdentity(identity);
4935         }
4936         return false;
4937     }
4938
4939     protected ICompanionDeviceManager getCompanionManager() {
4940         return ICompanionDeviceManager.Stub.asInterface(
4941                 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
4942     }
4943
4944     private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
4945         if (!listener.enabledAndUserMatches(sbn.getUserId())) {
4946             return false;
4947         }
4948         // TODO: remove this for older listeners.
4949         return true;
4950     }
4951
4952     private boolean isPackageSuspendedForUser(String pkg, int uid) {
4953         int userId = UserHandle.getUserId(uid);
4954         try {
4955             return mPackageManager.isPackageSuspendedForUser(pkg, userId);
4956         } catch (RemoteException re) {
4957             throw new SecurityException("Could not talk to package manager service");
4958         } catch (IllegalArgumentException ex) {
4959             // Package not found.
4960             return false;
4961         }
4962     }
4963
4964     private class TrimCache {
4965         StatusBarNotification heavy;
4966         StatusBarNotification sbnClone;
4967         StatusBarNotification sbnCloneLight;
4968
4969         TrimCache(StatusBarNotification sbn) {
4970             heavy = sbn;
4971         }
4972
4973         StatusBarNotification ForListener(ManagedServiceInfo info) {
4974             if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
4975                 if (sbnCloneLight == null) {
4976                     sbnCloneLight = heavy.cloneLight();
4977                 }
4978                 return sbnCloneLight;
4979             } else {
4980                 if (sbnClone == null) {
4981                     sbnClone = heavy.clone();
4982                 }
4983                 return sbnClone;
4984             }
4985         }
4986     }
4987
4988     public class NotificationAssistants extends ManagedServices {
4989
4990         public NotificationAssistants() {
4991             super(getContext(), mHandler, mNotificationLock, mUserProfiles);
4992         }
4993
4994         @Override
4995         protected Config getConfig() {
4996             Config c = new Config();
4997             c.caption = "notification assistant service";
4998             c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
4999             c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
5000             c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
5001             c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
5002             c.clientLabel = R.string.notification_ranker_binding_label;
5003             return c;
5004         }
5005
5006         @Override
5007         protected IInterface asInterface(IBinder binder) {
5008             return INotificationListener.Stub.asInterface(binder);
5009         }
5010
5011         @Override
5012         protected boolean checkType(IInterface service) {
5013             return service instanceof INotificationListener;
5014         }
5015
5016         @Override
5017         protected void onServiceAdded(ManagedServiceInfo info) {
5018             mListeners.registerGuestService(info);
5019         }
5020
5021         @Override
5022         @GuardedBy("mNotificationLock")
5023         protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
5024             mListeners.unregisterService(removed.service, removed.userid);
5025         }
5026
5027         public void onNotificationEnqueued(final NotificationRecord r) {
5028             final StatusBarNotification sbn = r.sbn;
5029             TrimCache trimCache = new TrimCache(sbn);
5030
5031             // There should be only one, but it's a list, so while we enforce
5032             // singularity elsewhere, we keep it general here, to avoid surprises.
5033             for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
5034                 boolean sbnVisible = isVisibleToListener(sbn, info);
5035                 if (!sbnVisible) {
5036                     continue;
5037                 }
5038
5039                 final int importance = r.getImportance();
5040                 final boolean fromUser = r.isImportanceFromUser();
5041                 final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
5042                 mHandler.post(new Runnable() {
5043                     @Override
5044                     public void run() {
5045                         notifyEnqueued(info, sbnToPost);
5046                     }
5047                 });
5048             }
5049         }
5050
5051         private void notifyEnqueued(final ManagedServiceInfo info,
5052                 final StatusBarNotification sbn) {
5053             final INotificationListener assistant = (INotificationListener) info.service;
5054             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5055             try {
5056                 assistant.onNotificationEnqueued(sbnHolder);
5057             } catch (RemoteException ex) {
5058                 Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
5059             }
5060         }
5061
5062         /**
5063          * asynchronously notify the assistant that a notification has been snoozed until a
5064          * context
5065          */
5066         @GuardedBy("mNotificationLock")
5067         public void notifyAssistantSnoozedLocked(final StatusBarNotification sbn,
5068                 final String snoozeCriterionId) {
5069             TrimCache trimCache = new TrimCache(sbn);
5070             for (final ManagedServiceInfo info : getServices()) {
5071                 final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
5072                 mHandler.post(new Runnable() {
5073                     @Override
5074                     public void run() {
5075                         final INotificationListener assistant =
5076                                 (INotificationListener) info.service;
5077                         StatusBarNotificationHolder sbnHolder
5078                                 = new StatusBarNotificationHolder(sbnToPost);
5079                         try {
5080                             assistant.onNotificationSnoozedUntilContext(
5081                                     sbnHolder, snoozeCriterionId);
5082                         } catch (RemoteException ex) {
5083                             Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
5084                         }
5085                     }
5086                 });
5087             }
5088         }
5089
5090         public boolean isEnabled() {
5091             return !getServices().isEmpty();
5092         }
5093     }
5094
5095     public class NotificationListeners extends ManagedServices {
5096
5097         private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
5098
5099         public NotificationListeners() {
5100             super(getContext(), mHandler, mNotificationLock, mUserProfiles);
5101         }
5102
5103         @Override
5104         protected Config getConfig() {
5105             Config c = new Config();
5106             c.caption = "notification listener";
5107             c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
5108             c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
5109             c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
5110             c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
5111             c.clientLabel = R.string.notification_listener_binding_label;
5112             return c;
5113         }
5114
5115         @Override
5116         protected IInterface asInterface(IBinder binder) {
5117             return INotificationListener.Stub.asInterface(binder);
5118         }
5119
5120         @Override
5121         protected boolean checkType(IInterface service) {
5122             return service instanceof INotificationListener;
5123         }
5124
5125         @Override
5126         public void onServiceAdded(ManagedServiceInfo info) {
5127             final INotificationListener listener = (INotificationListener) info.service;
5128             final NotificationRankingUpdate update;
5129             synchronized (mNotificationLock) {
5130                 update = makeRankingUpdateLocked(info);
5131             }
5132             try {
5133                 listener.onListenerConnected(update);
5134             } catch (RemoteException e) {
5135                 // we tried
5136             }
5137         }
5138
5139         @Override
5140         @GuardedBy("mNotificationLock")
5141         protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
5142             if (removeDisabledHints(removed)) {
5143                 updateListenerHintsLocked();
5144                 updateEffectsSuppressorLocked();
5145             }
5146             mLightTrimListeners.remove(removed);
5147         }
5148
5149         @GuardedBy("mNotificationLock")
5150         public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
5151             if (trim == TRIM_LIGHT) {
5152                 mLightTrimListeners.add(info);
5153             } else {
5154                 mLightTrimListeners.remove(info);
5155             }
5156         }
5157
5158         public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
5159             return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
5160         }
5161
5162         /**
5163          * asynchronously notify all listeners about a new notification
5164          *
5165          * <p>
5166          * Also takes care of removing a notification that has been visible to a listener before,
5167          * but isn't anymore.
5168          */
5169         @GuardedBy("mNotificationLock")
5170         public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
5171             // Lazily initialized snapshots of the notification.
5172             TrimCache trimCache = new TrimCache(sbn);
5173
5174             for (final ManagedServiceInfo info : getServices()) {
5175                 boolean sbnVisible = isVisibleToListener(sbn, info);
5176                 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
5177                 // This notification hasn't been and still isn't visible -> ignore.
5178                 if (!oldSbnVisible && !sbnVisible) {
5179                     continue;
5180                 }
5181                 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
5182
5183                 // This notification became invisible -> remove the old one.
5184                 if (oldSbnVisible && !sbnVisible) {
5185                     final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
5186                     mHandler.post(new Runnable() {
5187                         @Override
5188                         public void run() {
5189                             notifyRemoved(info, oldSbnLightClone, update, REASON_USER_STOPPED);
5190                         }
5191                     });
5192                     continue;
5193                 }
5194
5195                 final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
5196                 mHandler.post(new Runnable() {
5197                     @Override
5198                     public void run() {
5199                         notifyPosted(info, sbnToPost, update);
5200                     }
5201                 });
5202             }
5203         }
5204
5205         /**
5206          * asynchronously notify all listeners about a removed notification
5207          */
5208         @GuardedBy("mNotificationLock")
5209         public void notifyRemovedLocked(StatusBarNotification sbn, int reason) {
5210             // make a copy in case changes are made to the underlying Notification object
5211             // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
5212             // notification
5213             final StatusBarNotification sbnLight = sbn.cloneLight();
5214             for (final ManagedServiceInfo info : getServices()) {
5215                 if (!isVisibleToListener(sbn, info)) {
5216                     continue;
5217                 }
5218                 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
5219                 mHandler.post(new Runnable() {
5220                     @Override
5221                     public void run() {
5222                         notifyRemoved(info, sbnLight, update, reason);
5223                     }
5224                 });
5225             }
5226         }
5227
5228         /**
5229          * asynchronously notify all listeners about a reordering of notifications
5230          */
5231         @GuardedBy("mNotificationLock")
5232         public void notifyRankingUpdateLocked() {
5233             for (final ManagedServiceInfo serviceInfo : getServices()) {
5234                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5235                     continue;
5236                 }
5237                 final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
5238                 mHandler.post(new Runnable() {
5239                     @Override
5240                     public void run() {
5241                         notifyRankingUpdate(serviceInfo, update);
5242                     }
5243                 });
5244             }
5245         }
5246
5247         @GuardedBy("mNotificationLock")
5248         public void notifyListenerHintsChangedLocked(final int hints) {
5249             for (final ManagedServiceInfo serviceInfo : getServices()) {
5250                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5251                     continue;
5252                 }
5253                 mHandler.post(new Runnable() {
5254                     @Override
5255                     public void run() {
5256                         notifyListenerHintsChanged(serviceInfo, hints);
5257                     }
5258                 });
5259             }
5260         }
5261
5262         public void notifyInterruptionFilterChanged(final int interruptionFilter) {
5263             for (final ManagedServiceInfo serviceInfo : getServices()) {
5264                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5265                     continue;
5266                 }
5267                 mHandler.post(new Runnable() {
5268                     @Override
5269                     public void run() {
5270                         notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
5271                     }
5272                 });
5273             }
5274         }
5275
5276         protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user,
5277                 final NotificationChannel channel, final int modificationType) {
5278             if (channel == null) {
5279                 return;
5280             }
5281             for (final ManagedServiceInfo serviceInfo : getServices()) {
5282                 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
5283                     continue;
5284                 }
5285
5286                 mHandler.post(new Runnable() {
5287                     @Override
5288                     public void run() {
5289                         if (hasCompanionDevice(serviceInfo)) {
5290                             notifyNotificationChannelChanged(
5291                                     serviceInfo, pkg, user, channel, modificationType);
5292                         }
5293                     }
5294                 });
5295             }
5296         }
5297
5298         protected void notifyNotificationChannelGroupChanged(
5299                 final String pkg, final UserHandle user, final NotificationChannelGroup group,
5300                 final int modificationType) {
5301             if (group == null) {
5302                 return;
5303             }
5304             for (final ManagedServiceInfo serviceInfo : getServices()) {
5305                 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
5306                     continue;
5307                 }
5308
5309                 mHandler.post(new Runnable() {
5310                     @Override
5311                     public void run() {
5312                         if (hasCompanionDevice(serviceInfo)) {
5313                             notifyNotificationChannelGroupChanged(
5314                                     serviceInfo, pkg, user, group, modificationType);
5315                         }
5316                     }
5317                 });
5318             }
5319         }
5320
5321         private void notifyPosted(final ManagedServiceInfo info,
5322                 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
5323             final INotificationListener listener = (INotificationListener) info.service;
5324             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5325             try {
5326                 listener.onNotificationPosted(sbnHolder, rankingUpdate);
5327             } catch (RemoteException ex) {
5328                 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
5329             }
5330         }
5331
5332         private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
5333                 NotificationRankingUpdate rankingUpdate, int reason) {
5334             if (!info.enabledAndUserMatches(sbn.getUserId())) {
5335                 return;
5336             }
5337             final INotificationListener listener = (INotificationListener) info.service;
5338             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5339             try {
5340                 listener.onNotificationRemoved(sbnHolder, rankingUpdate, reason);
5341             } catch (RemoteException ex) {
5342                 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
5343             }
5344         }
5345
5346         private void notifyRankingUpdate(ManagedServiceInfo info,
5347                                          NotificationRankingUpdate rankingUpdate) {
5348             final INotificationListener listener = (INotificationListener) info.service;
5349             try {
5350                 listener.onNotificationRankingUpdate(rankingUpdate);
5351             } catch (RemoteException ex) {
5352                 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
5353             }
5354         }
5355
5356         private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
5357             final INotificationListener listener = (INotificationListener) info.service;
5358             try {
5359                 listener.onListenerHintsChanged(hints);
5360             } catch (RemoteException ex) {
5361                 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
5362             }
5363         }
5364
5365         private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
5366                 int interruptionFilter) {
5367             final INotificationListener listener = (INotificationListener) info.service;
5368             try {
5369                 listener.onInterruptionFilterChanged(interruptionFilter);
5370             } catch (RemoteException ex) {
5371                 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
5372             }
5373         }
5374
5375         void notifyNotificationChannelChanged(ManagedServiceInfo info,
5376                 final String pkg, final UserHandle user, final NotificationChannel channel,
5377                 final int modificationType) {
5378             final INotificationListener listener = (INotificationListener) info.service;
5379             try {
5380                 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
5381             } catch (RemoteException ex) {
5382                 Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
5383             }
5384         }
5385
5386         private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
5387                 final String pkg, final UserHandle user, final NotificationChannelGroup group,
5388                 final int modificationType) {
5389             final INotificationListener listener = (INotificationListener) info.service;
5390             try {
5391                 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
5392             } catch (RemoteException ex) {
5393                 Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
5394             }
5395         }
5396
5397         public boolean isListenerPackage(String packageName) {
5398             if (packageName == null) {
5399                 return false;
5400             }
5401             // TODO: clean up locking object later
5402             synchronized (mNotificationLock) {
5403                 for (final ManagedServiceInfo serviceInfo : getServices()) {
5404                     if (packageName.equals(serviceInfo.component.getPackageName())) {
5405                         return true;
5406                     }
5407                 }
5408             }
5409             return false;
5410         }
5411     }
5412
5413     public static final class DumpFilter {
5414         public boolean filtered = false;
5415         public String pkgFilter;
5416         public boolean zen;
5417         public long since;
5418         public boolean stats;
5419         public boolean redact = true;
5420         public boolean proto = false;
5421
5422         public static DumpFilter parseFromArguments(String[] args) {
5423             final DumpFilter filter = new DumpFilter();
5424             for (int ai = 0; ai < args.length; ai++) {
5425                 final String a = args[ai];
5426                 if ("--proto".equals(args[0])) {
5427                     filter.proto = true;
5428                 }
5429                 if ("--noredact".equals(a) || "--reveal".equals(a)) {
5430                     filter.redact = false;
5431                 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
5432                     if (ai < args.length-1) {
5433                         ai++;
5434                         filter.pkgFilter = args[ai].trim().toLowerCase();
5435                         if (filter.pkgFilter.isEmpty()) {
5436                             filter.pkgFilter = null;
5437                         } else {
5438                             filter.filtered = true;
5439                         }
5440                     }
5441                 } else if ("--zen".equals(a) || "zen".equals(a)) {
5442                     filter.filtered = true;
5443                     filter.zen = true;
5444                 } else if ("--stats".equals(a)) {
5445                     filter.stats = true;
5446                     if (ai < args.length-1) {
5447                         ai++;
5448                         filter.since = Long.parseLong(args[ai]);
5449                     } else {
5450                         filter.since = 0;
5451                     }
5452                 }
5453             }
5454             return filter;
5455         }
5456
5457         public boolean matches(StatusBarNotification sbn) {
5458             if (!filtered) return true;
5459             return zen ? true : sbn != null
5460                     && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
5461         }
5462
5463         public boolean matches(ComponentName component) {
5464             if (!filtered) return true;
5465             return zen ? true : component != null && matches(component.getPackageName());
5466         }
5467
5468         public boolean matches(String pkg) {
5469             if (!filtered) return true;
5470             return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
5471         }
5472
5473         @Override
5474         public String toString() {
5475             return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
5476         }
5477     }
5478
5479     /**
5480      * Wrapper for a StatusBarNotification object that allows transfer across a oneway
5481      * binder without sending large amounts of data over a oneway transaction.
5482      */
5483     private static final class StatusBarNotificationHolder
5484             extends IStatusBarNotificationHolder.Stub {
5485         private StatusBarNotification mValue;
5486
5487         public StatusBarNotificationHolder(StatusBarNotification value) {
5488             mValue = value;
5489         }
5490
5491         /** Get the held value and clear it. This function should only be called once per holder */
5492         @Override
5493         public StatusBarNotification get() {
5494             StatusBarNotification value = mValue;
5495             mValue = null;
5496             return value;
5497         }
5498     }
5499
5500     private final class PolicyAccess {
5501         private static final String SEPARATOR = ":";
5502         private final String[] PERM = {
5503             android.Manifest.permission.ACCESS_NOTIFICATION_POLICY
5504         };
5505
5506         public boolean isPackageGranted(String pkg) {
5507             return pkg != null && getGrantedPackages().contains(pkg);
5508         }
5509
5510         public void put(String pkg, boolean granted) {
5511             if (pkg == null) return;
5512             final ArraySet<String> pkgs = getGrantedPackages();
5513             boolean changed;
5514             if (granted) {
5515                 changed = pkgs.add(pkg);
5516             } else {
5517                 changed = pkgs.remove(pkg);
5518             }
5519             if (!changed) return;
5520             final String setting = TextUtils.join(SEPARATOR, pkgs);
5521             final int currentUser = ActivityManager.getCurrentUser();
5522             Settings.Secure.putStringForUser(getContext().getContentResolver(),
5523                     Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
5524                     setting,
5525                     currentUser);
5526             getContext().sendBroadcastAsUser(new Intent(NotificationManager
5527                     .ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
5528                 .setPackage(pkg)
5529                 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), new UserHandle(currentUser), null);
5530         }
5531
5532         public ArraySet<String> getGrantedPackages() {
5533             final ArraySet<String> pkgs = new ArraySet<>();
5534
5535             long identity = Binder.clearCallingIdentity();
5536             try {
5537                 final String setting = Settings.Secure.getStringForUser(
5538                         getContext().getContentResolver(),
5539                         Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
5540                         ActivityManager.getCurrentUser());
5541                 if (setting != null) {
5542                     final String[] tokens = setting.split(SEPARATOR);
5543                     for (int i = 0; i < tokens.length; i++) {
5544                         String token = tokens[i];
5545                         if (token != null) {
5546                             token = token.trim();
5547                         }
5548                         if (TextUtils.isEmpty(token)) {
5549                             continue;
5550                         }
5551                         pkgs.add(token);
5552                     }
5553                 }
5554             } finally {
5555                 Binder.restoreCallingIdentity(identity);
5556             }
5557             return pkgs;
5558         }
5559
5560         public String[] getRequestingPackages() throws RemoteException {
5561             final ParceledListSlice list = mPackageManager
5562                     .getPackagesHoldingPermissions(PERM, 0 /*flags*/,
5563                             ActivityManager.getCurrentUser());
5564             final List<PackageInfo> pkgs = list.getList();
5565             if (pkgs == null || pkgs.isEmpty()) return new String[0];
5566             final int N = pkgs.size();
5567             final String[] rt = new String[N];
5568             for (int i = 0; i < N; i++) {
5569                 rt[i] = pkgs.get(i).packageName;
5570             }
5571             return rt;
5572         }
5573     }
5574 }