OSDN Git Service

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