OSDN Git Service

Fix ClipboardService device lock check for cross profile am: 0595b5a94b
[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.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
20 import static android.service.notification.NotificationListenerService.TRIM_FULL;
21 import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
22 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
23 import static org.xmlpull.v1.XmlPullParser.END_TAG;
24 import static org.xmlpull.v1.XmlPullParser.START_TAG;
25
26 import android.app.ActivityManager;
27 import android.app.ActivityManagerNative;
28 import android.app.AppGlobals;
29 import android.app.AppOpsManager;
30 import android.app.IActivityManager;
31 import android.app.INotificationManager;
32 import android.app.ITransientNotification;
33 import android.app.Notification;
34 import android.app.NotificationManager;
35 import android.app.NotificationManager.Policy;
36 import android.app.PendingIntent;
37 import android.app.StatusBarManager;
38 import android.app.backup.BackupManager;
39 import android.app.usage.UsageEvents;
40 import android.app.usage.UsageStatsManagerInternal;
41 import android.content.BroadcastReceiver;
42 import android.content.ComponentName;
43 import android.content.ContentResolver;
44 import android.content.Context;
45 import android.content.Intent;
46 import android.content.IntentFilter;
47 import android.content.pm.ApplicationInfo;
48 import android.content.pm.IPackageManager;
49 import android.content.pm.PackageInfo;
50 import android.content.pm.PackageManager;
51 import android.content.pm.PackageManager.NameNotFoundException;
52 import android.content.pm.ParceledListSlice;
53 import android.content.pm.UserInfo;
54 import android.content.res.Resources;
55 import android.database.ContentObserver;
56 import android.media.AudioAttributes;
57 import android.media.AudioManager;
58 import android.media.AudioManagerInternal;
59 import android.media.AudioSystem;
60 import android.media.IRingtonePlayer;
61 import android.net.Uri;
62 import android.os.Binder;
63 import android.os.Build;
64 import android.os.Bundle;
65 import android.os.Environment;
66 import android.os.Handler;
67 import android.os.HandlerThread;
68 import android.os.IBinder;
69 import android.os.IInterface;
70 import android.os.Looper;
71 import android.os.Message;
72 import android.os.Process;
73 import android.os.RemoteException;
74 import android.os.SystemProperties;
75 import android.os.UserHandle;
76 import android.os.UserManager;
77 import android.os.Vibrator;
78 import android.provider.Settings;
79 import android.service.notification.Condition;
80 import android.service.notification.IConditionListener;
81 import android.service.notification.IConditionProvider;
82 import android.service.notification.INotificationListener;
83 import android.service.notification.IStatusBarNotificationHolder;
84 import android.service.notification.NotificationListenerService;
85 import android.service.notification.NotificationRankingUpdate;
86 import android.service.notification.StatusBarNotification;
87 import android.service.notification.ZenModeConfig;
88 import android.telephony.PhoneStateListener;
89 import android.telephony.TelephonyManager;
90 import android.text.TextUtils;
91 import android.util.ArrayMap;
92 import android.util.ArraySet;
93 import android.util.AtomicFile;
94 import android.util.Log;
95 import android.util.Slog;
96 import android.util.Xml;
97 import android.view.accessibility.AccessibilityEvent;
98 import android.view.accessibility.AccessibilityManager;
99 import android.widget.Toast;
100
101 import com.android.internal.R;
102 import com.android.internal.statusbar.NotificationVisibility;
103 import com.android.internal.util.FastXmlSerializer;
104 import com.android.server.EventLogTags;
105 import com.android.server.LocalServices;
106 import com.android.server.SystemService;
107 import com.android.server.lights.Light;
108 import com.android.server.lights.LightsManager;
109 import com.android.server.notification.ManagedServices.ManagedServiceInfo;
110 import com.android.server.notification.ManagedServices.UserProfiles;
111 import com.android.server.statusbar.StatusBarManagerInternal;
112
113 import libcore.io.IoUtils;
114
115 import org.json.JSONArray;
116 import org.json.JSONException;
117 import org.json.JSONObject;
118 import org.xmlpull.v1.XmlPullParser;
119 import org.xmlpull.v1.XmlPullParserException;
120 import org.xmlpull.v1.XmlSerializer;
121
122 import java.io.ByteArrayInputStream;
123 import java.io.ByteArrayOutputStream;
124 import java.io.File;
125 import java.io.FileDescriptor;
126 import java.io.FileInputStream;
127 import java.io.FileNotFoundException;
128 import java.io.FileOutputStream;
129 import java.io.IOException;
130 import java.io.InputStream;
131 import java.io.OutputStream;
132 import java.io.PrintWriter;
133 import java.nio.charset.StandardCharsets;
134 import java.util.ArrayDeque;
135 import java.util.ArrayList;
136 import java.util.HashSet;
137 import java.util.Iterator;
138 import java.util.List;
139 import java.util.Map.Entry;
140 import java.util.Objects;
141
142 /** {@hide} */
143 public class NotificationManagerService extends SystemService {
144     static final String TAG = "NotificationService";
145     static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
146     public static final boolean ENABLE_CHILD_NOTIFICATIONS = Build.IS_DEBUGGABLE
147             && SystemProperties.getBoolean("debug.child_notifs", false);
148
149     static final int MAX_PACKAGE_NOTIFICATIONS = 50;
150
151     // message codes
152     static final int MESSAGE_TIMEOUT = 2;
153     static final int MESSAGE_SAVE_POLICY_FILE = 3;
154     static final int MESSAGE_RECONSIDER_RANKING = 4;
155     static final int MESSAGE_RANKING_CONFIG_CHANGE = 5;
156     static final int MESSAGE_SEND_RANKING_UPDATE = 6;
157     static final int MESSAGE_LISTENER_HINTS_CHANGED = 7;
158     static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 8;
159
160     static final int LONG_DELAY = 3500; // 3.5 seconds
161     static final int SHORT_DELAY = 2000; // 2 seconds
162
163     static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
164
165     static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
166
167     static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
168     static final boolean SCORE_ONGOING_HIGHER = false;
169
170     static final int JUNK_SCORE = -1000;
171     static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10;
172     static final int SCORE_DISPLAY_THRESHOLD = Notification.PRIORITY_MIN * NOTIFICATION_PRIORITY_MULTIPLIER;
173
174     // Notifications with scores below this will not interrupt the user, either via LED or
175     // sound or vibration
176     static final int SCORE_INTERRUPTION_THRESHOLD =
177             Notification.PRIORITY_LOW * NOTIFICATION_PRIORITY_MULTIPLIER;
178
179     static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true;
180     static final boolean ENABLE_BLOCKED_TOASTS = true;
181
182     // When #matchesCallFilter is called from the ringer, wait at most
183     // 3s to resolve the contacts. This timeout is required since
184     // ContactsProvider might take a long time to start up.
185     //
186     // Return STARRED_CONTACT when the timeout is hit in order to avoid
187     // missed calls in ZEN mode "Important".
188     static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
189     static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
190             ValidateNotificationPeople.STARRED_CONTACT;
191
192     /** notification_enqueue status value for a newly enqueued notification. */
193     private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
194
195     /** notification_enqueue status value for an existing notification. */
196     private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
197
198     /** notification_enqueue status value for an ignored notification. */
199     private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
200
201     private IActivityManager mAm;
202     AudioManager mAudioManager;
203     AudioManagerInternal mAudioManagerInternal;
204     StatusBarManagerInternal mStatusBar;
205     Vibrator mVibrator;
206
207     final IBinder mForegroundToken = new Binder();
208     private WorkerHandler mHandler;
209     private final HandlerThread mRankingThread = new HandlerThread("ranker",
210             Process.THREAD_PRIORITY_BACKGROUND);
211
212     private Light mNotificationLight;
213     Light mAttentionLight;
214     private int mDefaultNotificationColor;
215     private int mDefaultNotificationLedOn;
216
217     private int mDefaultNotificationLedOff;
218     private long[] mDefaultVibrationPattern;
219
220     private long[] mFallbackVibrationPattern;
221     private boolean mUseAttentionLight;
222     boolean mSystemReady;
223
224     private boolean mDisableNotificationEffects;
225     private int mCallState;
226     private String mSoundNotificationKey;
227     private String mVibrateNotificationKey;
228
229     private final ArraySet<ManagedServiceInfo> mListenersDisablingEffects = new ArraySet<>();
230     private ComponentName mEffectsSuppressor;
231     private int mListenerHints;  // right now, all hints are global
232     private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
233
234     // for enabling and disabling notification pulse behavior
235     private boolean mScreenOn = true;
236     private boolean mInCall = false;
237     private boolean mNotificationPulseEnabled;
238
239     // used as a mutex for access to all active notifications & listeners
240     final ArrayList<NotificationRecord> mNotificationList =
241             new ArrayList<NotificationRecord>();
242     final ArrayMap<String, NotificationRecord> mNotificationsByKey =
243             new ArrayMap<String, NotificationRecord>();
244     final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();
245     final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
246     final PolicyAccess mPolicyAccess = new PolicyAccess();
247
248     // The last key in this list owns the hardware.
249     ArrayList<String> mLights = new ArrayList<>();
250
251     private AppOpsManager mAppOps;
252     private UsageStatsManagerInternal mAppUsageStats;
253
254     private Archive mArchive;
255
256     // Persistent storage for notification policy
257     private AtomicFile mPolicyFile;
258
259     // Temporary holder for <blocked-packages> config coming from old policy files.
260     private HashSet<String> mBlockedPackages = new HashSet<String>();
261
262     private static final int DB_VERSION = 1;
263
264     private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
265     private static final String ATTR_VERSION = "version";
266
267     // Obsolete:  converted if present, but not resaved to disk.
268     private static final String TAG_BLOCKED_PKGS = "blocked-packages";
269     private static final String TAG_PACKAGE = "package";
270     private static final String ATTR_NAME = "name";
271
272     private RankingHelper mRankingHelper;
273
274     private final UserProfiles mUserProfiles = new UserProfiles();
275     private NotificationListeners mListeners;
276     private ConditionProviders mConditionProviders;
277     private NotificationUsageStats mUsageStats;
278
279     private static final int MY_UID = Process.myUid();
280     private static final int MY_PID = Process.myPid();
281     private static final int REASON_DELEGATE_CLICK = 1;
282     private static final int REASON_DELEGATE_CANCEL = 2;
283     private static final int REASON_DELEGATE_CANCEL_ALL = 3;
284     private static final int REASON_DELEGATE_ERROR = 4;
285     private static final int REASON_PACKAGE_CHANGED = 5;
286     private static final int REASON_USER_STOPPED = 6;
287     private static final int REASON_PACKAGE_BANNED = 7;
288     private static final int REASON_NOMAN_CANCEL = 8;
289     private static final int REASON_NOMAN_CANCEL_ALL = 9;
290     private static final int REASON_LISTENER_CANCEL = 10;
291     private static final int REASON_LISTENER_CANCEL_ALL = 11;
292     private static final int REASON_GROUP_SUMMARY_CANCELED = 12;
293     private static final int REASON_GROUP_OPTIMIZATION = 13;
294
295     private static class Archive {
296         final int mBufferSize;
297         final ArrayDeque<StatusBarNotification> mBuffer;
298
299         public Archive(int size) {
300             mBufferSize = size;
301             mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
302         }
303
304         public String toString() {
305             final StringBuilder sb = new StringBuilder();
306             final int N = mBuffer.size();
307             sb.append("Archive (");
308             sb.append(N);
309             sb.append(" notification");
310             sb.append((N==1)?")":"s)");
311             return sb.toString();
312         }
313
314         public void record(StatusBarNotification nr) {
315             if (mBuffer.size() == mBufferSize) {
316                 mBuffer.removeFirst();
317             }
318
319             // We don't want to store the heavy bits of the notification in the archive,
320             // but other clients in the system process might be using the object, so we
321             // store a (lightened) copy.
322             mBuffer.addLast(nr.cloneLight());
323         }
324
325         public Iterator<StatusBarNotification> descendingIterator() {
326             return mBuffer.descendingIterator();
327         }
328
329         public StatusBarNotification[] getArray(int count) {
330             if (count == 0) count = mBufferSize;
331             final StatusBarNotification[] a
332                     = new StatusBarNotification[Math.min(count, mBuffer.size())];
333             Iterator<StatusBarNotification> iter = descendingIterator();
334             int i=0;
335             while (iter.hasNext() && i < count) {
336                 a[i++] = iter.next();
337             }
338             return a;
339         }
340
341     }
342
343     private void readPolicyXml(InputStream stream, boolean forRestore)
344             throws XmlPullParserException, NumberFormatException, IOException {
345         final XmlPullParser parser = Xml.newPullParser();
346         parser.setInput(stream, StandardCharsets.UTF_8.name());
347
348         int type;
349         String tag;
350         int version = DB_VERSION;
351         while ((type = parser.next()) != END_DOCUMENT) {
352             tag = parser.getName();
353             if (type == START_TAG) {
354                 if (TAG_NOTIFICATION_POLICY.equals(tag)) {
355                     version = Integer.parseInt(
356                             parser.getAttributeValue(null, ATTR_VERSION));
357                 } else if (TAG_BLOCKED_PKGS.equals(tag)) {
358                     while ((type = parser.next()) != END_DOCUMENT) {
359                         tag = parser.getName();
360                         if (TAG_PACKAGE.equals(tag)) {
361                             mBlockedPackages.add(
362                                     parser.getAttributeValue(null, ATTR_NAME));
363                         } else if (TAG_BLOCKED_PKGS.equals(tag) && type == END_TAG) {
364                             break;
365                         }
366                     }
367                 }
368             }
369             mZenModeHelper.readXml(parser, forRestore);
370             mRankingHelper.readXml(parser, forRestore);
371         }
372     }
373
374     private void loadPolicyFile() {
375         if (DBG) Slog.d(TAG, "loadPolicyFile");
376         synchronized(mPolicyFile) {
377             mBlockedPackages.clear();
378
379             FileInputStream infile = null;
380             try {
381                 infile = mPolicyFile.openRead();
382                 readPolicyXml(infile, false /*forRestore*/);
383             } catch (FileNotFoundException e) {
384                 // No data yet
385             } catch (IOException e) {
386                 Log.wtf(TAG, "Unable to read notification policy", e);
387             } catch (NumberFormatException e) {
388                 Log.wtf(TAG, "Unable to parse notification policy", e);
389             } catch (XmlPullParserException e) {
390                 Log.wtf(TAG, "Unable to parse notification policy", e);
391             } finally {
392                 IoUtils.closeQuietly(infile);
393             }
394         }
395     }
396
397     public void savePolicyFile() {
398         mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
399         mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
400     }
401
402     private void handleSavePolicyFile() {
403         if (DBG) Slog.d(TAG, "handleSavePolicyFile");
404         synchronized (mPolicyFile) {
405             final FileOutputStream stream;
406             try {
407                 stream = mPolicyFile.startWrite();
408             } catch (IOException e) {
409                 Slog.w(TAG, "Failed to save policy file", e);
410                 return;
411             }
412
413             try {
414                 writePolicyXml(stream, false /*forBackup*/);
415                 mPolicyFile.finishWrite(stream);
416             } catch (IOException e) {
417                 Slog.w(TAG, "Failed to save policy file, restoring backup", e);
418                 mPolicyFile.failWrite(stream);
419             }
420         }
421         BackupManager.dataChanged(getContext().getPackageName());
422     }
423
424     private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
425         final XmlSerializer out = new FastXmlSerializer();
426         out.setOutput(stream, StandardCharsets.UTF_8.name());
427         out.startDocument(null, true);
428         out.startTag(null, TAG_NOTIFICATION_POLICY);
429         out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
430         mZenModeHelper.writeXml(out, forBackup);
431         mRankingHelper.writeXml(out, forBackup);
432         out.endTag(null, TAG_NOTIFICATION_POLICY);
433         out.endDocument();
434     }
435
436     /** Use this when you actually want to post a notification or toast.
437      *
438      * Unchecked. Not exposed via Binder, but can be called in the course of enqueue*().
439      */
440     private boolean noteNotificationOp(String pkg, int uid) {
441         if (mAppOps.noteOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
442                 != AppOpsManager.MODE_ALLOWED) {
443             Slog.v(TAG, "notifications are disabled by AppOps for " + pkg);
444             return false;
445         }
446         return true;
447     }
448
449     /** Use this to check if a package can post a notification or toast. */
450     private boolean checkNotificationOp(String pkg, int uid) {
451         return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
452                 == AppOpsManager.MODE_ALLOWED;
453     }
454
455     private static final class ToastRecord
456     {
457         final int pid;
458         final String pkg;
459         final ITransientNotification callback;
460         int duration;
461
462         ToastRecord(int pid, String pkg, ITransientNotification callback, int duration)
463         {
464             this.pid = pid;
465             this.pkg = pkg;
466             this.callback = callback;
467             this.duration = duration;
468         }
469
470         void update(int duration) {
471             this.duration = duration;
472         }
473
474         void dump(PrintWriter pw, String prefix, DumpFilter filter) {
475             if (filter != null && !filter.matches(pkg)) return;
476             pw.println(prefix + this);
477         }
478
479         @Override
480         public final String toString()
481         {
482             return "ToastRecord{"
483                 + Integer.toHexString(System.identityHashCode(this))
484                 + " pkg=" + pkg
485                 + " callback=" + callback
486                 + " duration=" + duration;
487         }
488     }
489
490     private final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
491
492         @Override
493         public void onSetDisabled(int status) {
494             synchronized (mNotificationList) {
495                 mDisableNotificationEffects =
496                         (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
497                 if (disableNotificationEffects(null) != null) {
498                     // cancel whatever's going on
499                     long identity = Binder.clearCallingIdentity();
500                     try {
501                         final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
502                         if (player != null) {
503                             player.stopAsync();
504                         }
505                     } catch (RemoteException e) {
506                     } finally {
507                         Binder.restoreCallingIdentity(identity);
508                     }
509
510                     identity = Binder.clearCallingIdentity();
511                     try {
512                         mVibrator.cancel();
513                     } finally {
514                         Binder.restoreCallingIdentity(identity);
515                     }
516                 }
517             }
518         }
519
520         @Override
521         public void onClearAll(int callingUid, int callingPid, int userId) {
522             synchronized (mNotificationList) {
523                 cancelAllLocked(callingUid, callingPid, userId, REASON_DELEGATE_CANCEL_ALL, null,
524                         /*includeCurrentProfiles*/ true);
525             }
526         }
527
528         @Override
529         public void onNotificationClick(int callingUid, int callingPid, String key) {
530             synchronized (mNotificationList) {
531                 NotificationRecord r = mNotificationsByKey.get(key);
532                 if (r == null) {
533                     Log.w(TAG, "No notification with key: " + key);
534                     return;
535                 }
536                 final long now = System.currentTimeMillis();
537                 EventLogTags.writeNotificationClicked(key,
538                         r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
539
540                 StatusBarNotification sbn = r.sbn;
541                 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
542                         sbn.getId(), Notification.FLAG_AUTO_CANCEL,
543                         Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
544                         REASON_DELEGATE_CLICK, null);
545             }
546         }
547
548         @Override
549         public void onNotificationActionClick(int callingUid, int callingPid, String key,
550                 int actionIndex) {
551             synchronized (mNotificationList) {
552                 NotificationRecord r = mNotificationsByKey.get(key);
553                 if (r == null) {
554                     Log.w(TAG, "No notification with key: " + key);
555                     return;
556                 }
557                 final long now = System.currentTimeMillis();
558                 EventLogTags.writeNotificationActionClicked(key, actionIndex,
559                         r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
560                 // TODO: Log action click via UsageStats.
561             }
562         }
563
564         @Override
565         public void onNotificationClear(int callingUid, int callingPid,
566                 String pkg, String tag, int id, int userId) {
567             cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
568                     Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
569                     true, userId, REASON_DELEGATE_CANCEL, null);
570         }
571
572         @Override
573         public void onPanelRevealed(boolean clearEffects, int items) {
574             EventLogTags.writeNotificationPanelRevealed(items);
575             if (clearEffects) {
576                 clearEffects();
577             }
578         }
579
580         @Override
581         public void onPanelHidden() {
582             EventLogTags.writeNotificationPanelHidden();
583         }
584
585         @Override
586         public void clearEffects() {
587             synchronized (mNotificationList) {
588                 if (DBG) Slog.d(TAG, "clearEffects");
589
590                 // sound
591                 mSoundNotificationKey = null;
592
593                 long identity = Binder.clearCallingIdentity();
594                 try {
595                     final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
596                     if (player != null) {
597                         player.stopAsync();
598                     }
599                 } catch (RemoteException e) {
600                 } finally {
601                     Binder.restoreCallingIdentity(identity);
602                 }
603
604                 // vibrate
605                 mVibrateNotificationKey = null;
606                 identity = Binder.clearCallingIdentity();
607                 try {
608                     mVibrator.cancel();
609                 } finally {
610                     Binder.restoreCallingIdentity(identity);
611                 }
612
613                 // light
614                 mLights.clear();
615                 updateLightsLocked();
616             }
617         }
618
619         @Override
620         public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
621                 int uid, int initialPid, String message, int userId) {
622             Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
623                     + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
624             cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
625                     REASON_DELEGATE_ERROR, null);
626             long ident = Binder.clearCallingIdentity();
627             try {
628                 ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg,
629                         "Bad notification posted from package " + pkg
630                         + ": " + message);
631             } catch (RemoteException e) {
632             }
633             Binder.restoreCallingIdentity(ident);
634         }
635
636         @Override
637         public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
638                 NotificationVisibility[] noLongerVisibleKeys) {
639             synchronized (mNotificationList) {
640                 for (NotificationVisibility nv : newlyVisibleKeys) {
641                     NotificationRecord r = mNotificationsByKey.get(nv.key);
642                     if (r == null) continue;
643                     r.setVisibility(true, nv.rank);
644                     nv.recycle();
645                 }
646                 // Note that we might receive this event after notifications
647                 // have already left the system, e.g. after dismissing from the
648                 // shade. Hence not finding notifications in
649                 // mNotificationsByKey is not an exceptional condition.
650                 for (NotificationVisibility nv : noLongerVisibleKeys) {
651                     NotificationRecord r = mNotificationsByKey.get(nv.key);
652                     if (r == null) continue;
653                     r.setVisibility(false, nv.rank);
654                     nv.recycle();
655                 }
656             }
657         }
658
659         @Override
660         public void onNotificationExpansionChanged(String key,
661                 boolean userAction, boolean expanded) {
662             synchronized (mNotificationList) {
663                 NotificationRecord r = mNotificationsByKey.get(key);
664                 if (r != null) {
665                     r.stats.onExpansionChanged(userAction, expanded);
666                     final long now = System.currentTimeMillis();
667                     EventLogTags.writeNotificationExpansion(key,
668                             userAction ? 1 : 0, expanded ? 1 : 0,
669                             r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
670                 }
671             }
672         }
673     };
674
675     private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
676         @Override
677         public void onReceive(Context context, Intent intent) {
678             String action = intent.getAction();
679             if (action == null) {
680                 return;
681             }
682
683             boolean queryRestart = false;
684             boolean queryRemove = false;
685             boolean packageChanged = false;
686             boolean cancelNotifications = true;
687
688             if (action.equals(Intent.ACTION_PACKAGE_ADDED)
689                     || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
690                     || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
691                     || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
692                     || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
693                     || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
694                 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
695                         UserHandle.USER_ALL);
696                 String pkgList[] = null;
697                 boolean queryReplace = queryRemove &&
698                         intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
699                 if (DBG) Slog.i(TAG, "action=" + action + " queryReplace=" + queryReplace);
700                 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
701                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
702                 } else if (queryRestart) {
703                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
704                 } else {
705                     Uri uri = intent.getData();
706                     if (uri == null) {
707                         return;
708                     }
709                     String pkgName = uri.getSchemeSpecificPart();
710                     if (pkgName == null) {
711                         return;
712                     }
713                     if (packageChanged) {
714                         // We cancel notifications for packages which have just been disabled
715                         try {
716                             final IPackageManager pm = AppGlobals.getPackageManager();
717                             final int enabled = pm.getApplicationEnabledSetting(pkgName,
718                                     changeUserId != UserHandle.USER_ALL ? changeUserId :
719                                     UserHandle.USER_OWNER);
720                             if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
721                                     || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
722                                 cancelNotifications = false;
723                             }
724                         } catch (IllegalArgumentException e) {
725                             // Package doesn't exist; probably racing with uninstall.
726                             // cancelNotifications is already true, so nothing to do here.
727                             if (DBG) {
728                                 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
729                             }
730                         } catch (RemoteException e) {
731                             // Failed to talk to PackageManagerService Should never happen!
732                         }
733                     }
734                     pkgList = new String[]{pkgName};
735                 }
736
737                 if (pkgList != null && (pkgList.length > 0)) {
738                     for (String pkgName : pkgList) {
739                         if (cancelNotifications) {
740                             cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart,
741                                     changeUserId, REASON_PACKAGE_CHANGED, null);
742                         }
743                     }
744                 }
745                 mListeners.onPackagesChanged(queryReplace, pkgList);
746                 mConditionProviders.onPackagesChanged(queryReplace, pkgList);
747                 mRankingHelper.onPackagesChanged(queryReplace, pkgList);
748             }
749         }
750     };
751
752     private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
753         @Override
754         public void onReceive(Context context, Intent intent) {
755             String action = intent.getAction();
756
757             if (action.equals(Intent.ACTION_SCREEN_ON)) {
758                 // Keep track of screen on/off state, but do not turn off the notification light
759                 // until user passes through the lock screen or views the notification.
760                 mScreenOn = true;
761                 updateNotificationPulse();
762             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
763                 mScreenOn = false;
764                 updateNotificationPulse();
765             } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
766                 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
767                         .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
768                 updateNotificationPulse();
769             } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
770                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
771                 if (userHandle >= 0) {
772                     cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
773                             REASON_USER_STOPPED, null);
774                 }
775             } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
776                 // turn off LED when user passes through lock screen
777                 mNotificationLight.turnOff();
778                 mStatusBar.notificationLightOff();
779             } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
780                 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
781                 // reload per-user settings
782                 mSettingsObserver.update(null);
783                 mUserProfiles.updateCache(context);
784                 // Refresh managed services
785                 mConditionProviders.onUserSwitched(user);
786                 mListeners.onUserSwitched(user);
787                 mZenModeHelper.onUserSwitched(user);
788             } else if (action.equals(Intent.ACTION_USER_ADDED)) {
789                 mUserProfiles.updateCache(context);
790             } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
791                 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
792                 mZenModeHelper.onUserRemoved(user);
793             }
794         }
795     };
796
797     private final class SettingsObserver extends ContentObserver {
798         private final Uri NOTIFICATION_LIGHT_PULSE_URI
799                 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
800
801         SettingsObserver(Handler handler) {
802             super(handler);
803         }
804
805         void observe() {
806             ContentResolver resolver = getContext().getContentResolver();
807             resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
808                     false, this, UserHandle.USER_ALL);
809             update(null);
810         }
811
812         @Override public void onChange(boolean selfChange, Uri uri) {
813             update(uri);
814         }
815
816         public void update(Uri uri) {
817             ContentResolver resolver = getContext().getContentResolver();
818             if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
819                 boolean pulseEnabled = Settings.System.getInt(resolver,
820                             Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
821                 if (mNotificationPulseEnabled != pulseEnabled) {
822                     mNotificationPulseEnabled = pulseEnabled;
823                     updateNotificationPulse();
824                 }
825             }
826         }
827     }
828
829     private SettingsObserver mSettingsObserver;
830     private ZenModeHelper mZenModeHelper;
831
832     private final Runnable mBuzzBeepBlinked = new Runnable() {
833         @Override
834         public void run() {
835             mStatusBar.buzzBeepBlinked();
836         }
837     };
838
839     static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
840         int[] ar = r.getIntArray(resid);
841         if (ar == null) {
842             return def;
843         }
844         final int len = ar.length > maxlen ? maxlen : ar.length;
845         long[] out = new long[len];
846         for (int i=0; i<len; i++) {
847             out[i] = ar[i];
848         }
849         return out;
850     }
851
852     public NotificationManagerService(Context context) {
853         super(context);
854     }
855
856     @Override
857     public void onStart() {
858         Resources resources = getContext().getResources();
859
860         mAm = ActivityManagerNative.getDefault();
861         mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
862         mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
863         mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
864
865         mHandler = new WorkerHandler();
866         mRankingThread.start();
867         String[] extractorNames;
868         try {
869             extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
870         } catch (Resources.NotFoundException e) {
871             extractorNames = new String[0];
872         }
873         mUsageStats = new NotificationUsageStats(getContext());
874         mRankingHelper = new RankingHelper(getContext(),
875                 new RankingWorkerHandler(mRankingThread.getLooper()),
876                 mUsageStats,
877                 extractorNames);
878         mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles);
879         mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
880         mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
881             @Override
882             public void onConfigChanged() {
883                 savePolicyFile();
884             }
885
886             @Override
887             void onZenModeChanged() {
888                 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
889                 synchronized(mNotificationList) {
890                     updateInterruptionFilterLocked();
891                 }
892             }
893
894             @Override
895             void onPolicyChanged() {
896                 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
897             }
898         });
899         final File systemDir = new File(Environment.getDataDirectory(), "system");
900         mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
901
902         importOldBlockDb();
903
904         mListeners = new NotificationListeners();
905         mStatusBar = getLocalService(StatusBarManagerInternal.class);
906         mStatusBar.setNotificationDelegate(mNotificationDelegate);
907
908         final LightsManager lights = getLocalService(LightsManager.class);
909         mNotificationLight = lights.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
910         mAttentionLight = lights.getLight(LightsManager.LIGHT_ID_ATTENTION);
911
912         mDefaultNotificationColor = resources.getColor(
913                 R.color.config_defaultNotificationColor);
914         mDefaultNotificationLedOn = resources.getInteger(
915                 R.integer.config_defaultNotificationLedOn);
916         mDefaultNotificationLedOff = resources.getInteger(
917                 R.integer.config_defaultNotificationLedOff);
918
919         mDefaultVibrationPattern = getLongArray(resources,
920                 R.array.config_defaultNotificationVibePattern,
921                 VIBRATE_PATTERN_MAXLEN,
922                 DEFAULT_VIBRATE_PATTERN);
923
924         mFallbackVibrationPattern = getLongArray(resources,
925                 R.array.config_notificationFallbackVibePattern,
926                 VIBRATE_PATTERN_MAXLEN,
927                 DEFAULT_VIBRATE_PATTERN);
928
929         mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
930
931         // Don't start allowing notifications until the setup wizard has run once.
932         // After that, including subsequent boots, init with notifications turned on.
933         // This works on the first boot because the setup wizard will toggle this
934         // flag at least once and we'll go back to 0 after that.
935         if (0 == Settings.Global.getInt(getContext().getContentResolver(),
936                     Settings.Global.DEVICE_PROVISIONED, 0)) {
937             mDisableNotificationEffects = true;
938         }
939         mZenModeHelper.initZenMode();
940         mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
941
942         mUserProfiles.updateCache(getContext());
943         listenForCallState();
944
945         // register for various Intents
946         IntentFilter filter = new IntentFilter();
947         filter.addAction(Intent.ACTION_SCREEN_ON);
948         filter.addAction(Intent.ACTION_SCREEN_OFF);
949         filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
950         filter.addAction(Intent.ACTION_USER_PRESENT);
951         filter.addAction(Intent.ACTION_USER_STOPPED);
952         filter.addAction(Intent.ACTION_USER_SWITCHED);
953         filter.addAction(Intent.ACTION_USER_ADDED);
954         filter.addAction(Intent.ACTION_USER_REMOVED);
955         getContext().registerReceiver(mIntentReceiver, filter);
956
957         IntentFilter pkgFilter = new IntentFilter();
958         pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
959         pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
960         pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
961         pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
962         pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
963         pkgFilter.addDataScheme("package");
964         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
965                 null);
966
967         IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
968         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
969                 null);
970
971         mSettingsObserver = new SettingsObserver(mHandler);
972
973         mArchive = new Archive(resources.getInteger(
974                 R.integer.config_notificationServiceArchiveSize));
975
976         publishBinderService(Context.NOTIFICATION_SERVICE, mService);
977         publishLocalService(NotificationManagerInternal.class, mInternalService);
978     }
979
980     private void sendRegisteredOnlyBroadcast(String action) {
981         getContext().sendBroadcastAsUser(new Intent(action)
982                 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
983     }
984
985     /**
986      * Read the old XML-based app block database and import those blockages into the AppOps system.
987      */
988     private void importOldBlockDb() {
989         loadPolicyFile();
990
991         PackageManager pm = getContext().getPackageManager();
992         for (String pkg : mBlockedPackages) {
993             PackageInfo info = null;
994             try {
995                 info = pm.getPackageInfo(pkg, 0);
996                 setNotificationsEnabledForPackageImpl(pkg, info.applicationInfo.uid, false);
997             } catch (NameNotFoundException e) {
998                 // forget you
999             }
1000         }
1001         mBlockedPackages.clear();
1002     }
1003
1004     @Override
1005     public void onBootPhase(int phase) {
1006         if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1007             // no beeping until we're basically done booting
1008             mSystemReady = true;
1009
1010             // Grab our optional AudioService
1011             mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
1012             mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
1013             mZenModeHelper.onSystemReady();
1014         } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1015             // This observer will force an update when observe is called, causing us to
1016             // bind to listener services.
1017             mSettingsObserver.observe();
1018             mListeners.onBootPhaseAppsCanStart();
1019             mConditionProviders.onBootPhaseAppsCanStart();
1020         }
1021     }
1022
1023     void setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled) {
1024         Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
1025
1026         mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
1027                 enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
1028
1029         // Now, cancel any outstanding notifications that are part of a just-disabled app
1030         if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
1031             cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true, UserHandle.getUserId(uid),
1032                     REASON_PACKAGE_BANNED, null);
1033         }
1034     }
1035
1036     private void updateListenerHintsLocked() {
1037         final int hints = mListenersDisablingEffects.isEmpty() ? 0 : HINT_HOST_DISABLE_EFFECTS;
1038         if (hints == mListenerHints) return;
1039         ZenLog.traceListenerHintsChanged(mListenerHints, hints, mListenersDisablingEffects.size());
1040         mListenerHints = hints;
1041         scheduleListenerHintsChanged(hints);
1042     }
1043
1044     private void updateEffectsSuppressorLocked() {
1045         final ComponentName suppressor = !mListenersDisablingEffects.isEmpty()
1046                 ? mListenersDisablingEffects.valueAt(0).component : null;
1047         if (Objects.equals(suppressor, mEffectsSuppressor)) return;
1048         ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressor, suppressor);
1049         mEffectsSuppressor = suppressor;
1050         mZenModeHelper.setEffectsSuppressed(suppressor != null);
1051         sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
1052     }
1053
1054     private void updateInterruptionFilterLocked() {
1055         int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1056         if (interruptionFilter == mInterruptionFilter) return;
1057         mInterruptionFilter = interruptionFilter;
1058         scheduleInterruptionFilterChanged(interruptionFilter);
1059     }
1060
1061     private final IBinder mService = new INotificationManager.Stub() {
1062         // Toasts
1063         // ============================================================================
1064
1065         @Override
1066         public void enqueueToast(String pkg, ITransientNotification callback, int duration)
1067         {
1068             if (DBG) {
1069                 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1070                         + " duration=" + duration);
1071             }
1072
1073             if (pkg == null || callback == null) {
1074                 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1075                 return ;
1076             }
1077
1078             final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg));
1079
1080             if (ENABLE_BLOCKED_TOASTS && !noteNotificationOp(pkg, Binder.getCallingUid())) {
1081                 if (!isSystemToast) {
1082                     Slog.e(TAG, "Suppressing toast from package " + pkg + " by user request.");
1083                     return;
1084                 }
1085             }
1086
1087             synchronized (mToastQueue) {
1088                 int callingPid = Binder.getCallingPid();
1089                 long callingId = Binder.clearCallingIdentity();
1090                 try {
1091                     ToastRecord record;
1092                     int index = indexOfToastLocked(pkg, callback);
1093                     // If it's already in the queue, we update it in place, we don't
1094                     // move it to the end of the queue.
1095                     if (index >= 0) {
1096                         record = mToastQueue.get(index);
1097                         record.update(duration);
1098                     } else {
1099                         // Limit the number of toasts that any given package except the android
1100                         // package can enqueue.  Prevents DOS attacks and deals with leaks.
1101                         if (!isSystemToast) {
1102                             int count = 0;
1103                             final int N = mToastQueue.size();
1104                             for (int i=0; i<N; i++) {
1105                                  final ToastRecord r = mToastQueue.get(i);
1106                                  if (r.pkg.equals(pkg)) {
1107                                      count++;
1108                                      if (count >= MAX_PACKAGE_NOTIFICATIONS) {
1109                                          Slog.e(TAG, "Package has already posted " + count
1110                                                 + " toasts. Not showing more. Package=" + pkg);
1111                                          return;
1112                                      }
1113                                  }
1114                             }
1115                         }
1116
1117                         record = new ToastRecord(callingPid, pkg, callback, duration);
1118                         mToastQueue.add(record);
1119                         index = mToastQueue.size() - 1;
1120                         keepProcessAliveLocked(callingPid);
1121                     }
1122                     // If it's at index 0, it's the current toast.  It doesn't matter if it's
1123                     // new or just been updated.  Call back and tell it to show itself.
1124                     // If the callback fails, this will remove it from the list, so don't
1125                     // assume that it's valid after this.
1126                     if (index == 0) {
1127                         showNextToastLocked();
1128                     }
1129                 } finally {
1130                     Binder.restoreCallingIdentity(callingId);
1131                 }
1132             }
1133         }
1134
1135         @Override
1136         public void cancelToast(String pkg, ITransientNotification callback) {
1137             Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
1138
1139             if (pkg == null || callback == null) {
1140                 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
1141                 return ;
1142             }
1143
1144             synchronized (mToastQueue) {
1145                 long callingId = Binder.clearCallingIdentity();
1146                 try {
1147                     int index = indexOfToastLocked(pkg, callback);
1148                     if (index >= 0) {
1149                         cancelToastLocked(index);
1150                     } else {
1151                         Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
1152                                 + " callback=" + callback);
1153                     }
1154                 } finally {
1155                     Binder.restoreCallingIdentity(callingId);
1156                 }
1157             }
1158         }
1159
1160         @Override
1161         public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
1162                 Notification notification, int[] idOut, int userId) throws RemoteException {
1163             enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
1164                     Binder.getCallingPid(), tag, id, notification, idOut, userId);
1165         }
1166
1167         @Override
1168         public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
1169             checkCallerIsSystemOrSameApp(pkg);
1170             userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1171                     Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
1172             // Don't allow client applications to cancel foreground service notis.
1173             cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
1174                     Binder.getCallingUid() == Process.SYSTEM_UID
1175                     ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false, userId, REASON_NOMAN_CANCEL,
1176                     null);
1177         }
1178
1179         @Override
1180         public void cancelAllNotifications(String pkg, int userId) {
1181             checkCallerIsSystemOrSameApp(pkg);
1182
1183             userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1184                     Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
1185
1186             // Calling from user space, don't allow the canceling of actively
1187             // running foreground services.
1188             cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
1189                     pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
1190                     REASON_NOMAN_CANCEL_ALL, null);
1191         }
1192
1193         @Override
1194         public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
1195             checkCallerIsSystem();
1196
1197             setNotificationsEnabledForPackageImpl(pkg, uid, enabled);
1198         }
1199
1200         /**
1201          * Use this when you just want to know if notifications are OK for this package.
1202          */
1203         @Override
1204         public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
1205             checkCallerIsSystem();
1206             return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
1207                     == AppOpsManager.MODE_ALLOWED);
1208         }
1209
1210         @Override
1211         public void setPackagePriority(String pkg, int uid, int priority) {
1212             checkCallerIsSystem();
1213             mRankingHelper.setPackagePriority(pkg, uid, priority);
1214             savePolicyFile();
1215         }
1216
1217         @Override
1218         public int getPackagePriority(String pkg, int uid) {
1219             checkCallerIsSystem();
1220             return mRankingHelper.getPackagePriority(pkg, uid);
1221         }
1222
1223         @Override
1224         public void setPackagePeekable(String pkg, int uid, boolean peekable) {
1225             checkCallerIsSystem();
1226
1227             mRankingHelper.setPackagePeekable(pkg, uid, peekable);
1228         }
1229
1230         @Override
1231         public boolean getPackagePeekable(String pkg, int uid) {
1232             checkCallerIsSystem();
1233             return mRankingHelper.getPackagePeekable(pkg, uid);
1234         }
1235
1236         @Override
1237         public void setPackageVisibilityOverride(String pkg, int uid, int visibility) {
1238             checkCallerIsSystem();
1239             mRankingHelper.setPackageVisibilityOverride(pkg, uid, visibility);
1240             savePolicyFile();
1241         }
1242
1243         @Override
1244         public int getPackageVisibilityOverride(String pkg, int uid) {
1245             checkCallerIsSystem();
1246             return mRankingHelper.getPackageVisibilityOverride(pkg, uid);
1247         }
1248
1249         /**
1250          * System-only API for getting a list of current (i.e. not cleared) notifications.
1251          *
1252          * Requires ACCESS_NOTIFICATIONS which is signature|system.
1253          * @returns A list of all the notifications, in natural order.
1254          */
1255         @Override
1256         public StatusBarNotification[] getActiveNotifications(String callingPkg) {
1257             // enforce() will ensure the calling uid has the correct permission
1258             getContext().enforceCallingOrSelfPermission(
1259                     android.Manifest.permission.ACCESS_NOTIFICATIONS,
1260                     "NotificationManagerService.getActiveNotifications");
1261
1262             StatusBarNotification[] tmp = null;
1263             int uid = Binder.getCallingUid();
1264
1265             // noteOp will check to make sure the callingPkg matches the uid
1266             if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1267                     == AppOpsManager.MODE_ALLOWED) {
1268                 synchronized (mNotificationList) {
1269                     tmp = new StatusBarNotification[mNotificationList.size()];
1270                     final int N = mNotificationList.size();
1271                     for (int i=0; i<N; i++) {
1272                         tmp[i] = mNotificationList.get(i).sbn;
1273                     }
1274                 }
1275             }
1276             return tmp;
1277         }
1278
1279         /**
1280          * Public API for getting a list of current notifications for the calling package/uid.
1281          *
1282          * @returns A list of all the package's notifications, in natural order.
1283          */
1284         @Override
1285         public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
1286                 int incomingUserId) {
1287             checkCallerIsSystemOrSameApp(pkg);
1288             int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1289                     Binder.getCallingUid(), incomingUserId, true, false,
1290                     "getAppActiveNotifications", pkg);
1291
1292             final int N = mNotificationList.size();
1293             final ArrayList<StatusBarNotification> list = new ArrayList<StatusBarNotification>(N);
1294
1295             synchronized (mNotificationList) {
1296                 for (int i = 0; i < N; i++) {
1297                     final StatusBarNotification sbn = mNotificationList.get(i).sbn;
1298                     if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId) {
1299                         // We could pass back a cloneLight() but clients might get confused and
1300                         // try to send this thing back to notify() again, which would not work
1301                         // very well.
1302                         final StatusBarNotification sbnOut = new StatusBarNotification(
1303                                 sbn.getPackageName(),
1304                                 sbn.getOpPkg(),
1305                                 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
1306                                 0, // hide score from apps
1307                                 sbn.getNotification().clone(),
1308                                 sbn.getUser(), sbn.getPostTime());
1309                         list.add(sbnOut);
1310                     }
1311                 }
1312             }
1313
1314             return new ParceledListSlice<StatusBarNotification>(list);
1315         }
1316
1317         /**
1318          * System-only API for getting a list of recent (cleared, no longer shown) notifications.
1319          *
1320          * Requires ACCESS_NOTIFICATIONS which is signature|system.
1321          */
1322         @Override
1323         public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
1324             // enforce() will ensure the calling uid has the correct permission
1325             getContext().enforceCallingOrSelfPermission(
1326                     android.Manifest.permission.ACCESS_NOTIFICATIONS,
1327                     "NotificationManagerService.getHistoricalNotifications");
1328
1329             StatusBarNotification[] tmp = null;
1330             int uid = Binder.getCallingUid();
1331
1332             // noteOp will check to make sure the callingPkg matches the uid
1333             if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1334                     == AppOpsManager.MODE_ALLOWED) {
1335                 synchronized (mArchive) {
1336                     tmp = mArchive.getArray(count);
1337                 }
1338             }
1339             return tmp;
1340         }
1341
1342         /**
1343          * Register a listener binder directly with the notification manager.
1344          *
1345          * Only works with system callers. Apps should extend
1346          * {@link android.service.notification.NotificationListenerService}.
1347          */
1348         @Override
1349         public void registerListener(final INotificationListener listener,
1350                 final ComponentName component, final int userid) {
1351             enforceSystemOrSystemUI("INotificationManager.registerListener");
1352             mListeners.registerService(listener, component, userid);
1353         }
1354
1355         /**
1356          * Remove a listener binder directly
1357          */
1358         @Override
1359         public void unregisterListener(INotificationListener listener, int userid) {
1360             mListeners.unregisterService(listener, userid);
1361         }
1362
1363         /**
1364          * Allow an INotificationListener to simulate a "clear all" operation.
1365          *
1366          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
1367          *
1368          * @param token The binder for the listener, to check that the caller is allowed
1369          */
1370         @Override
1371         public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
1372             final int callingUid = Binder.getCallingUid();
1373             final int callingPid = Binder.getCallingPid();
1374             long identity = Binder.clearCallingIdentity();
1375             try {
1376                 synchronized (mNotificationList) {
1377                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1378                     if (keys != null) {
1379                         final int N = keys.length;
1380                         for (int i = 0; i < N; i++) {
1381                             NotificationRecord r = mNotificationsByKey.get(keys[i]);
1382                             if (r == null) continue;
1383                             final int userId = r.sbn.getUserId();
1384                             if (userId != info.userid && userId != UserHandle.USER_ALL &&
1385                                     !mUserProfiles.isCurrentProfile(userId)) {
1386                                 throw new SecurityException("Disallowed call from listener: "
1387                                         + info.service);
1388                             }
1389                             cancelNotificationFromListenerLocked(info, callingUid, callingPid,
1390                                     r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
1391                                     userId);
1392                         }
1393                     } else {
1394                         cancelAllLocked(callingUid, callingPid, info.userid,
1395                                 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
1396                     }
1397                 }
1398             } finally {
1399                 Binder.restoreCallingIdentity(identity);
1400             }
1401         }
1402
1403         @Override
1404         public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
1405             long identity = Binder.clearCallingIdentity();
1406             try {
1407                 synchronized (mNotificationList) {
1408                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1409                     if (keys != null) {
1410                         final int N = keys.length;
1411                         for (int i = 0; i < N; i++) {
1412                             NotificationRecord r = mNotificationsByKey.get(keys[i]);
1413                             if (r == null) continue;
1414                             final int userId = r.sbn.getUserId();
1415                             if (userId != info.userid && userId != UserHandle.USER_ALL &&
1416                                     !mUserProfiles.isCurrentProfile(userId)) {
1417                                 throw new SecurityException("Disallowed call from listener: "
1418                                         + info.service);
1419                             }
1420                             if (!r.isSeen()) {
1421                                 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
1422                                 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
1423                                         userId == UserHandle.USER_ALL ? UserHandle.USER_OWNER
1424                                                 : userId,
1425                                         UsageEvents.Event.USER_INTERACTION);
1426                                 r.setSeen();
1427                             }
1428                         }
1429                     }
1430                 }
1431             } finally {
1432                 Binder.restoreCallingIdentity(identity);
1433             }
1434         }
1435
1436         private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
1437                 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
1438             cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
1439                     Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
1440                     true,
1441                     userId, REASON_LISTENER_CANCEL, info);
1442         }
1443
1444         /**
1445          * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
1446          *
1447          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
1448          *
1449          * @param token The binder for the listener, to check that the caller is allowed
1450          */
1451         @Override
1452         public void cancelNotificationFromListener(INotificationListener token, String pkg,
1453                 String tag, int id) {
1454             final int callingUid = Binder.getCallingUid();
1455             final int callingPid = Binder.getCallingPid();
1456             long identity = Binder.clearCallingIdentity();
1457             try {
1458                 synchronized (mNotificationList) {
1459                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1460                     if (info.supportsProfiles()) {
1461                         Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
1462                                 + "from " + info.component
1463                                 + " use cancelNotification(key) instead.");
1464                     } else {
1465                         cancelNotificationFromListenerLocked(info, callingUid, callingPid,
1466                                 pkg, tag, id, info.userid);
1467                     }
1468                 }
1469             } finally {
1470                 Binder.restoreCallingIdentity(identity);
1471             }
1472         }
1473
1474         /**
1475          * Allow an INotificationListener to request the list of outstanding notifications seen by
1476          * the current user. Useful when starting up, after which point the listener callbacks
1477          * should be used.
1478          *
1479          * @param token The binder for the listener, to check that the caller is allowed
1480          * @param keys An array of notification keys to fetch, or null to fetch everything
1481          * @returns The return value will contain the notifications specified in keys, in that
1482          *      order, or if keys is null, all the notifications, in natural order.
1483          */
1484         @Override
1485         public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
1486                 INotificationListener token, String[] keys, int trim) {
1487             synchronized (mNotificationList) {
1488                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1489                 final boolean getKeys = keys != null;
1490                 final int N = getKeys ? keys.length : mNotificationList.size();
1491                 final ArrayList<StatusBarNotification> list
1492                         = new ArrayList<StatusBarNotification>(N);
1493                 for (int i=0; i<N; i++) {
1494                     final NotificationRecord r = getKeys
1495                             ? mNotificationsByKey.get(keys[i])
1496                             : mNotificationList.get(i);
1497                     if (r == null) continue;
1498                     StatusBarNotification sbn = r.sbn;
1499                     if (!isVisibleToListener(sbn, info)) continue;
1500                     StatusBarNotification sbnToSend =
1501                             (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
1502                     list.add(sbnToSend);
1503                 }
1504                 return new ParceledListSlice<StatusBarNotification>(list);
1505             }
1506         }
1507
1508         @Override
1509         public void requestHintsFromListener(INotificationListener token, int hints) {
1510             final long identity = Binder.clearCallingIdentity();
1511             try {
1512                 synchronized (mNotificationList) {
1513                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1514                     final boolean disableEffects = (hints & HINT_HOST_DISABLE_EFFECTS) != 0;
1515                     if (disableEffects) {
1516                         mListenersDisablingEffects.add(info);
1517                     } else {
1518                         mListenersDisablingEffects.remove(info);
1519                     }
1520                     updateListenerHintsLocked();
1521                     updateEffectsSuppressorLocked();
1522                 }
1523             } finally {
1524                 Binder.restoreCallingIdentity(identity);
1525             }
1526         }
1527
1528         @Override
1529         public int getHintsFromListener(INotificationListener token) {
1530             synchronized (mNotificationList) {
1531                 return mListenerHints;
1532             }
1533         }
1534
1535         @Override
1536         public void requestInterruptionFilterFromListener(INotificationListener token,
1537                 int interruptionFilter) throws RemoteException {
1538             final long identity = Binder.clearCallingIdentity();
1539             try {
1540                 synchronized (mNotificationList) {
1541                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1542                     mZenModeHelper.requestFromListener(info.component, interruptionFilter);
1543                     updateInterruptionFilterLocked();
1544                 }
1545             } finally {
1546                 Binder.restoreCallingIdentity(identity);
1547             }
1548         }
1549
1550         @Override
1551         public int getInterruptionFilterFromListener(INotificationListener token)
1552                 throws RemoteException {
1553             synchronized (mNotificationLight) {
1554                 return mInterruptionFilter;
1555             }
1556         }
1557
1558         @Override
1559         public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
1560                 throws RemoteException {
1561             synchronized (mNotificationList) {
1562                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1563                 if (info == null) return;
1564                 mListeners.setOnNotificationPostedTrimLocked(info, trim);
1565             }
1566         }
1567
1568         @Override
1569         public int getZenMode() {
1570             return mZenModeHelper.getZenMode();
1571         }
1572
1573         @Override
1574         public ZenModeConfig getZenModeConfig() {
1575             enforceSystemOrSystemUIOrVolume("INotificationManager.getZenModeConfig");
1576             return mZenModeHelper.getConfig();
1577         }
1578
1579         @Override
1580         public boolean setZenModeConfig(ZenModeConfig config, String reason) {
1581             checkCallerIsSystem();
1582             return mZenModeHelper.setConfig(config, reason);
1583         }
1584
1585         @Override
1586         public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
1587             enforceSystemOrSystemUIOrVolume("INotificationManager.setZenMode");
1588             final long identity = Binder.clearCallingIdentity();
1589             try {
1590                 mZenModeHelper.setManualZenMode(mode, conditionId, reason);
1591             } finally {
1592                 Binder.restoreCallingIdentity(identity);
1593             }
1594         }
1595
1596         @Override
1597         public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
1598             enforcePolicyAccess(pkg, "setInterruptionFilter");
1599             final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
1600             if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
1601             final long identity = Binder.clearCallingIdentity();
1602             try {
1603                 mZenModeHelper.setManualZenMode(zen, null, "setInterruptionFilter");
1604             } finally {
1605                 Binder.restoreCallingIdentity(identity);
1606             }
1607         }
1608
1609         @Override
1610         public void notifyConditions(final String pkg, IConditionProvider provider,
1611                 final Condition[] conditions) {
1612             final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
1613             checkCallerIsSystemOrSameApp(pkg);
1614             mHandler.post(new Runnable() {
1615                 @Override
1616                 public void run() {
1617                     mConditionProviders.notifyConditions(pkg, info, conditions);
1618                 }
1619             });
1620         }
1621
1622         @Override
1623         public void requestZenModeConditions(IConditionListener callback, int relevance) {
1624             enforceSystemOrSystemUIOrVolume("INotificationManager.requestZenModeConditions");
1625             mZenModeHelper.requestZenModeConditions(callback, relevance);
1626         }
1627
1628         private void enforceSystemOrSystemUIOrVolume(String message) {
1629             if (mAudioManagerInternal != null) {
1630                 final int vcuid = mAudioManagerInternal.getVolumeControllerUid();
1631                 if (vcuid > 0 && Binder.getCallingUid() == vcuid) {
1632                     return;
1633                 }
1634             }
1635             enforceSystemOrSystemUI(message);
1636         }
1637
1638         private void enforceSystemOrSystemUI(String message) {
1639             if (isCallerSystem()) return;
1640             getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
1641                     message);
1642         }
1643
1644         private void enforcePolicyAccess(String pkg, String method) {
1645             checkCallerIsSameApp(pkg);
1646             if (!checkPolicyAccess(pkg)) {
1647                 Slog.w(TAG, "Notification policy access denied calling " + method);
1648                 throw new SecurityException("Notification policy access denied");
1649             }
1650         }
1651
1652         private boolean checkPackagePolicyAccess(String pkg) {
1653             return mPolicyAccess.isPackageGranted(pkg);
1654         }
1655
1656         private boolean checkPolicyAccess(String pkg) {
1657             return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
1658         }
1659
1660         @Override
1661         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1662             if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1663                     != PackageManager.PERMISSION_GRANTED) {
1664                 pw.println("Permission Denial: can't dump NotificationManager from pid="
1665                         + Binder.getCallingPid()
1666                         + ", uid=" + Binder.getCallingUid());
1667                 return;
1668             }
1669
1670             final DumpFilter filter = DumpFilter.parseFromArguments(args);
1671             if (filter != null && filter.stats) {
1672                 dumpJson(pw, filter);
1673             } else {
1674                 dumpImpl(pw, filter);
1675             }
1676         }
1677
1678         @Override
1679         public ComponentName getEffectsSuppressor() {
1680             enforceSystemOrSystemUIOrVolume("INotificationManager.getEffectsSuppressor");
1681             return mEffectsSuppressor;
1682         }
1683
1684         @Override
1685         public boolean matchesCallFilter(Bundle extras) {
1686             enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
1687             return mZenModeHelper.matchesCallFilter(
1688                     UserHandle.getCallingUserHandle(),
1689                     extras,
1690                     mRankingHelper.findExtractor(ValidateNotificationPeople.class),
1691                     MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
1692                     MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
1693         }
1694
1695         @Override
1696         public boolean isSystemConditionProviderEnabled(String path) {
1697             enforceSystemOrSystemUIOrVolume("INotificationManager.isSystemConditionProviderEnabled");
1698             return mConditionProviders.isSystemProviderEnabled(path);
1699         }
1700
1701         // Backup/restore interface
1702         @Override
1703         public byte[] getBackupPayload(int user) {
1704             if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
1705             if (user != UserHandle.USER_OWNER) {
1706                 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
1707                 return null;
1708             }
1709             final ByteArrayOutputStream baos = new ByteArrayOutputStream();
1710             try {
1711                 writePolicyXml(baos, true /*forBackup*/);
1712                 return baos.toByteArray();
1713             } catch (IOException e) {
1714                 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
1715             }
1716             return null;
1717         }
1718
1719         @Override
1720         public void applyRestore(byte[] payload, int user) {
1721             if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
1722                     + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
1723             if (payload == null) {
1724                 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
1725                 return;
1726             }
1727             if (user != UserHandle.USER_OWNER) {
1728                 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
1729                 return;
1730             }
1731             final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
1732             try {
1733                 readPolicyXml(bais, true /*forRestore*/);
1734                 savePolicyFile();
1735             } catch (NumberFormatException | XmlPullParserException | IOException e) {
1736                 Slog.w(TAG, "applyRestore: error reading payload", e);
1737             }
1738         }
1739
1740         @Override
1741         public boolean isNotificationPolicyAccessGranted(String pkg) {
1742             return checkPolicyAccess(pkg);
1743         }
1744
1745         @Override
1746         public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {
1747             enforceSystemOrSystemUI("request policy access status for another package");
1748             return checkPackagePolicyAccess(pkg);
1749         }
1750
1751         @Override
1752         public String[] getPackagesRequestingNotificationPolicyAccess()
1753                 throws RemoteException {
1754             enforceSystemOrSystemUI("request policy access packages");
1755             final long identity = Binder.clearCallingIdentity();
1756             try {
1757                 return mPolicyAccess.getRequestingPackages();
1758             } finally {
1759                 Binder.restoreCallingIdentity(identity);
1760             }
1761         }
1762
1763         @Override
1764         public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
1765                 throws RemoteException {
1766             enforceSystemOrSystemUI("grant notification policy access");
1767             final long identity = Binder.clearCallingIdentity();
1768             try {
1769                 synchronized (mNotificationList) {
1770                     mPolicyAccess.put(pkg, granted);
1771                 }
1772             } finally {
1773                 Binder.restoreCallingIdentity(identity);
1774             }
1775         }
1776
1777         @Override
1778         public Policy getNotificationPolicy(String pkg) {
1779             enforcePolicyAccess(pkg, "getNotificationPolicy");
1780             final long identity = Binder.clearCallingIdentity();
1781             try {
1782                 return mZenModeHelper.getNotificationPolicy();
1783             } finally {
1784                 Binder.restoreCallingIdentity(identity);
1785             }
1786         }
1787
1788         @Override
1789         public void setNotificationPolicy(String pkg, Policy policy) {
1790             enforcePolicyAccess(pkg, "setNotificationPolicy");
1791             final long identity = Binder.clearCallingIdentity();
1792             try {
1793                 mZenModeHelper.setNotificationPolicy(policy);
1794             } finally {
1795                 Binder.restoreCallingIdentity(identity);
1796             }
1797         }
1798     };
1799
1800     private String disableNotificationEffects(NotificationRecord record) {
1801         if (mDisableNotificationEffects) {
1802             return "booleanState";
1803         }
1804         if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1805             return "listenerHints";
1806         }
1807         if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
1808             return "callState";
1809         }
1810         return null;
1811     };
1812
1813     private void dumpJson(PrintWriter pw, DumpFilter filter) {
1814         JSONObject dump = new JSONObject();
1815         try {
1816             dump.put("service", "Notification Manager");
1817             JSONArray bans = new JSONArray();
1818             try {
1819                 ArrayMap<Integer, ArrayList<String>> packageBans = getPackageBans(filter);
1820                 for (Integer userId : packageBans.keySet()) {
1821                     for (String packageName : packageBans.get(userId)) {
1822                         JSONObject ban = new JSONObject();
1823                         ban.put("userId", userId);
1824                         ban.put("packageName", packageName);
1825                         bans.put(ban);
1826                     }
1827                 }
1828             } catch (NameNotFoundException e) {
1829                 // pass
1830             }
1831             dump.put("bans", bans);
1832             dump.put("stats", mUsageStats.dumpJson(filter));
1833         } catch (JSONException e) {
1834             e.printStackTrace();
1835         }
1836         pw.println(dump);
1837     }
1838
1839     void dumpImpl(PrintWriter pw, DumpFilter filter) {
1840         pw.print("Current Notification Manager state");
1841         if (filter.filtered) {
1842             pw.print(" (filtered to "); pw.print(filter); pw.print(")");
1843         }
1844         pw.println(':');
1845         int N;
1846         final boolean zenOnly = filter.filtered && filter.zen;
1847
1848         if (!zenOnly) {
1849             synchronized (mToastQueue) {
1850                 N = mToastQueue.size();
1851                 if (N > 0) {
1852                     pw.println("  Toast Queue:");
1853                     for (int i=0; i<N; i++) {
1854                         mToastQueue.get(i).dump(pw, "    ", filter);
1855                     }
1856                     pw.println("  ");
1857                 }
1858             }
1859         }
1860
1861         synchronized (mNotificationList) {
1862             if (!zenOnly) {
1863                 N = mNotificationList.size();
1864                 if (N > 0) {
1865                     pw.println("  Notification List:");
1866                     for (int i=0; i<N; i++) {
1867                         final NotificationRecord nr = mNotificationList.get(i);
1868                         if (filter.filtered && !filter.matches(nr.sbn)) continue;
1869                         nr.dump(pw, "    ", getContext(), filter.redact);
1870                     }
1871                     pw.println("  ");
1872                 }
1873
1874                 if (!filter.filtered) {
1875                     N = mLights.size();
1876                     if (N > 0) {
1877                         pw.println("  Lights List:");
1878                         for (int i=0; i<N; i++) {
1879                             if (i == N - 1) {
1880                                 pw.print("  > ");
1881                             } else {
1882                                 pw.print("    ");
1883                             }
1884                             pw.println(mLights.get(i));
1885                         }
1886                         pw.println("  ");
1887                     }
1888                     pw.println("  mUseAttentionLight=" + mUseAttentionLight);
1889                     pw.println("  mNotificationPulseEnabled=" + mNotificationPulseEnabled);
1890                     pw.println("  mSoundNotificationKey=" + mSoundNotificationKey);
1891                     pw.println("  mVibrateNotificationKey=" + mVibrateNotificationKey);
1892                     pw.println("  mDisableNotificationEffects=" + mDisableNotificationEffects);
1893                     pw.println("  mCallState=" + callStateToString(mCallState));
1894                     pw.println("  mSystemReady=" + mSystemReady);
1895                 }
1896                 pw.println("  mArchive=" + mArchive.toString());
1897                 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
1898                 int i=0;
1899                 while (iter.hasNext()) {
1900                     final StatusBarNotification sbn = iter.next();
1901                     if (filter != null && !filter.matches(sbn)) continue;
1902                     pw.println("    " + sbn);
1903                     if (++i >= 5) {
1904                         if (iter.hasNext()) pw.println("    ...");
1905                         break;
1906                     }
1907                 }
1908             }
1909
1910             if (!zenOnly) {
1911                 pw.println("\n  Usage Stats:");
1912                 mUsageStats.dump(pw, "    ", filter);
1913             }
1914
1915             if (!filter.filtered || zenOnly) {
1916                 pw.println("\n  Zen Mode:");
1917                 pw.print("    mInterruptionFilter="); pw.println(mInterruptionFilter);
1918                 mZenModeHelper.dump(pw, "    ");
1919
1920                 pw.println("\n  Zen Log:");
1921                 ZenLog.dump(pw, "    ");
1922             }
1923
1924             if (!zenOnly) {
1925                 pw.println("\n  Ranking Config:");
1926                 mRankingHelper.dump(pw, "    ", filter);
1927
1928                 pw.println("\n  Notification listeners:");
1929                 mListeners.dump(pw, filter);
1930                 pw.print("    mListenerHints: "); pw.println(mListenerHints);
1931                 pw.print("    mListenersDisablingEffects: (");
1932                 N = mListenersDisablingEffects.size();
1933                 for (int i = 0; i < N; i++) {
1934                     final ManagedServiceInfo listener = mListenersDisablingEffects.valueAt(i);
1935                     if (i > 0) pw.print(',');
1936                     pw.print(listener.component);
1937                 }
1938                 pw.println(')');
1939             }
1940             pw.println("\n  Policy access:");
1941             pw.print("    mPolicyAccess: "); pw.println(mPolicyAccess);
1942
1943             pw.println("\n  Condition providers:");
1944             mConditionProviders.dump(pw, filter);
1945
1946             pw.println("\n  Group summaries:");
1947             for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
1948                 NotificationRecord r = entry.getValue();
1949                 pw.println("    " + entry.getKey() + " -> " + r.getKey());
1950                 if (mNotificationsByKey.get(r.getKey()) != r) {
1951                     pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
1952                     r.dump(pw, "      ", getContext(), filter.redact);
1953                 }
1954             }
1955
1956             try {
1957                 pw.println("\n  Banned Packages:");
1958                 ArrayMap<Integer, ArrayList<String>> packageBans = getPackageBans(filter);
1959                 for (Integer userId : packageBans.keySet()) {
1960                     for (String packageName : packageBans.get(userId)) {
1961                         pw.println("    " + userId + ": " + packageName);
1962                     }
1963                 }
1964             } catch (NameNotFoundException e) {
1965                 // pass
1966             }
1967         }
1968     }
1969
1970     private ArrayMap<Integer, ArrayList<String>> getPackageBans(DumpFilter filter)
1971             throws NameNotFoundException {
1972         ArrayMap<Integer, ArrayList<String>> packageBans = new ArrayMap<>();
1973         ArrayList<String> packageNames = new ArrayList<>();
1974         for (UserInfo user : UserManager.get(getContext()).getUsers()) {
1975             final int userId = user.getUserHandle().getIdentifier();
1976             final PackageManager packageManager = getContext().getPackageManager();
1977             List<PackageInfo> packages = packageManager.getInstalledPackages(0, userId);
1978             final int packageCount = packages.size();
1979             for (int p = 0; p < packageCount; p++) {
1980                 final String packageName = packages.get(p).packageName;
1981                 if (filter == null || filter.matches(packageName)) {
1982                     final int uid = packageManager.getPackageUid(packageName, userId);
1983                     if (!checkNotificationOp(packageName, uid)) {
1984                         packageNames.add(packageName);
1985                     }
1986                 }
1987             }
1988             if (!packageNames.isEmpty()) {
1989                 packageBans.put(userId, packageNames);
1990                 packageNames = new ArrayList<>();
1991             }
1992         }
1993         return packageBans;
1994     }
1995
1996     /**
1997      * The private API only accessible to the system process.
1998      */
1999     private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
2000         @Override
2001         public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
2002                 String tag, int id, Notification notification, int[] idReceived, int userId) {
2003             enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
2004                     idReceived, userId);
2005         }
2006
2007         @Override
2008         public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
2009                 int userId) {
2010             checkCallerIsSystem();
2011             synchronized (mNotificationList) {
2012                 int i = indexOfNotificationLocked(pkg, null, notificationId, userId);
2013                 if (i < 0) {
2014                     Log.d(TAG, "stripForegroundServiceFlag: Could not find notification with "
2015                             + "pkg=" + pkg + " / id=" + notificationId + " / userId=" + userId);
2016                     return;
2017                 }
2018                 NotificationRecord r = mNotificationList.get(i);
2019                 StatusBarNotification sbn = r.sbn;
2020                 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
2021                 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove FLAG_FOREGROUND_SERVICE,
2022                 // we have to revert to the flags we received initially *and* force remove
2023                 // FLAG_FOREGROUND_SERVICE.
2024                 sbn.getNotification().flags =
2025                         (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
2026                 mRankingHelper.sort(mNotificationList);
2027                 mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
2028             }
2029         }
2030     };
2031
2032     void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
2033             final int callingPid, final String tag, final int id, final Notification notification,
2034             int[] idOut, int incomingUserId) {
2035         if (DBG) {
2036             Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
2037                     + " notification=" + notification);
2038         }
2039         checkCallerIsSystemOrSameApp(pkg);
2040         final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg));
2041         final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
2042
2043         final int userId = ActivityManager.handleIncomingUser(callingPid,
2044                 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
2045         final UserHandle user = new UserHandle(userId);
2046
2047         // Limit the number of notifications that any given package except the android
2048         // package or a registered listener can enqueue.  Prevents DOS attacks and deals with leaks.
2049         if (!isSystemNotification && !isNotificationFromListener) {
2050             synchronized (mNotificationList) {
2051                 int count = 0;
2052                 final int N = mNotificationList.size();
2053                 for (int i=0; i<N; i++) {
2054                     final NotificationRecord r = mNotificationList.get(i);
2055                     if (r.sbn.getPackageName().equals(pkg) && r.sbn.getUserId() == userId) {
2056                         if (r.sbn.getId() == id && TextUtils.equals(r.sbn.getTag(), tag)) {
2057                             break;  // Allow updating existing notification
2058                         }
2059                         count++;
2060                         if (count >= MAX_PACKAGE_NOTIFICATIONS) {
2061                             Slog.e(TAG, "Package has already posted " + count
2062                                     + " notifications.  Not showing more.  package=" + pkg);
2063                             return;
2064                         }
2065                     }
2066                 }
2067             }
2068         }
2069
2070         if (pkg == null || notification == null) {
2071             throw new IllegalArgumentException("null not allowed: pkg=" + pkg
2072                     + " id=" + id + " notification=" + notification);
2073         }
2074
2075         if (notification.getSmallIcon() != null) {
2076             if (!notification.isValid()) {
2077                 throw new IllegalArgumentException("Invalid notification (): pkg=" + pkg
2078                         + " id=" + id + " notification=" + notification);
2079             }
2080         }
2081
2082         mHandler.post(new Runnable() {
2083             @Override
2084             public void run() {
2085
2086                 synchronized (mNotificationList) {
2087
2088                     // === Scoring ===
2089
2090                     // 0. Sanitize inputs
2091                     notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN,
2092                             Notification.PRIORITY_MAX);
2093                     // Migrate notification flags to scores
2094                     if (0 != (notification.flags & Notification.FLAG_HIGH_PRIORITY)) {
2095                         if (notification.priority < Notification.PRIORITY_MAX) {
2096                             notification.priority = Notification.PRIORITY_MAX;
2097                         }
2098                     } else if (SCORE_ONGOING_HIGHER &&
2099                             0 != (notification.flags & Notification.FLAG_ONGOING_EVENT)) {
2100                         if (notification.priority < Notification.PRIORITY_HIGH) {
2101                             notification.priority = Notification.PRIORITY_HIGH;
2102                         }
2103                     }
2104                     // force no heads up per package config
2105                     if (!mRankingHelper.getPackagePeekable(pkg, callingUid)) {
2106                         if (notification.extras == null) {
2107                             notification.extras = new Bundle();
2108                         }
2109                         notification.extras.putInt(Notification.EXTRA_AS_HEADS_UP,
2110                                 Notification.HEADS_UP_NEVER);
2111                     }
2112
2113                     // 1. initial score: buckets of 10, around the app [-20..20]
2114                     final int score = notification.priority * NOTIFICATION_PRIORITY_MULTIPLIER;
2115
2116                     // 2. extract ranking signals from the notification data
2117                     final StatusBarNotification n = new StatusBarNotification(
2118                             pkg, opPkg, id, tag, callingUid, callingPid, score, notification,
2119                             user);
2120                     NotificationRecord r = new NotificationRecord(n, score);
2121                     NotificationRecord old = mNotificationsByKey.get(n.getKey());
2122                     if (old != null) {
2123                         // Retain ranking information from previous record
2124                         r.copyRankingInformation(old);
2125                     }
2126
2127                     // Handle grouped notifications and bail out early if we
2128                     // can to avoid extracting signals.
2129                     handleGroupedNotificationLocked(r, old, callingUid, callingPid);
2130                     boolean ignoreNotification =
2131                             removeUnusedGroupedNotificationLocked(r, old, callingUid, callingPid);
2132
2133                     // This conditional is a dirty hack to limit the logging done on
2134                     //     behalf of the download manager without affecting other apps.
2135                     if (!pkg.equals("com.android.providers.downloads")
2136                             || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
2137                         int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
2138                         if (ignoreNotification) {
2139                             enqueueStatus = EVENTLOG_ENQUEUE_STATUS_IGNORED;
2140                         } else if (old != null) {
2141                             enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
2142                         }
2143                         EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
2144                                 pkg, id, tag, userId, notification.toString(),
2145                                 enqueueStatus);
2146                     }
2147
2148                     if (ignoreNotification) {
2149                         return;
2150                     }
2151
2152                     mRankingHelper.extractSignals(r);
2153
2154                     // 3. Apply local rules
2155
2156                     // blocked apps
2157                     if (ENABLE_BLOCKED_NOTIFICATIONS && !noteNotificationOp(pkg, callingUid)) {
2158                         if (!isSystemNotification) {
2159                             r.score = JUNK_SCORE;
2160                             Slog.e(TAG, "Suppressing notification from package " + pkg
2161                                     + " by user request.");
2162                             mUsageStats.registerBlocked(r);
2163                         }
2164                     }
2165
2166                     if (r.score < SCORE_DISPLAY_THRESHOLD) {
2167                         // Notification will be blocked because the score is too low.
2168                         return;
2169                     }
2170
2171                     int index = indexOfNotificationLocked(n.getKey());
2172                     if (index < 0) {
2173                         mNotificationList.add(r);
2174                         mUsageStats.registerPostedByApp(r);
2175                     } else {
2176                         old = mNotificationList.get(index);
2177                         mNotificationList.set(index, r);
2178                         mUsageStats.registerUpdatedByApp(r, old);
2179                         // Make sure we don't lose the foreground service state.
2180                         notification.flags |=
2181                                 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
2182                         r.isUpdate = true;
2183                     }
2184
2185                     mNotificationsByKey.put(n.getKey(), r);
2186
2187                     // Ensure if this is a foreground service that the proper additional
2188                     // flags are set.
2189                     if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
2190                         notification.flags |= Notification.FLAG_ONGOING_EVENT
2191                                 | Notification.FLAG_NO_CLEAR;
2192                     }
2193
2194                     applyZenModeLocked(r);
2195                     mRankingHelper.sort(mNotificationList);
2196
2197                     if (notification.getSmallIcon() != null) {
2198                         StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
2199                         mListeners.notifyPostedLocked(n, oldSbn);
2200                     } else {
2201                         Slog.e(TAG, "Not posting notification without small icon: " + notification);
2202                         if (old != null && !old.isCanceled) {
2203                             mListeners.notifyRemovedLocked(n);
2204                         }
2205                         // ATTENTION: in a future release we will bail out here
2206                         // so that we do not play sounds, show lights, etc. for invalid
2207                         // notifications
2208                         Slog.e(TAG, "WARNING: In a future release this will crash the app: "
2209                                 + n.getPackageName());
2210                     }
2211
2212                     buzzBeepBlinkLocked(r);
2213                 }
2214             }
2215         });
2216
2217         idOut[0] = id;
2218     }
2219
2220     /**
2221      * Ensures that grouped notification receive their special treatment.
2222      *
2223      * <p>Cancels group children if the new notification causes a group to lose
2224      * its summary.</p>
2225      *
2226      * <p>Updates mSummaryByGroupKey.</p>
2227      */
2228     private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
2229             int callingUid, int callingPid) {
2230         StatusBarNotification sbn = r.sbn;
2231         Notification n = sbn.getNotification();
2232         String group = sbn.getGroupKey();
2233         boolean isSummary = n.isGroupSummary();
2234
2235         Notification oldN = old != null ? old.sbn.getNotification() : null;
2236         String oldGroup = old != null ? old.sbn.getGroupKey() : null;
2237         boolean oldIsSummary = old != null && oldN.isGroupSummary();
2238
2239         if (oldIsSummary) {
2240             NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
2241             if (removedSummary != old) {
2242                 String removedKey =
2243                         removedSummary != null ? removedSummary.getKey() : "<null>";
2244                 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
2245                         ", removed=" + removedKey);
2246             }
2247         }
2248         if (isSummary) {
2249             mSummaryByGroupKey.put(group, r);
2250         }
2251
2252         // Clear out group children of the old notification if the update
2253         // causes the group summary to go away. This happens when the old
2254         // notification was a summary and the new one isn't, or when the old
2255         // notification was a summary and its group key changed.
2256         if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
2257             cancelGroupChildrenLocked(old, callingUid, callingPid, null,
2258                     REASON_GROUP_SUMMARY_CANCELED);
2259         }
2260     }
2261
2262     /**
2263      * Performs group notification optimizations if SysUI is the only active
2264      * notification listener and returns whether the given notification should
2265      * be ignored.
2266      *
2267      * <p>Returns true if the given notification is a child of a group with a
2268      * summary, which means that SysUI will never show it, and hence the new
2269      * notification can be safely ignored. Also cancels any previous instance
2270      * of the ignored notification.</p>
2271      *
2272      * <p>For summaries, cancels all children of that group, as SysUI will
2273      * never show them anymore.</p>
2274      *
2275      * @return true if the given notification can be ignored as an optimization
2276      */
2277     private boolean removeUnusedGroupedNotificationLocked(NotificationRecord r,
2278             NotificationRecord old, int callingUid, int callingPid) {
2279         if (!ENABLE_CHILD_NOTIFICATIONS) {
2280             // No optimizations are possible if listeners want groups.
2281             if (mListeners.notificationGroupsDesired()) {
2282                 return false;
2283             }
2284
2285             StatusBarNotification sbn = r.sbn;
2286             String group = sbn.getGroupKey();
2287             boolean isSummary = sbn.getNotification().isGroupSummary();
2288             boolean isChild = sbn.getNotification().isGroupChild();
2289
2290             NotificationRecord summary = mSummaryByGroupKey.get(group);
2291             if (isChild && summary != null) {
2292                 // Child with an active summary -> ignore
2293                 if (DBG) {
2294                     Slog.d(TAG, "Ignoring group child " + sbn.getKey() + " due to existing summary "
2295                             + summary.getKey());
2296                 }
2297                 // Make sure we don't leave an old version of the notification around.
2298                 if (old != null) {
2299                     if (DBG) {
2300                         Slog.d(TAG, "Canceling old version of ignored group child " + sbn.getKey());
2301                     }
2302                     cancelNotificationLocked(old, false, REASON_GROUP_OPTIMIZATION);
2303                 }
2304                 return true;
2305             } else if (isSummary) {
2306                 // Summary -> cancel children
2307                 cancelGroupChildrenLocked(r, callingUid, callingPid, null,
2308                         REASON_GROUP_OPTIMIZATION);
2309             }
2310         }
2311         return false;
2312     }
2313
2314     private void buzzBeepBlinkLocked(NotificationRecord record) {
2315         boolean buzz = false;
2316         boolean beep = false;
2317         boolean blink = false;
2318
2319         final Notification notification = record.sbn.getNotification();
2320
2321         // Should this notification make noise, vibe, or use the LED?
2322         final boolean aboveThreshold = record.score >= SCORE_INTERRUPTION_THRESHOLD;
2323         final boolean canInterrupt = aboveThreshold && !record.isIntercepted();
2324         if (DBG || record.isIntercepted())
2325             Slog.v(TAG,
2326                     "pkg=" + record.sbn.getPackageName() + " canInterrupt=" + canInterrupt +
2327                             " intercept=" + record.isIntercepted()
2328             );
2329
2330         final int currentUser;
2331         final long token = Binder.clearCallingIdentity();
2332         try {
2333             currentUser = ActivityManager.getCurrentUser();
2334         } finally {
2335             Binder.restoreCallingIdentity(token);
2336         }
2337
2338         // If we're not supposed to beep, vibrate, etc. then don't.
2339         final String disableEffects = disableNotificationEffects(record);
2340         if (disableEffects != null) {
2341             ZenLog.traceDisableEffects(record, disableEffects);
2342         }
2343         if (disableEffects == null
2344                 && (!(record.isUpdate
2345                     && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
2346                 && (record.getUserId() == UserHandle.USER_ALL ||
2347                     record.getUserId() == currentUser ||
2348                     mUserProfiles.isCurrentProfile(record.getUserId()))
2349                 && canInterrupt
2350                 && mSystemReady
2351                 && mAudioManager != null) {
2352             if (DBG) Slog.v(TAG, "Interrupting!");
2353
2354             sendAccessibilityEvent(notification, record.sbn.getPackageName());
2355
2356             // sound
2357
2358             // should we use the default notification sound? (indicated either by
2359             // DEFAULT_SOUND or because notification.sound is pointing at
2360             // Settings.System.NOTIFICATION_SOUND)
2361             final boolean useDefaultSound =
2362                    (notification.defaults & Notification.DEFAULT_SOUND) != 0 ||
2363                            Settings.System.DEFAULT_NOTIFICATION_URI
2364                                    .equals(notification.sound);
2365
2366             Uri soundUri = null;
2367             boolean hasValidSound = false;
2368
2369             if (useDefaultSound) {
2370                 soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
2371
2372                 // check to see if the default notification sound is silent
2373                 ContentResolver resolver = getContext().getContentResolver();
2374                 hasValidSound = Settings.System.getString(resolver,
2375                        Settings.System.NOTIFICATION_SOUND) != null;
2376             } else if (notification.sound != null) {
2377                 soundUri = notification.sound;
2378                 hasValidSound = (soundUri != null);
2379             }
2380
2381             if (hasValidSound) {
2382                 boolean looping =
2383                         (notification.flags & Notification.FLAG_INSISTENT) != 0;
2384                 AudioAttributes audioAttributes = audioAttributesForNotification(notification);
2385                 mSoundNotificationKey = record.getKey();
2386                 // do not play notifications if stream volume is 0 (typically because
2387                 // ringer mode is silent) or if there is a user of exclusive audio focus
2388                 if ((mAudioManager.getStreamVolume(
2389                         AudioAttributes.toLegacyStreamType(audioAttributes)) != 0)
2390                             && !mAudioManager.isAudioFocusExclusive()) {
2391                     final long identity = Binder.clearCallingIdentity();
2392                     try {
2393                         final IRingtonePlayer player =
2394                                 mAudioManager.getRingtonePlayer();
2395                         if (player != null) {
2396                             if (DBG) Slog.v(TAG, "Playing sound " + soundUri
2397                                     + " with attributes " + audioAttributes);
2398                             player.playAsync(soundUri, record.sbn.getUser(), looping,
2399                                     audioAttributes);
2400                             beep = true;
2401                         }
2402                     } catch (RemoteException e) {
2403                     } finally {
2404                         Binder.restoreCallingIdentity(identity);
2405                     }
2406                 }
2407             }
2408
2409             // vibrate
2410             // Does the notification want to specify its own vibration?
2411             final boolean hasCustomVibrate = notification.vibrate != null;
2412
2413             // new in 4.2: if there was supposed to be a sound and we're in vibrate
2414             // mode, and no other vibration is specified, we fall back to vibration
2415             final boolean convertSoundToVibration =
2416                        !hasCustomVibrate
2417                     && hasValidSound
2418                     && (mAudioManager.getRingerModeInternal()
2419                                == AudioManager.RINGER_MODE_VIBRATE);
2420
2421             // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
2422             final boolean useDefaultVibrate =
2423                     (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
2424
2425             if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate)
2426                     && !(mAudioManager.getRingerModeInternal()
2427                             == AudioManager.RINGER_MODE_SILENT)) {
2428                 mVibrateNotificationKey = record.getKey();
2429
2430                 if (useDefaultVibrate || convertSoundToVibration) {
2431                     // Escalate privileges so we can use the vibrator even if the
2432                     // notifying app does not have the VIBRATE permission.
2433                     long identity = Binder.clearCallingIdentity();
2434                     try {
2435                         mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
2436                             useDefaultVibrate ? mDefaultVibrationPattern
2437                                 : mFallbackVibrationPattern,
2438                             ((notification.flags & Notification.FLAG_INSISTENT) != 0)
2439                                 ? 0: -1, audioAttributesForNotification(notification));
2440                         buzz = true;
2441                     } finally {
2442                         Binder.restoreCallingIdentity(identity);
2443                     }
2444                 } else if (notification.vibrate.length > 1) {
2445                     // If you want your own vibration pattern, you need the VIBRATE
2446                     // permission
2447                     mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
2448                             notification.vibrate,
2449                         ((notification.flags & Notification.FLAG_INSISTENT) != 0)
2450                                 ? 0: -1, audioAttributesForNotification(notification));
2451                     buzz = true;
2452                 }
2453             }
2454         }
2455
2456         // light
2457         // release the light
2458         boolean wasShowLights = mLights.remove(record.getKey());
2459         if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold) {
2460             mLights.add(record.getKey());
2461             updateLightsLocked();
2462             if (mUseAttentionLight) {
2463                 mAttentionLight.pulse();
2464             }
2465             blink = true;
2466         } else if (wasShowLights) {
2467             updateLightsLocked();
2468         }
2469         if (buzz || beep || blink) {
2470             EventLogTags.writeNotificationAlert(record.getKey(),
2471                     buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
2472             mHandler.post(mBuzzBeepBlinked);
2473         }
2474     }
2475
2476     private static AudioAttributes audioAttributesForNotification(Notification n) {
2477         if (n.audioAttributes != null
2478                 && !Notification.AUDIO_ATTRIBUTES_DEFAULT.equals(n.audioAttributes)) {
2479             // the audio attributes are set and different from the default, use them
2480             return n.audioAttributes;
2481         } else if (n.audioStreamType >= 0 && n.audioStreamType < AudioSystem.getNumStreamTypes()) {
2482             // the stream type is valid, use it
2483             return new AudioAttributes.Builder()
2484                     .setInternalLegacyStreamType(n.audioStreamType)
2485                     .build();
2486         } else if (n.audioStreamType == AudioSystem.STREAM_DEFAULT) {
2487             return Notification.AUDIO_ATTRIBUTES_DEFAULT;
2488         } else {
2489             Log.w(TAG, String.format("Invalid stream type: %d", n.audioStreamType));
2490             return Notification.AUDIO_ATTRIBUTES_DEFAULT;
2491         }
2492     }
2493
2494     void showNextToastLocked() {
2495         ToastRecord record = mToastQueue.get(0);
2496         while (record != null) {
2497             if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
2498             try {
2499                 record.callback.show();
2500                 scheduleTimeoutLocked(record);
2501                 return;
2502             } catch (RemoteException e) {
2503                 Slog.w(TAG, "Object died trying to show notification " + record.callback
2504                         + " in package " + record.pkg);
2505                 // remove it from the list and let the process die
2506                 int index = mToastQueue.indexOf(record);
2507                 if (index >= 0) {
2508                     mToastQueue.remove(index);
2509                 }
2510                 keepProcessAliveLocked(record.pid);
2511                 if (mToastQueue.size() > 0) {
2512                     record = mToastQueue.get(0);
2513                 } else {
2514                     record = null;
2515                 }
2516             }
2517         }
2518     }
2519
2520     void cancelToastLocked(int index) {
2521         ToastRecord record = mToastQueue.get(index);
2522         try {
2523             record.callback.hide();
2524         } catch (RemoteException e) {
2525             Slog.w(TAG, "Object died trying to hide notification " + record.callback
2526                     + " in package " + record.pkg);
2527             // don't worry about this, we're about to remove it from
2528             // the list anyway
2529         }
2530         mToastQueue.remove(index);
2531         keepProcessAliveLocked(record.pid);
2532         if (mToastQueue.size() > 0) {
2533             // Show the next one. If the callback fails, this will remove
2534             // it from the list, so don't assume that the list hasn't changed
2535             // after this point.
2536             showNextToastLocked();
2537         }
2538     }
2539
2540     private void scheduleTimeoutLocked(ToastRecord r)
2541     {
2542         mHandler.removeCallbacksAndMessages(r);
2543         Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
2544         long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
2545         mHandler.sendMessageDelayed(m, delay);
2546     }
2547
2548     private void handleTimeout(ToastRecord record)
2549     {
2550         if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
2551         synchronized (mToastQueue) {
2552             int index = indexOfToastLocked(record.pkg, record.callback);
2553             if (index >= 0) {
2554                 cancelToastLocked(index);
2555             }
2556         }
2557     }
2558
2559     // lock on mToastQueue
2560     int indexOfToastLocked(String pkg, ITransientNotification callback)
2561     {
2562         IBinder cbak = callback.asBinder();
2563         ArrayList<ToastRecord> list = mToastQueue;
2564         int len = list.size();
2565         for (int i=0; i<len; i++) {
2566             ToastRecord r = list.get(i);
2567             if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
2568                 return i;
2569             }
2570         }
2571         return -1;
2572     }
2573
2574     // lock on mToastQueue
2575     void keepProcessAliveLocked(int pid)
2576     {
2577         int toastCount = 0; // toasts from this pid
2578         ArrayList<ToastRecord> list = mToastQueue;
2579         int N = list.size();
2580         for (int i=0; i<N; i++) {
2581             ToastRecord r = list.get(i);
2582             if (r.pid == pid) {
2583                 toastCount++;
2584             }
2585         }
2586         try {
2587             mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
2588         } catch (RemoteException e) {
2589             // Shouldn't happen.
2590         }
2591     }
2592
2593     private void handleRankingReconsideration(Message message) {
2594         if (!(message.obj instanceof RankingReconsideration)) return;
2595         RankingReconsideration recon = (RankingReconsideration) message.obj;
2596         recon.run();
2597         boolean changed;
2598         synchronized (mNotificationList) {
2599             final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
2600             if (record == null) {
2601                 return;
2602             }
2603             int indexBefore = findNotificationRecordIndexLocked(record);
2604             boolean interceptBefore = record.isIntercepted();
2605             int visibilityBefore = record.getPackageVisibilityOverride();
2606             recon.applyChangesLocked(record);
2607             applyZenModeLocked(record);
2608             mRankingHelper.sort(mNotificationList);
2609             int indexAfter = findNotificationRecordIndexLocked(record);
2610             boolean interceptAfter = record.isIntercepted();
2611             int visibilityAfter = record.getPackageVisibilityOverride();
2612             changed = indexBefore != indexAfter || interceptBefore != interceptAfter
2613                     || visibilityBefore != visibilityAfter;
2614             if (interceptBefore && !interceptAfter) {
2615                 buzzBeepBlinkLocked(record);
2616             }
2617         }
2618         if (changed) {
2619             scheduleSendRankingUpdate();
2620         }
2621     }
2622
2623     private void handleRankingConfigChange() {
2624         synchronized (mNotificationList) {
2625             final int N = mNotificationList.size();
2626             ArrayList<String> orderBefore = new ArrayList<String>(N);
2627             int[] visibilities = new int[N];
2628             for (int i = 0; i < N; i++) {
2629                 final NotificationRecord r = mNotificationList.get(i);
2630                 orderBefore.add(r.getKey());
2631                 visibilities[i] = r.getPackageVisibilityOverride();
2632                 mRankingHelper.extractSignals(r);
2633             }
2634             for (int i = 0; i < N; i++) {
2635                 mRankingHelper.sort(mNotificationList);
2636                 final NotificationRecord r = mNotificationList.get(i);
2637                 if (!orderBefore.get(i).equals(r.getKey())
2638                         || visibilities[i] != r.getPackageVisibilityOverride()) {
2639                     scheduleSendRankingUpdate();
2640                     return;
2641                 }
2642             }
2643         }
2644     }
2645
2646     // let zen mode evaluate this record
2647     private void applyZenModeLocked(NotificationRecord record) {
2648         record.setIntercepted(mZenModeHelper.shouldIntercept(record));
2649     }
2650
2651     // lock on mNotificationList
2652     private int findNotificationRecordIndexLocked(NotificationRecord target) {
2653         return mRankingHelper.indexOf(mNotificationList, target);
2654     }
2655
2656     private void scheduleSendRankingUpdate() {
2657         mHandler.removeMessages(MESSAGE_SEND_RANKING_UPDATE);
2658         Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE);
2659         mHandler.sendMessage(m);
2660     }
2661
2662     private void handleSendRankingUpdate() {
2663         synchronized (mNotificationList) {
2664             mListeners.notifyRankingUpdateLocked();
2665         }
2666     }
2667
2668     private void scheduleListenerHintsChanged(int state) {
2669         mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
2670         mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
2671     }
2672
2673     private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
2674         mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
2675         mHandler.obtainMessage(
2676                 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
2677                 listenerInterruptionFilter,
2678                 0).sendToTarget();
2679     }
2680
2681     private void handleListenerHintsChanged(int hints) {
2682         synchronized (mNotificationList) {
2683             mListeners.notifyListenerHintsChangedLocked(hints);
2684         }
2685     }
2686
2687     private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
2688         synchronized (mNotificationList) {
2689             mListeners.notifyInterruptionFilterChanged(interruptionFilter);
2690         }
2691     }
2692
2693     private final class WorkerHandler extends Handler
2694     {
2695         @Override
2696         public void handleMessage(Message msg)
2697         {
2698             switch (msg.what)
2699             {
2700                 case MESSAGE_TIMEOUT:
2701                     handleTimeout((ToastRecord)msg.obj);
2702                     break;
2703                 case MESSAGE_SAVE_POLICY_FILE:
2704                     handleSavePolicyFile();
2705                     break;
2706                 case MESSAGE_SEND_RANKING_UPDATE:
2707                     handleSendRankingUpdate();
2708                     break;
2709                 case MESSAGE_LISTENER_HINTS_CHANGED:
2710                     handleListenerHintsChanged(msg.arg1);
2711                     break;
2712                 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
2713                     handleListenerInterruptionFilterChanged(msg.arg1);
2714                     break;
2715             }
2716         }
2717
2718     }
2719
2720     private final class RankingWorkerHandler extends Handler
2721     {
2722         public RankingWorkerHandler(Looper looper) {
2723             super(looper);
2724         }
2725
2726         @Override
2727         public void handleMessage(Message msg) {
2728             switch (msg.what) {
2729                 case MESSAGE_RECONSIDER_RANKING:
2730                     handleRankingReconsideration(msg);
2731                     break;
2732                 case MESSAGE_RANKING_CONFIG_CHANGE:
2733                     handleRankingConfigChange();
2734                     break;
2735             }
2736         }
2737     }
2738
2739     // Notifications
2740     // ============================================================================
2741     static int clamp(int x, int low, int high) {
2742         return (x < low) ? low : ((x > high) ? high : x);
2743     }
2744
2745     void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
2746         AccessibilityManager manager = AccessibilityManager.getInstance(getContext());
2747         if (!manager.isEnabled()) {
2748             return;
2749         }
2750
2751         AccessibilityEvent event =
2752             AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
2753         event.setPackageName(packageName);
2754         event.setClassName(Notification.class.getName());
2755         event.setParcelableData(notification);
2756         CharSequence tickerText = notification.tickerText;
2757         if (!TextUtils.isEmpty(tickerText)) {
2758             event.getText().add(tickerText);
2759         }
2760
2761         manager.sendAccessibilityEvent(event);
2762     }
2763
2764     private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) {
2765         // tell the app
2766         if (sendDelete) {
2767             if (r.getNotification().deleteIntent != null) {
2768                 try {
2769                     r.getNotification().deleteIntent.send();
2770                 } catch (PendingIntent.CanceledException ex) {
2771                     // do nothing - there's no relevant way to recover, and
2772                     //     no reason to let this propagate
2773                     Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
2774                 }
2775             }
2776         }
2777
2778         // status bar
2779         if (r.getNotification().getSmallIcon() != null) {
2780             r.isCanceled = true;
2781             mListeners.notifyRemovedLocked(r.sbn);
2782         }
2783
2784         final String canceledKey = r.getKey();
2785
2786         // sound
2787         if (canceledKey.equals(mSoundNotificationKey)) {
2788             mSoundNotificationKey = null;
2789             final long identity = Binder.clearCallingIdentity();
2790             try {
2791                 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
2792                 if (player != null) {
2793                     player.stopAsync();
2794                 }
2795             } catch (RemoteException e) {
2796             } finally {
2797                 Binder.restoreCallingIdentity(identity);
2798             }
2799         }
2800
2801         // vibrate
2802         if (canceledKey.equals(mVibrateNotificationKey)) {
2803             mVibrateNotificationKey = null;
2804             long identity = Binder.clearCallingIdentity();
2805             try {
2806                 mVibrator.cancel();
2807             }
2808             finally {
2809                 Binder.restoreCallingIdentity(identity);
2810             }
2811         }
2812
2813         // light
2814         mLights.remove(canceledKey);
2815
2816         // Record usage stats
2817         switch (reason) {
2818             case REASON_DELEGATE_CANCEL:
2819             case REASON_DELEGATE_CANCEL_ALL:
2820             case REASON_LISTENER_CANCEL:
2821             case REASON_LISTENER_CANCEL_ALL:
2822                 mUsageStats.registerDismissedByUser(r);
2823                 break;
2824             case REASON_NOMAN_CANCEL:
2825             case REASON_NOMAN_CANCEL_ALL:
2826                 mUsageStats.registerRemovedByApp(r);
2827                 break;
2828         }
2829
2830         mNotificationsByKey.remove(r.sbn.getKey());
2831         String groupKey = r.getGroupKey();
2832         NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
2833         if (groupSummary != null && groupSummary.getKey().equals(r.getKey())) {
2834             mSummaryByGroupKey.remove(groupKey);
2835         }
2836
2837         // Save it for users of getHistoricalNotifications()
2838         mArchive.record(r.sbn);
2839
2840         final long now = System.currentTimeMillis();
2841         EventLogTags.writeNotificationCanceled(canceledKey, reason,
2842                 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
2843     }
2844
2845     /**
2846      * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
2847      * and none of the {@code mustNotHaveFlags}.
2848      */
2849     void cancelNotification(final int callingUid, final int callingPid,
2850             final String pkg, final String tag, final int id,
2851             final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
2852             final int userId, final int reason, final ManagedServiceInfo listener) {
2853         // In enqueueNotificationInternal notifications are added by scheduling the
2854         // work on the worker handler. Hence, we also schedule the cancel on this
2855         // handler to avoid a scenario where an add notification call followed by a
2856         // remove notification call ends up in not removing the notification.
2857         mHandler.post(new Runnable() {
2858             @Override
2859             public void run() {
2860                 String listenerName = listener == null ? null : listener.component.toShortString();
2861                 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
2862                         userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
2863
2864                 synchronized (mNotificationList) {
2865                     int index = indexOfNotificationLocked(pkg, tag, id, userId);
2866                     if (index >= 0) {
2867                         NotificationRecord r = mNotificationList.get(index);
2868
2869                         // Ideally we'd do this in the caller of this method. However, that would
2870                         // require the caller to also find the notification.
2871                         if (reason == REASON_DELEGATE_CLICK) {
2872                             mUsageStats.registerClickedByUser(r);
2873                         }
2874
2875                         if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
2876                             return;
2877                         }
2878                         if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
2879                             return;
2880                         }
2881
2882                         mNotificationList.remove(index);
2883
2884                         cancelNotificationLocked(r, sendDelete, reason);
2885                         cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
2886                                 REASON_GROUP_SUMMARY_CANCELED);
2887                         updateLightsLocked();
2888                     }
2889                 }
2890             }
2891         });
2892     }
2893
2894     /**
2895      * Determine whether the userId applies to the notification in question, either because
2896      * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
2897      */
2898     private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
2899         return
2900                 // looking for USER_ALL notifications? match everything
2901                    userId == UserHandle.USER_ALL
2902                 // a notification sent to USER_ALL matches any query
2903                 || r.getUserId() == UserHandle.USER_ALL
2904                 // an exact user match
2905                 || r.getUserId() == userId;
2906     }
2907
2908     /**
2909      * Determine whether the userId applies to the notification in question, either because
2910      * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
2911      * because it matches one of the users profiles.
2912      */
2913     private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
2914         return notificationMatchesUserId(r, userId)
2915                 || mUserProfiles.isCurrentProfile(r.getUserId());
2916     }
2917
2918     /**
2919      * Cancels all notifications from a given package that have all of the
2920      * {@code mustHaveFlags}.
2921      */
2922     boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags,
2923             int mustNotHaveFlags, boolean doit, int userId, int reason,
2924             ManagedServiceInfo listener) {
2925         String listenerName = listener == null ? null : listener.component.toShortString();
2926         EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
2927                 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
2928                 listenerName);
2929
2930         synchronized (mNotificationList) {
2931             final int N = mNotificationList.size();
2932             ArrayList<NotificationRecord> canceledNotifications = null;
2933             for (int i = N-1; i >= 0; --i) {
2934                 NotificationRecord r = mNotificationList.get(i);
2935                 if (!notificationMatchesUserId(r, userId)) {
2936                     continue;
2937                 }
2938                 // Don't remove notifications to all, if there's no package name specified
2939                 if (r.getUserId() == UserHandle.USER_ALL && pkg == null) {
2940                     continue;
2941                 }
2942                 if ((r.getFlags() & mustHaveFlags) != mustHaveFlags) {
2943                     continue;
2944                 }
2945                 if ((r.getFlags() & mustNotHaveFlags) != 0) {
2946                     continue;
2947                 }
2948                 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
2949                     continue;
2950                 }
2951                 if (canceledNotifications == null) {
2952                     canceledNotifications = new ArrayList<>();
2953                 }
2954                 canceledNotifications.add(r);
2955                 if (!doit) {
2956                     return true;
2957                 }
2958                 mNotificationList.remove(i);
2959                 cancelNotificationLocked(r, false, reason);
2960             }
2961             if (doit && canceledNotifications != null) {
2962                 final int M = canceledNotifications.size();
2963                 for (int i = 0; i < M; i++) {
2964                     cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
2965                             listenerName, REASON_GROUP_SUMMARY_CANCELED);
2966                 }
2967             }
2968             if (canceledNotifications != null) {
2969                 updateLightsLocked();
2970             }
2971             return canceledNotifications != null;
2972         }
2973     }
2974
2975     void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
2976             ManagedServiceInfo listener, boolean includeCurrentProfiles) {
2977         String listenerName = listener == null ? null : listener.component.toShortString();
2978         EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
2979                 null, userId, 0, 0, reason, listenerName);
2980
2981         ArrayList<NotificationRecord> canceledNotifications = null;
2982         final int N = mNotificationList.size();
2983         for (int i=N-1; i>=0; i--) {
2984             NotificationRecord r = mNotificationList.get(i);
2985             if (includeCurrentProfiles) {
2986                 if (!notificationMatchesCurrentProfiles(r, userId)) {
2987                     continue;
2988                 }
2989             } else {
2990                 if (!notificationMatchesUserId(r, userId)) {
2991                     continue;
2992                 }
2993             }
2994
2995             if ((r.getFlags() & (Notification.FLAG_ONGOING_EVENT
2996                             | Notification.FLAG_NO_CLEAR)) == 0) {
2997                 mNotificationList.remove(i);
2998                 cancelNotificationLocked(r, true, reason);
2999                 // Make a note so we can cancel children later.
3000                 if (canceledNotifications == null) {
3001                     canceledNotifications = new ArrayList<>();
3002                 }
3003                 canceledNotifications.add(r);
3004             }
3005         }
3006         int M = canceledNotifications != null ? canceledNotifications.size() : 0;
3007         for (int i = 0; i < M; i++) {
3008             cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
3009                     listenerName, REASON_GROUP_SUMMARY_CANCELED);
3010         }
3011         updateLightsLocked();
3012     }
3013
3014     // Warning: The caller is responsible for invoking updateLightsLocked().
3015     private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
3016             String listenerName, int reason) {
3017         Notification n = r.getNotification();
3018         if (!n.isGroupSummary()) {
3019             return;
3020         }
3021
3022         String pkg = r.sbn.getPackageName();
3023         int userId = r.getUserId();
3024
3025         if (pkg == null) {
3026             if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
3027             return;
3028         }
3029
3030         final int N = mNotificationList.size();
3031         for (int i = N - 1; i >= 0; i--) {
3032             NotificationRecord childR = mNotificationList.get(i);
3033             StatusBarNotification childSbn = childR.sbn;
3034             if (childR.getNotification().isGroupChild() &&
3035                     childR.getGroupKey().equals(r.getGroupKey())) {
3036                 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
3037                         childSbn.getTag(), userId, 0, 0, reason, listenerName);
3038                 mNotificationList.remove(i);
3039                 cancelNotificationLocked(childR, false, reason);
3040             }
3041         }
3042     }
3043
3044     // lock on mNotificationList
3045     void updateLightsLocked()
3046     {
3047         // handle notification lights
3048         NotificationRecord ledNotification = null;
3049         while (ledNotification == null && !mLights.isEmpty()) {
3050             final String owner = mLights.get(mLights.size() - 1);
3051             ledNotification = mNotificationsByKey.get(owner);
3052             if (ledNotification == null) {
3053                 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
3054                 mLights.remove(owner);
3055             }
3056         }
3057
3058         // Don't flash while we are in a call or screen is on
3059         if (ledNotification == null || mInCall || mScreenOn) {
3060             mNotificationLight.turnOff();
3061             mStatusBar.notificationLightOff();
3062         } else {
3063             final Notification ledno = ledNotification.sbn.getNotification();
3064             int ledARGB = ledno.ledARGB;
3065             int ledOnMS = ledno.ledOnMS;
3066             int ledOffMS = ledno.ledOffMS;
3067             if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0) {
3068                 ledARGB = mDefaultNotificationColor;
3069                 ledOnMS = mDefaultNotificationLedOn;
3070                 ledOffMS = mDefaultNotificationLedOff;
3071             }
3072             if (mNotificationPulseEnabled) {
3073                 // pulse repeatedly
3074                 mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED,
3075                         ledOnMS, ledOffMS);
3076             }
3077             // let SystemUI make an independent decision
3078             mStatusBar.notificationLightPulse(ledARGB, ledOnMS, ledOffMS);
3079         }
3080     }
3081
3082     // lock on mNotificationList
3083     int indexOfNotificationLocked(String pkg, String tag, int id, int userId)
3084     {
3085         ArrayList<NotificationRecord> list = mNotificationList;
3086         final int len = list.size();
3087         for (int i=0; i<len; i++) {
3088             NotificationRecord r = list.get(i);
3089             if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
3090                     TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
3091                 return i;
3092             }
3093         }
3094         return -1;
3095     }
3096
3097     // lock on mNotificationList
3098     int indexOfNotificationLocked(String key) {
3099         final int N = mNotificationList.size();
3100         for (int i = 0; i < N; i++) {
3101             if (key.equals(mNotificationList.get(i).getKey())) {
3102                 return i;
3103             }
3104         }
3105         return -1;
3106     }
3107
3108     private void updateNotificationPulse() {
3109         synchronized (mNotificationList) {
3110             updateLightsLocked();
3111         }
3112     }
3113
3114     private static boolean isUidSystem(int uid) {
3115         final int appid = UserHandle.getAppId(uid);
3116         return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
3117     }
3118
3119     private static boolean isCallerSystem() {
3120         return isUidSystem(Binder.getCallingUid());
3121     }
3122
3123     private static void checkCallerIsSystem() {
3124         if (isCallerSystem()) {
3125             return;
3126         }
3127         throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
3128     }
3129
3130     private static void checkCallerIsSystemOrSameApp(String pkg) {
3131         if (isCallerSystem()) {
3132             return;
3133         }
3134         checkCallerIsSameApp(pkg);
3135     }
3136
3137     private static void checkCallerIsSameApp(String pkg) {
3138         final int uid = Binder.getCallingUid();
3139         try {
3140             ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
3141                     pkg, 0, UserHandle.getCallingUserId());
3142             if (ai == null) {
3143                 throw new SecurityException("Unknown package " + pkg);
3144             }
3145             if (!UserHandle.isSameApp(ai.uid, uid)) {
3146                 throw new SecurityException("Calling uid " + uid + " gave package"
3147                         + pkg + " which is owned by uid " + ai.uid);
3148             }
3149         } catch (RemoteException re) {
3150             throw new SecurityException("Unknown package " + pkg + "\n" + re);
3151         }
3152     }
3153
3154     private static String callStateToString(int state) {
3155         switch (state) {
3156             case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
3157             case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
3158             case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
3159             default: return "CALL_STATE_UNKNOWN_" + state;
3160         }
3161     }
3162
3163     private void listenForCallState() {
3164         TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
3165             @Override
3166             public void onCallStateChanged(int state, String incomingNumber) {
3167                 if (mCallState == state) return;
3168                 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
3169                 mCallState = state;
3170             }
3171         }, PhoneStateListener.LISTEN_CALL_STATE);
3172     }
3173
3174     /**
3175      * Generates a NotificationRankingUpdate from 'sbns', considering only
3176      * notifications visible to the given listener.
3177      *
3178      * <p>Caller must hold a lock on mNotificationList.</p>
3179      */
3180     private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
3181         int speedBumpIndex = -1;
3182         final int N = mNotificationList.size();
3183         ArrayList<String> keys = new ArrayList<String>(N);
3184         ArrayList<String> interceptedKeys = new ArrayList<String>(N);
3185         Bundle visibilityOverrides = new Bundle();
3186         for (int i = 0; i < N; i++) {
3187             NotificationRecord record = mNotificationList.get(i);
3188             if (!isVisibleToListener(record.sbn, info)) {
3189                 continue;
3190             }
3191             keys.add(record.sbn.getKey());
3192             if (record.isIntercepted()) {
3193                 interceptedKeys.add(record.sbn.getKey());
3194             }
3195             if (record.getPackageVisibilityOverride()
3196                     != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
3197                 visibilityOverrides.putInt(record.sbn.getKey(),
3198                         record.getPackageVisibilityOverride());
3199             }
3200             // Find first min-prio notification for speedbump placement.
3201             if (speedBumpIndex == -1 &&
3202                     // Intrusiveness trumps priority, hence ignore intrusives.
3203                     !record.isRecentlyIntrusive() &&
3204                     // Currently, package priority is either PRIORITY_DEFAULT or PRIORITY_MAX, so
3205                     // scanning for PRIORITY_MIN within the package bucket PRIORITY_DEFAULT
3206                     // (or lower as a safeguard) is sufficient to find the speedbump index.
3207                     // We'll have to revisit this when more package priority buckets are introduced.
3208                     record.getPackagePriority() <= Notification.PRIORITY_DEFAULT &&
3209                     record.sbn.getNotification().priority == Notification.PRIORITY_MIN) {
3210                 speedBumpIndex = keys.size() - 1;
3211             }
3212         }
3213         String[] keysAr = keys.toArray(new String[keys.size()]);
3214         String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
3215         return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
3216                 speedBumpIndex);
3217     }
3218
3219     private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
3220         if (!listener.enabledAndUserMatches(sbn.getUserId())) {
3221             return false;
3222         }
3223         // TODO: remove this for older listeners.
3224         return true;
3225     }
3226
3227     public class NotificationListeners extends ManagedServices {
3228
3229         private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
3230         private boolean mNotificationGroupsDesired;
3231
3232         public NotificationListeners() {
3233             super(getContext(), mHandler, mNotificationList, mUserProfiles);
3234         }
3235
3236         @Override
3237         protected Config getConfig() {
3238             Config c = new Config();
3239             c.caption = "notification listener";
3240             c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
3241             c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
3242             c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
3243             c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
3244             c.clientLabel = R.string.notification_listener_binding_label;
3245             return c;
3246         }
3247
3248         @Override
3249         protected IInterface asInterface(IBinder binder) {
3250             return INotificationListener.Stub.asInterface(binder);
3251         }
3252
3253         @Override
3254         public void onServiceAdded(ManagedServiceInfo info) {
3255             final INotificationListener listener = (INotificationListener) info.service;
3256             final NotificationRankingUpdate update;
3257             synchronized (mNotificationList) {
3258                 updateNotificationGroupsDesiredLocked();
3259                 update = makeRankingUpdateLocked(info);
3260             }
3261             try {
3262                 listener.onListenerConnected(update);
3263             } catch (RemoteException e) {
3264                 // we tried
3265             }
3266         }
3267
3268         @Override
3269         protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
3270             if (mListenersDisablingEffects.remove(removed)) {
3271                 updateListenerHintsLocked();
3272                 updateEffectsSuppressorLocked();
3273             }
3274             mLightTrimListeners.remove(removed);
3275             updateNotificationGroupsDesiredLocked();
3276         }
3277
3278         public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
3279             if (trim == TRIM_LIGHT) {
3280                 mLightTrimListeners.add(info);
3281             } else {
3282                 mLightTrimListeners.remove(info);
3283             }
3284         }
3285
3286         public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
3287             return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
3288
3289         }
3290
3291         /**
3292          * asynchronously notify all listeners about a new notification
3293          *
3294          * <p>
3295          * Also takes care of removing a notification that has been visible to a listener before,
3296          * but isn't anymore.
3297          */
3298         public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
3299             // Lazily initialized snapshots of the notification.
3300             StatusBarNotification sbnClone = null;
3301             StatusBarNotification sbnCloneLight = null;
3302
3303             for (final ManagedServiceInfo info : mServices) {
3304                 boolean sbnVisible = isVisibleToListener(sbn, info);
3305                 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
3306                 // This notification hasn't been and still isn't visible -> ignore.
3307                 if (!oldSbnVisible && !sbnVisible) {
3308                     continue;
3309                 }
3310                 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
3311
3312                 // This notification became invisible -> remove the old one.
3313                 if (oldSbnVisible && !sbnVisible) {
3314                     final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
3315                     mHandler.post(new Runnable() {
3316                         @Override
3317                         public void run() {
3318                             notifyRemoved(info, oldSbnLightClone, update);
3319                         }
3320                     });
3321                     continue;
3322                 }
3323
3324                 final int trim = mListeners.getOnNotificationPostedTrim(info);
3325
3326                 if (trim == TRIM_LIGHT && sbnCloneLight == null) {
3327                     sbnCloneLight = sbn.cloneLight();
3328                 } else if (trim == TRIM_FULL && sbnClone == null) {
3329                     sbnClone = sbn.clone();
3330                 }
3331                 final StatusBarNotification sbnToPost =
3332                         (trim == TRIM_FULL) ? sbnClone : sbnCloneLight;
3333
3334                 mHandler.post(new Runnable() {
3335                     @Override
3336                     public void run() {
3337                         notifyPosted(info, sbnToPost, update);
3338                     }
3339                 });
3340             }
3341         }
3342
3343         /**
3344          * asynchronously notify all listeners about a removed notification
3345          */
3346         public void notifyRemovedLocked(StatusBarNotification sbn) {
3347             // make a copy in case changes are made to the underlying Notification object
3348             // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
3349             // notification
3350             final StatusBarNotification sbnLight = sbn.cloneLight();
3351             for (final ManagedServiceInfo info : mServices) {
3352                 if (!isVisibleToListener(sbn, info)) {
3353                     continue;
3354                 }
3355                 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
3356                 mHandler.post(new Runnable() {
3357                     @Override
3358                     public void run() {
3359                         notifyRemoved(info, sbnLight, update);
3360                     }
3361                 });
3362             }
3363         }
3364
3365         /**
3366          * asynchronously notify all listeners about a reordering of notifications
3367          */
3368         public void notifyRankingUpdateLocked() {
3369             for (final ManagedServiceInfo serviceInfo : mServices) {
3370                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
3371                     continue;
3372                 }
3373                 final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
3374                 mHandler.post(new Runnable() {
3375                     @Override
3376                     public void run() {
3377                         notifyRankingUpdate(serviceInfo, update);
3378                     }
3379                 });
3380             }
3381         }
3382
3383         public void notifyListenerHintsChangedLocked(final int hints) {
3384             for (final ManagedServiceInfo serviceInfo : mServices) {
3385                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
3386                     continue;
3387                 }
3388                 mHandler.post(new Runnable() {
3389                     @Override
3390                     public void run() {
3391                         notifyListenerHintsChanged(serviceInfo, hints);
3392                     }
3393                 });
3394             }
3395         }
3396
3397         public void notifyInterruptionFilterChanged(final int interruptionFilter) {
3398             for (final ManagedServiceInfo serviceInfo : mServices) {
3399                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
3400                     continue;
3401                 }
3402                 mHandler.post(new Runnable() {
3403                     @Override
3404                     public void run() {
3405                         notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
3406                     }
3407                 });
3408             }
3409         }
3410
3411         private void notifyPosted(final ManagedServiceInfo info,
3412                 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
3413             final INotificationListener listener = (INotificationListener)info.service;
3414             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
3415             try {
3416                 listener.onNotificationPosted(sbnHolder, rankingUpdate);
3417             } catch (RemoteException ex) {
3418                 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
3419             }
3420         }
3421
3422         private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
3423                 NotificationRankingUpdate rankingUpdate) {
3424             if (!info.enabledAndUserMatches(sbn.getUserId())) {
3425                 return;
3426             }
3427             final INotificationListener listener = (INotificationListener) info.service;
3428             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
3429             try {
3430                 listener.onNotificationRemoved(sbnHolder, rankingUpdate);
3431             } catch (RemoteException ex) {
3432                 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
3433             }
3434         }
3435
3436         private void notifyRankingUpdate(ManagedServiceInfo info,
3437                                          NotificationRankingUpdate rankingUpdate) {
3438             final INotificationListener listener = (INotificationListener) info.service;
3439             try {
3440                 listener.onNotificationRankingUpdate(rankingUpdate);
3441             } catch (RemoteException ex) {
3442                 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
3443             }
3444         }
3445
3446         private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
3447             final INotificationListener listener = (INotificationListener) info.service;
3448             try {
3449                 listener.onListenerHintsChanged(hints);
3450             } catch (RemoteException ex) {
3451                 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
3452             }
3453         }
3454
3455         private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
3456                 int interruptionFilter) {
3457             final INotificationListener listener = (INotificationListener) info.service;
3458             try {
3459                 listener.onInterruptionFilterChanged(interruptionFilter);
3460             } catch (RemoteException ex) {
3461                 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
3462             }
3463         }
3464
3465         private boolean isListenerPackage(String packageName) {
3466             if (packageName == null) {
3467                 return false;
3468             }
3469             // TODO: clean up locking object later
3470             synchronized (mNotificationList) {
3471                 for (final ManagedServiceInfo serviceInfo : mServices) {
3472                     if (packageName.equals(serviceInfo.component.getPackageName())) {
3473                         return true;
3474                     }
3475                 }
3476             }
3477             return false;
3478         }
3479
3480         /**
3481          * Returns whether any of the currently registered listeners wants to receive notification
3482          * groups.
3483          *
3484          * <p>Currently we assume groups are desired by non-SystemUI listeners.</p>
3485          */
3486         public boolean notificationGroupsDesired() {
3487             return mNotificationGroupsDesired;
3488         }
3489
3490         private void updateNotificationGroupsDesiredLocked() {
3491             mNotificationGroupsDesired = true;
3492             // No listeners, no groups.
3493             if (mServices.isEmpty()) {
3494                 mNotificationGroupsDesired = false;
3495                 return;
3496             }
3497             // One listener: Check whether it's SysUI.
3498             if (mServices.size() == 1 &&
3499                     mServices.get(0).component.getPackageName().equals("com.android.systemui")) {
3500                 mNotificationGroupsDesired = false;
3501                 return;
3502             }
3503         }
3504     }
3505
3506     public static final class DumpFilter {
3507         public boolean filtered = false;
3508         public String pkgFilter;
3509         public boolean zen;
3510         public long since;
3511         public boolean stats;
3512         public boolean redact = true;
3513
3514         public static DumpFilter parseFromArguments(String[] args) {
3515             final DumpFilter filter = new DumpFilter();
3516             for (int ai = 0; ai < args.length; ai++) {
3517                 final String a = args[ai];
3518                 if ("--noredact".equals(a) || "--reveal".equals(a)) {
3519                     filter.redact = false;
3520                 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
3521                     if (ai < args.length-1) {
3522                         ai++;
3523                         filter.pkgFilter = args[ai].trim().toLowerCase();
3524                         if (filter.pkgFilter.isEmpty()) {
3525                             filter.pkgFilter = null;
3526                         } else {
3527                             filter.filtered = true;
3528                         }
3529                     }
3530                 } else if ("--zen".equals(a) || "zen".equals(a)) {
3531                     filter.filtered = true;
3532                     filter.zen = true;
3533                 } else if ("--stats".equals(a)) {
3534                     filter.stats = true;
3535                     if (ai < args.length-1) {
3536                         ai++;
3537                         filter.since = Long.valueOf(args[ai]);
3538                     } else {
3539                         filter.since = 0;
3540                     }
3541                 }
3542             }
3543             return filter;
3544         }
3545
3546         public boolean matches(StatusBarNotification sbn) {
3547             if (!filtered) return true;
3548             return zen ? true : sbn != null
3549                     && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
3550         }
3551
3552         public boolean matches(ComponentName component) {
3553             if (!filtered) return true;
3554             return zen ? true : component != null && matches(component.getPackageName());
3555         }
3556
3557         public boolean matches(String pkg) {
3558             if (!filtered) return true;
3559             return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
3560         }
3561
3562         @Override
3563         public String toString() {
3564             return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
3565         }
3566     }
3567
3568     /**
3569      * Wrapper for a StatusBarNotification object that allows transfer across a oneway
3570      * binder without sending large amounts of data over a oneway transaction.
3571      */
3572     private static final class StatusBarNotificationHolder
3573             extends IStatusBarNotificationHolder.Stub {
3574         private StatusBarNotification mValue;
3575
3576         public StatusBarNotificationHolder(StatusBarNotification value) {
3577             mValue = value;
3578         }
3579
3580         /** Get the held value and clear it. This function should only be called once per holder */
3581         @Override
3582         public StatusBarNotification get() {
3583             StatusBarNotification value = mValue;
3584             mValue = null;
3585             return value;
3586         }
3587     }
3588
3589     private final class PolicyAccess {
3590         private static final String SEPARATOR = ":";
3591         private final String[] PERM = {
3592             android.Manifest.permission.ACCESS_NOTIFICATION_POLICY
3593         };
3594
3595         public boolean isPackageGranted(String pkg) {
3596             return pkg != null && getGrantedPackages().contains(pkg);
3597         }
3598
3599         public void put(String pkg, boolean granted) {
3600             if (pkg == null) return;
3601             final ArraySet<String> pkgs = getGrantedPackages();
3602             boolean changed;
3603             if (granted) {
3604                 changed = pkgs.add(pkg);
3605             } else {
3606                 changed = pkgs.remove(pkg);
3607             }
3608             if (!changed) return;
3609             final String setting = TextUtils.join(SEPARATOR, pkgs);
3610             final int currentUser = ActivityManager.getCurrentUser();
3611             Settings.Secure.putStringForUser(getContext().getContentResolver(),
3612                     Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
3613                     setting,
3614                     currentUser);
3615             getContext().sendBroadcastAsUser(new Intent(NotificationManager
3616                     .ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
3617                 .setPackage(pkg)
3618                 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), new UserHandle(currentUser), null);
3619         }
3620
3621         public ArraySet<String> getGrantedPackages() {
3622             final ArraySet<String> pkgs = new ArraySet<>();
3623
3624             long identity = Binder.clearCallingIdentity();
3625             try {
3626                 final String setting = Settings.Secure.getStringForUser(
3627                         getContext().getContentResolver(),
3628                         Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
3629                         ActivityManager.getCurrentUser());
3630                 if (setting != null) {
3631                     final String[] tokens = setting.split(SEPARATOR);
3632                     for (int i = 0; i < tokens.length; i++) {
3633                         String token = tokens[i];
3634                         if (token != null) {
3635                             token.trim();
3636                         }
3637                         if (TextUtils.isEmpty(token)) {
3638                             continue;
3639                         }
3640                         pkgs.add(token);
3641                     }
3642                 }
3643             } finally {
3644                 Binder.restoreCallingIdentity(identity);
3645             }
3646             return pkgs;
3647         }
3648
3649         public String[] getRequestingPackages() throws RemoteException {
3650             final ParceledListSlice list = AppGlobals.getPackageManager()
3651                     .getPackagesHoldingPermissions(PERM, 0 /*flags*/,
3652                             ActivityManager.getCurrentUser());
3653             final List<PackageInfo> pkgs = list.getList();
3654             if (pkgs == null || pkgs.isEmpty()) return new String[0];
3655             final int N = pkgs.size();
3656             final String[] rt = new String[N];
3657             for (int i = 0; i < N; i++) {
3658                 rt[i] = pkgs.get(i).packageName;
3659             }
3660             return rt;
3661         }
3662     }
3663 }