OSDN Git Service

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