OSDN Git Service

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