OSDN Git Service

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