OSDN Git Service

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