OSDN Git Service

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