OSDN Git Service

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