OSDN Git Service

Force FGS notifications to show for a minimum time
[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.app.NotificationManager.IMPORTANCE_LOW;
20 import static android.app.NotificationManager.IMPORTANCE_MIN;
21 import static android.app.NotificationManager.IMPORTANCE_NONE;
22 import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
23 import static android.content.pm.PackageManager.FEATURE_LEANBACK;
24 import static android.content.pm.PackageManager.FEATURE_TELEVISION;
25 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
26 import static android.os.UserHandle.USER_NULL;
27 import static android.service.notification.NotificationListenerService
28         .NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
29 import static android.service.notification.NotificationListenerService
30         .NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
31 import static android.service.notification.NotificationListenerService
32         .NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
33 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
34 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
35 import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
36 import static android.service.notification.NotificationListenerService.REASON_CANCEL;
37 import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
38 import static android.service.notification.NotificationListenerService.REASON_CLICK;
39 import static android.service.notification.NotificationListenerService.REASON_ERROR;
40 import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
41 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL;
42 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL;
43 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED;
44 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED;
45 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED;
46 import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF;
47 import static android.service.notification.NotificationListenerService.REASON_SNOOZED;
48 import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
49 import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
50 import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
51 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
52 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
53 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
54 import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
55 import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
56 import static android.service.notification.NotificationListenerService.TRIM_FULL;
57 import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
58
59 import static android.view.Display.DEFAULT_DISPLAY;
60 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
61
62 import android.Manifest;
63 import android.annotation.NonNull;
64 import android.annotation.Nullable;
65 import android.app.ActivityManager;
66 import android.app.ActivityManagerInternal;
67 import android.app.AlarmManager;
68 import android.app.AppGlobals;
69 import android.app.AppOpsManager;
70 import android.app.AutomaticZenRule;
71 import android.app.NotificationChannelGroup;
72 import android.app.backup.BackupManager;
73 import android.app.IActivityManager;
74 import android.app.INotificationManager;
75 import android.app.ITransientNotification;
76 import android.app.Notification;
77 import android.app.NotificationChannel;
78 import android.app.NotificationManager.Policy;
79 import android.app.NotificationManager;
80 import android.app.PendingIntent;
81 import android.app.StatusBarManager;
82 import android.app.usage.UsageEvents;
83 import android.app.usage.UsageStatsManagerInternal;
84 import android.companion.ICompanionDeviceManager;
85 import android.content.BroadcastReceiver;
86 import android.content.ComponentName;
87 import android.content.ContentResolver;
88 import android.content.Context;
89 import android.content.Intent;
90 import android.content.IntentFilter;
91 import android.content.pm.ApplicationInfo;
92 import android.content.pm.IPackageManager;
93 import android.content.pm.PackageManager;
94 import android.content.pm.PackageManager.NameNotFoundException;
95 import android.content.pm.ParceledListSlice;
96 import android.content.res.Resources;
97 import android.database.ContentObserver;
98 import android.media.AudioAttributes;
99 import android.media.AudioManager;
100 import android.media.AudioManagerInternal;
101 import android.media.IRingtonePlayer;
102 import android.net.Uri;
103 import android.os.Binder;
104 import android.os.Build;
105 import android.os.Bundle;
106 import android.os.Environment;
107 import android.os.Handler;
108 import android.os.HandlerThread;
109 import android.os.IBinder;
110 import android.os.IInterface;
111 import android.os.Looper;
112 import android.os.Message;
113 import android.os.Process;
114 import android.os.RemoteException;
115 import android.os.ResultReceiver;
116 import android.os.ServiceManager;
117 import android.os.ShellCallback;
118 import android.os.ShellCommand;
119 import android.os.SystemClock;
120 import android.os.SystemProperties;
121 import android.os.UserHandle;
122 import android.os.Vibrator;
123 import android.os.VibrationEffect;
124 import android.provider.Settings;
125 import android.service.notification.Adjustment;
126 import android.service.notification.Condition;
127 import android.service.notification.IConditionProvider;
128 import android.service.notification.INotificationListener;
129 import android.service.notification.IStatusBarNotificationHolder;
130 import android.service.notification.NotificationAssistantService;
131 import android.service.notification.NotificationListenerService;
132 import android.service.notification.NotificationRankingUpdate;
133 import android.service.notification.NotificationRecordProto;
134 import android.service.notification.NotificationServiceDumpProto;
135 import android.service.notification.NotificationServiceProto;
136 import android.service.notification.SnoozeCriterion;
137 import android.service.notification.StatusBarNotification;
138 import android.service.notification.ZenModeConfig;
139 import android.service.notification.ZenModeProto;
140 import android.telecom.TelecomManager;
141 import android.telephony.PhoneStateListener;
142 import android.telephony.TelephonyManager;
143 import android.text.TextUtils;
144 import android.util.ArrayMap;
145 import android.util.ArraySet;
146 import android.util.AtomicFile;
147 import android.util.Log;
148 import android.util.Slog;
149 import android.util.SparseArray;
150 import android.util.Xml;
151 import android.util.proto.ProtoOutputStream;
152 import android.view.WindowManagerInternal;
153 import android.view.accessibility.AccessibilityEvent;
154 import android.view.accessibility.AccessibilityManager;
155 import android.widget.Toast;
156
157 import com.android.internal.R;
158 import com.android.internal.annotations.GuardedBy;
159 import com.android.internal.annotations.VisibleForTesting;
160 import com.android.internal.logging.MetricsLogger;
161 import com.android.internal.logging.nano.MetricsProto;
162 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
163 import com.android.internal.os.BackgroundThread;
164 import com.android.internal.statusbar.NotificationVisibility;
165 import com.android.internal.util.ArrayUtils;
166 import com.android.internal.util.DumpUtils;
167 import com.android.internal.util.FastXmlSerializer;
168 import com.android.internal.util.Preconditions;
169 import com.android.internal.util.XmlUtils;
170 import com.android.server.DeviceIdleController;
171 import com.android.server.EventLogTags;
172 import com.android.server.LocalServices;
173 import com.android.server.SystemService;
174 import com.android.server.lights.Light;
175 import com.android.server.lights.LightsManager;
176 import com.android.server.notification.ManagedServices.ManagedServiceInfo;
177 import com.android.server.policy.PhoneWindowManager;
178 import com.android.server.statusbar.StatusBarManagerInternal;
179 import com.android.server.notification.ManagedServices.UserProfiles;
180
181 import libcore.io.IoUtils;
182
183 import org.json.JSONException;
184 import org.json.JSONObject;
185 import org.xmlpull.v1.XmlPullParser;
186 import org.xmlpull.v1.XmlPullParserException;
187 import org.xmlpull.v1.XmlSerializer;
188
189 import java.io.ByteArrayInputStream;
190 import java.io.ByteArrayOutputStream;
191 import java.io.File;
192 import java.io.FileDescriptor;
193 import java.io.FileNotFoundException;
194 import java.io.FileOutputStream;
195 import java.io.IOException;
196 import java.io.InputStream;
197 import java.io.OutputStream;
198 import java.io.PrintWriter;
199 import java.net.URI;
200 import java.nio.charset.StandardCharsets;
201 import java.util.ArrayDeque;
202 import java.util.ArrayList;
203 import java.util.Arrays;
204 import java.util.Iterator;
205 import java.util.List;
206 import java.util.Map.Entry;
207 import java.util.Objects;
208 import java.util.Set;
209 import java.util.concurrent.TimeUnit;
210
211 /** {@hide} */
212 public class NotificationManagerService extends SystemService {
213     static final String TAG = "NotificationService";
214     static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
215     public static final boolean ENABLE_CHILD_NOTIFICATIONS
216             = SystemProperties.getBoolean("debug.child_notifs", true);
217
218     static final int MAX_PACKAGE_NOTIFICATIONS = 50;
219     static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 5f;
220
221     // message codes
222     static final int MESSAGE_TIMEOUT = 2;
223     static final int MESSAGE_SAVE_POLICY_FILE = 3;
224     static final int MESSAGE_SEND_RANKING_UPDATE = 4;
225     static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
226     static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
227
228     // ranking thread messages
229     private static final int MESSAGE_RECONSIDER_RANKING = 1000;
230     private static final int MESSAGE_RANKING_SORT = 1001;
231
232     static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
233     static final int SHORT_DELAY = 2000; // 2 seconds
234
235     static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
236
237     static final long SNOOZE_UNTIL_UNSPECIFIED = -1;
238
239     static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
240
241     static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
242
243     static final boolean ENABLE_BLOCKED_TOASTS = true;
244
245     // When #matchesCallFilter is called from the ringer, wait at most
246     // 3s to resolve the contacts. This timeout is required since
247     // ContactsProvider might take a long time to start up.
248     //
249     // Return STARRED_CONTACT when the timeout is hit in order to avoid
250     // missed calls in ZEN mode "Important".
251     static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
252     static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
253             ValidateNotificationPeople.STARRED_CONTACT;
254
255     /** notification_enqueue status value for a newly enqueued notification. */
256     private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
257
258     /** notification_enqueue status value for an existing notification. */
259     private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
260
261     /** notification_enqueue status value for an ignored notification. */
262     private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
263     private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
264
265     private static final long DELAY_FOR_ASSISTANT_TIME = 100;
266
267     private static final String ACTION_NOTIFICATION_TIMEOUT =
268             NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
269     private static final int REQUEST_CODE_TIMEOUT = 1;
270     private static final String SCHEME_TIMEOUT = "timeout";
271     private static final String EXTRA_KEY = "key";
272
273     private IActivityManager mAm;
274     private ActivityManager mActivityManager;
275     private IPackageManager mPackageManager;
276     private PackageManager mPackageManagerClient;
277     AudioManager mAudioManager;
278     AudioManagerInternal mAudioManagerInternal;
279     @Nullable StatusBarManagerInternal mStatusBar;
280     Vibrator mVibrator;
281     private WindowManagerInternal mWindowManagerInternal;
282     private AlarmManager mAlarmManager;
283     private ICompanionDeviceManager mCompanionManager;
284     private AccessibilityManager mAccessibilityManager;
285
286     final IBinder mForegroundToken = new Binder();
287     private WorkerHandler mHandler;
288     private final HandlerThread mRankingThread = new HandlerThread("ranker",
289             Process.THREAD_PRIORITY_BACKGROUND);
290
291     private Light mNotificationLight;
292     Light mAttentionLight;
293
294     private long[] mFallbackVibrationPattern;
295     private boolean mUseAttentionLight;
296     boolean mSystemReady;
297
298     private boolean mDisableNotificationEffects;
299     private int mCallState;
300     private String mSoundNotificationKey;
301     private String mVibrateNotificationKey;
302
303     private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
304             new SparseArray<>();
305     private List<ComponentName> mEffectsSuppressors = new ArrayList<>();
306     private int mListenerHints;  // right now, all hints are global
307     private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
308
309     // for enabling and disabling notification pulse behavior
310     private boolean mScreenOn = true;
311     protected boolean mInCall = false;
312     private boolean mNotificationPulseEnabled;
313
314     private Uri mInCallNotificationUri;
315     private AudioAttributes mInCallNotificationAudioAttributes;
316     private float mInCallNotificationVolume;
317
318     // used as a mutex for access to all active notifications & listeners
319     final Object mNotificationLock = new Object();
320     @GuardedBy("mNotificationLock")
321     final ArrayList<NotificationRecord> mNotificationList = new ArrayList<>();
322     @GuardedBy("mNotificationLock")
323     final ArrayMap<String, NotificationRecord> mNotificationsByKey = new ArrayMap<>();
324     @GuardedBy("mNotificationLock")
325     final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();
326     @GuardedBy("mNotificationLock")
327     final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
328     final ArrayList<ToastRecord> mToastQueue = new ArrayList<>();
329     final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
330
331     // The last key in this list owns the hardware.
332     ArrayList<String> mLights = new ArrayList<>();
333
334     private AppOpsManager mAppOps;
335     private UsageStatsManagerInternal mAppUsageStats;
336
337     private Archive mArchive;
338
339     // Persistent storage for notification policy
340     private AtomicFile mPolicyFile;
341
342     private static final int DB_VERSION = 1;
343
344     private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
345     private static final String ATTR_VERSION = "version";
346
347     private RankingHelper mRankingHelper;
348
349     private final UserProfiles mUserProfiles = new UserProfiles();
350     private NotificationListeners mListeners;
351     private NotificationAssistants mAssistants;
352     private ConditionProviders mConditionProviders;
353     private NotificationUsageStats mUsageStats;
354
355     private static final int MY_UID = Process.myUid();
356     private static final int MY_PID = Process.myPid();
357     private static final IBinder WHITELIST_TOKEN = new Binder();
358     private RankingHandler mRankingHandler;
359     private long mLastOverRateLogTime;
360     private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
361
362     private SnoozeHelper mSnoozeHelper;
363     private GroupHelper mGroupHelper;
364     private boolean mIsTelevision;
365
366     private static class Archive {
367         final int mBufferSize;
368         final ArrayDeque<StatusBarNotification> mBuffer;
369
370         public Archive(int size) {
371             mBufferSize = size;
372             mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
373         }
374
375         public String toString() {
376             final StringBuilder sb = new StringBuilder();
377             final int N = mBuffer.size();
378             sb.append("Archive (");
379             sb.append(N);
380             sb.append(" notification");
381             sb.append((N==1)?")":"s)");
382             return sb.toString();
383         }
384
385         public void record(StatusBarNotification nr) {
386             if (mBuffer.size() == mBufferSize) {
387                 mBuffer.removeFirst();
388             }
389
390             // We don't want to store the heavy bits of the notification in the archive,
391             // but other clients in the system process might be using the object, so we
392             // store a (lightened) copy.
393             mBuffer.addLast(nr.cloneLight());
394         }
395
396         public Iterator<StatusBarNotification> descendingIterator() {
397             return mBuffer.descendingIterator();
398         }
399
400         public StatusBarNotification[] getArray(int count) {
401             if (count == 0) count = mBufferSize;
402             final StatusBarNotification[] a
403                     = new StatusBarNotification[Math.min(count, mBuffer.size())];
404             Iterator<StatusBarNotification> iter = descendingIterator();
405             int i=0;
406             while (iter.hasNext() && i < count) {
407                 a[i++] = iter.next();
408             }
409             return a;
410         }
411
412     }
413
414     protected void readDefaultApprovedServices(int userId) {
415         String defaultListenerAccess = getContext().getResources().getString(
416                 com.android.internal.R.string.config_defaultListenerAccessPackages);
417         if (defaultListenerAccess != null) {
418             for (String whitelisted :
419                     defaultListenerAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
420                 // Gather all notification listener components for candidate pkgs.
421                 Set<ComponentName> approvedListeners =
422                         mListeners.queryPackageForServices(whitelisted,
423                                 PackageManager.MATCH_DIRECT_BOOT_AWARE
424                                         | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
425                 for (ComponentName cn : approvedListeners) {
426                     try {
427                         getBinderService().setNotificationListenerAccessGrantedForUser(cn,
428                                     userId, true);
429                     } catch (RemoteException e) {
430                         e.printStackTrace();
431                     }
432                 }
433             }
434         }
435         String defaultDndAccess = getContext().getResources().getString(
436                 com.android.internal.R.string.config_defaultDndAccessPackages);
437         if (defaultListenerAccess != null) {
438             for (String whitelisted :
439                     defaultDndAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
440                 try {
441                     getBinderService().setNotificationPolicyAccessGranted(whitelisted, true);
442                 } catch (RemoteException e) {
443                     e.printStackTrace();
444                 }
445             }
446         }
447     }
448
449     void readPolicyXml(InputStream stream, boolean forRestore)
450             throws XmlPullParserException, NumberFormatException, IOException {
451         final XmlPullParser parser = Xml.newPullParser();
452         parser.setInput(stream, StandardCharsets.UTF_8.name());
453         XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY);
454         boolean migratedManagedServices = false;
455         int outerDepth = parser.getDepth();
456         while (XmlUtils.nextElementWithin(parser, outerDepth)) {
457             if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) {
458                 mZenModeHelper.readXml(parser, forRestore);
459             } else if (RankingHelper.TAG_RANKING.equals(parser.getName())){
460                 mRankingHelper.readXml(parser, forRestore);
461             }
462             // No non-system managed services are allowed on low ram devices
463             if (!ActivityManager.isLowRamDeviceStatic()) {
464                 if (mListeners.getConfig().xmlTag.equals(parser.getName())) {
465                     mListeners.readXml(parser);
466                     migratedManagedServices = true;
467                 } else if (mAssistants.getConfig().xmlTag.equals(parser.getName())) {
468                     mAssistants.readXml(parser);
469                     migratedManagedServices = true;
470                 } else if (mConditionProviders.getConfig().xmlTag.equals(parser.getName())) {
471                     mConditionProviders.readXml(parser);
472                     migratedManagedServices = true;
473                 }
474             }
475         }
476
477         if (!migratedManagedServices) {
478             mListeners.migrateToXml();
479             mAssistants.migrateToXml();
480             mConditionProviders.migrateToXml();
481             savePolicyFile();
482         }
483     }
484
485     private void loadPolicyFile() {
486         if (DBG) Slog.d(TAG, "loadPolicyFile");
487         synchronized (mPolicyFile) {
488
489             InputStream infile = null;
490             try {
491                 infile = mPolicyFile.openRead();
492                 readPolicyXml(infile, false /*forRestore*/);
493             } catch (FileNotFoundException e) {
494                 // No data yet
495                 // Load default managed services approvals
496                 readDefaultApprovedServices(UserHandle.USER_SYSTEM);
497             } catch (IOException e) {
498                 Log.wtf(TAG, "Unable to read notification policy", e);
499             } catch (NumberFormatException e) {
500                 Log.wtf(TAG, "Unable to parse notification policy", e);
501             } catch (XmlPullParserException e) {
502                 Log.wtf(TAG, "Unable to parse notification policy", e);
503             } finally {
504                 IoUtils.closeQuietly(infile);
505             }
506         }
507     }
508
509     public void savePolicyFile() {
510         mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
511         mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
512     }
513
514     private void handleSavePolicyFile() {
515         if (DBG) Slog.d(TAG, "handleSavePolicyFile");
516         synchronized (mPolicyFile) {
517             final FileOutputStream stream;
518             try {
519                 stream = mPolicyFile.startWrite();
520             } catch (IOException e) {
521                 Slog.w(TAG, "Failed to save policy file", e);
522                 return;
523             }
524
525             try {
526                 writePolicyXml(stream, false /*forBackup*/);
527                 mPolicyFile.finishWrite(stream);
528             } catch (IOException e) {
529                 Slog.w(TAG, "Failed to save policy file, restoring backup", e);
530                 mPolicyFile.failWrite(stream);
531             }
532         }
533         BackupManager.dataChanged(getContext().getPackageName());
534     }
535
536     private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
537         final XmlSerializer out = new FastXmlSerializer();
538         out.setOutput(stream, StandardCharsets.UTF_8.name());
539         out.startDocument(null, true);
540         out.startTag(null, TAG_NOTIFICATION_POLICY);
541         out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
542         mZenModeHelper.writeXml(out, forBackup);
543         mRankingHelper.writeXml(out, forBackup);
544         mListeners.writeXml(out, forBackup);
545         mAssistants.writeXml(out, forBackup);
546         mConditionProviders.writeXml(out, forBackup);
547         out.endTag(null, TAG_NOTIFICATION_POLICY);
548         out.endDocument();
549     }
550
551     /** Use this to check if a package can post a notification or toast. */
552     private boolean checkNotificationOp(String pkg, int uid) {
553         return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
554                 == AppOpsManager.MODE_ALLOWED && !isPackageSuspendedForUser(pkg, uid);
555     }
556
557     private static final class ToastRecord
558     {
559         final int pid;
560         final String pkg;
561         ITransientNotification callback;
562         int duration;
563         Binder token;
564
565         ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
566                     Binder token) {
567             this.pid = pid;
568             this.pkg = pkg;
569             this.callback = callback;
570             this.duration = duration;
571             this.token = token;
572         }
573
574         void update(int duration) {
575             this.duration = duration;
576         }
577
578         void update(ITransientNotification callback) {
579             this.callback = callback;
580         }
581
582         void dump(PrintWriter pw, String prefix, DumpFilter filter) {
583             if (filter != null && !filter.matches(pkg)) return;
584             pw.println(prefix + this);
585         }
586
587         @Override
588         public final String toString()
589         {
590             return "ToastRecord{"
591                 + Integer.toHexString(System.identityHashCode(this))
592                 + " pkg=" + pkg
593                 + " callback=" + callback
594                 + " duration=" + duration;
595         }
596     }
597
598     @VisibleForTesting
599     final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
600
601         @Override
602         public void onSetDisabled(int status) {
603             synchronized (mNotificationLock) {
604                 mDisableNotificationEffects =
605                         (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
606                 if (disableNotificationEffects(null) != null) {
607                     // cancel whatever's going on
608                     long identity = Binder.clearCallingIdentity();
609                     try {
610                         final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
611                         if (player != null) {
612                             player.stopAsync();
613                         }
614                     } catch (RemoteException e) {
615                     } finally {
616                         Binder.restoreCallingIdentity(identity);
617                     }
618
619                     identity = Binder.clearCallingIdentity();
620                     try {
621                         mVibrator.cancel();
622                     } finally {
623                         Binder.restoreCallingIdentity(identity);
624                     }
625                 }
626             }
627         }
628
629         @Override
630         public void onClearAll(int callingUid, int callingPid, int userId) {
631             synchronized (mNotificationLock) {
632                 cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null,
633                         /*includeCurrentProfiles*/ true);
634             }
635         }
636
637         @Override
638         public void onNotificationClick(int callingUid, int callingPid, String key) {
639             synchronized (mNotificationLock) {
640                 NotificationRecord r = mNotificationsByKey.get(key);
641                 if (r == null) {
642                     Log.w(TAG, "No notification with key: " + key);
643                     return;
644                 }
645                 final long now = System.currentTimeMillis();
646                 MetricsLogger.action(r.getLogMaker(now)
647                         .setCategory(MetricsEvent.NOTIFICATION_ITEM)
648                         .setType(MetricsEvent.TYPE_ACTION));
649                 EventLogTags.writeNotificationClicked(key,
650                         r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
651
652                 StatusBarNotification sbn = r.sbn;
653                 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
654                         sbn.getId(), Notification.FLAG_AUTO_CANCEL,
655                         Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
656                         REASON_CLICK, null);
657             }
658         }
659
660         @Override
661         public void onNotificationActionClick(int callingUid, int callingPid, String key,
662                 int actionIndex) {
663             synchronized (mNotificationLock) {
664                 NotificationRecord r = mNotificationsByKey.get(key);
665                 if (r == null) {
666                     Log.w(TAG, "No notification with key: " + key);
667                     return;
668                 }
669                 final long now = System.currentTimeMillis();
670                 MetricsLogger.action(r.getLogMaker(now)
671                         .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION)
672                         .setType(MetricsEvent.TYPE_ACTION)
673                         .setSubtype(actionIndex));
674                 EventLogTags.writeNotificationActionClicked(key, actionIndex,
675                         r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
676                 // TODO: Log action click via UsageStats.
677             }
678         }
679
680         @Override
681         public void onNotificationClear(int callingUid, int callingPid,
682                 String pkg, String tag, int id, int userId) {
683             cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
684                     Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
685                     true, userId, REASON_CANCEL, null);
686         }
687
688         @Override
689         public void onPanelRevealed(boolean clearEffects, int items) {
690             MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL);
691             MetricsLogger.histogram(getContext(), "note_load", items);
692             EventLogTags.writeNotificationPanelRevealed(items);
693             if (clearEffects) {
694                 clearEffects();
695             }
696         }
697
698         @Override
699         public void onPanelHidden() {
700             MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL);
701             EventLogTags.writeNotificationPanelHidden();
702         }
703
704         @Override
705         public void clearEffects() {
706             synchronized (mNotificationLock) {
707                 if (DBG) Slog.d(TAG, "clearEffects");
708                 clearSoundLocked();
709                 clearVibrateLocked();
710                 clearLightsLocked();
711             }
712         }
713
714         @Override
715         public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
716                 int uid, int initialPid, String message, int userId) {
717             Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
718                     + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
719             cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
720                     REASON_ERROR, null);
721             long ident = Binder.clearCallingIdentity();
722             try {
723                 ActivityManager.getService().crashApplication(uid, initialPid, pkg, -1,
724                         "Bad notification posted from package " + pkg
725                         + ": " + message);
726             } catch (RemoteException e) {
727             }
728             Binder.restoreCallingIdentity(ident);
729         }
730
731         @Override
732         public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
733                 NotificationVisibility[] noLongerVisibleKeys) {
734             synchronized (mNotificationLock) {
735                 for (NotificationVisibility nv : newlyVisibleKeys) {
736                     NotificationRecord r = mNotificationsByKey.get(nv.key);
737                     if (r == null) continue;
738                     r.setVisibility(true, nv.rank);
739                     nv.recycle();
740                 }
741                 // Note that we might receive this event after notifications
742                 // have already left the system, e.g. after dismissing from the
743                 // shade. Hence not finding notifications in
744                 // mNotificationsByKey is not an exceptional condition.
745                 for (NotificationVisibility nv : noLongerVisibleKeys) {
746                     NotificationRecord r = mNotificationsByKey.get(nv.key);
747                     if (r == null) continue;
748                     r.setVisibility(false, nv.rank);
749                     nv.recycle();
750                 }
751             }
752         }
753
754         @Override
755         public void onNotificationExpansionChanged(String key,
756                 boolean userAction, boolean expanded) {
757             synchronized (mNotificationLock) {
758                 NotificationRecord r = mNotificationsByKey.get(key);
759                 if (r != null) {
760                     r.stats.onExpansionChanged(userAction, expanded);
761                     final long now = System.currentTimeMillis();
762                     if (userAction) {
763                         MetricsLogger.action(r.getLogMaker(now)
764                                 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
765                                 .setType(expanded ? MetricsEvent.TYPE_DETAIL
766                                         : MetricsEvent.TYPE_COLLAPSE));
767                     }
768                     EventLogTags.writeNotificationExpansion(key,
769                             userAction ? 1 : 0, expanded ? 1 : 0,
770                             r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
771                 }
772             }
773         }
774     };
775
776     @GuardedBy("mNotificationLock")
777     private void clearSoundLocked() {
778         mSoundNotificationKey = null;
779         long identity = Binder.clearCallingIdentity();
780         try {
781             final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
782             if (player != null) {
783                 player.stopAsync();
784             }
785         } catch (RemoteException e) {
786         } finally {
787             Binder.restoreCallingIdentity(identity);
788         }
789     }
790
791     @GuardedBy("mNotificationLock")
792     private void clearVibrateLocked() {
793         mVibrateNotificationKey = null;
794         long identity = Binder.clearCallingIdentity();
795         try {
796             mVibrator.cancel();
797         } finally {
798             Binder.restoreCallingIdentity(identity);
799         }
800     }
801
802     @GuardedBy("mNotificationLock")
803     private void clearLightsLocked() {
804         // light
805         mLights.clear();
806         updateLightsLocked();
807     }
808
809     protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() {
810         @Override
811         public void onReceive(Context context, Intent intent) {
812             if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
813                 mZenModeHelper.updateDefaultZenRules();
814                 mRankingHelper.onLocaleChanged(context, ActivityManager.getCurrentUser());
815             }
816         }
817     };
818
819     private final BroadcastReceiver mRestoreReceiver = new BroadcastReceiver() {
820         @Override
821         public void onReceive(Context context, Intent intent) {
822             if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
823                 try {
824                     String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
825                     String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
826                     int restoredFromSdkInt = intent.getIntExtra(
827                             Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, 0);
828                     mListeners.onSettingRestored(
829                             element, newValue, restoredFromSdkInt, getSendingUserId());
830                     mConditionProviders.onSettingRestored(
831                             element, newValue, restoredFromSdkInt, getSendingUserId());
832                 } catch (Exception e) {
833                     Slog.wtf(TAG, "Cannot restore managed services from settings", e);
834                 }
835             }
836         }
837     };
838
839     private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() {
840         @Override
841         public void onReceive(Context context, Intent intent) {
842             String action = intent.getAction();
843             if (action == null) {
844                 return;
845             }
846             if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) {
847                 final NotificationRecord record;
848                 synchronized (mNotificationLock) {
849                     record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
850                 }
851                 if (record != null) {
852                     cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(),
853                             record.sbn.getPackageName(), record.sbn.getTag(),
854                             record.sbn.getId(), 0,
855                             Notification.FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
856                             REASON_TIMEOUT, null);
857                 }
858             }
859         }
860     };
861
862     private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
863         @Override
864         public void onReceive(Context context, Intent intent) {
865             String action = intent.getAction();
866             if (action == null) {
867                 return;
868             }
869
870             boolean queryRestart = false;
871             boolean queryRemove = false;
872             boolean packageChanged = false;
873             boolean cancelNotifications = true;
874             int reason = REASON_PACKAGE_CHANGED;
875
876             if (action.equals(Intent.ACTION_PACKAGE_ADDED)
877                     || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
878                     || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
879                     || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
880                     || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
881                     || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
882                     || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
883                 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
884                         UserHandle.USER_ALL);
885                 String pkgList[] = null;
886                 int uidList[] = null;
887                 boolean removingPackage = queryRemove &&
888                         !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
889                 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
890                 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
891                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
892                     uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
893                 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
894                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
895                     reason = REASON_PACKAGE_SUSPENDED;
896                 } else if (queryRestart) {
897                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
898                     uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
899                 } else {
900                     Uri uri = intent.getData();
901                     if (uri == null) {
902                         return;
903                     }
904                     String pkgName = uri.getSchemeSpecificPart();
905                     if (pkgName == null) {
906                         return;
907                     }
908                     if (packageChanged) {
909                         // We cancel notifications for packages which have just been disabled
910                         try {
911                             final int enabled = mPackageManager.getApplicationEnabledSetting(
912                                     pkgName,
913                                     changeUserId != UserHandle.USER_ALL ? changeUserId :
914                                             UserHandle.USER_SYSTEM);
915                             if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
916                                     || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
917                                 cancelNotifications = false;
918                             }
919                         } catch (IllegalArgumentException e) {
920                             // Package doesn't exist; probably racing with uninstall.
921                             // cancelNotifications is already true, so nothing to do here.
922                             if (DBG) {
923                                 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
924                             }
925                         } catch (RemoteException e) {
926                             // Failed to talk to PackageManagerService Should never happen!
927                         }
928                     }
929                     pkgList = new String[]{pkgName};
930                     uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
931                 }
932                 if (pkgList != null && (pkgList.length > 0)) {
933                     for (String pkgName : pkgList) {
934                         if (cancelNotifications) {
935                             cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0,
936                                     !queryRestart, changeUserId, reason, null);
937                         }
938                     }
939                 }
940                 mListeners.onPackagesChanged(removingPackage, pkgList, uidList);
941                 mAssistants.onPackagesChanged(removingPackage, pkgList, uidList);
942                 mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList);
943                 mRankingHelper.onPackagesChanged(removingPackage, changeUserId, pkgList, uidList);
944                 savePolicyFile();
945             }
946         }
947     };
948
949     private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
950         @Override
951         public void onReceive(Context context, Intent intent) {
952             String action = intent.getAction();
953
954             if (action.equals(Intent.ACTION_SCREEN_ON)) {
955                 // Keep track of screen on/off state, but do not turn off the notification light
956                 // until user passes through the lock screen or views the notification.
957                 mScreenOn = true;
958                 updateNotificationPulse();
959             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
960                 mScreenOn = false;
961                 updateNotificationPulse();
962             } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
963                 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
964                         .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
965                 updateNotificationPulse();
966             } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
967                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
968                 if (userHandle >= 0) {
969                     cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
970                             REASON_USER_STOPPED, null);
971                 }
972             } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
973                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
974                 if (userHandle >= 0) {
975                     cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
976                             REASON_PROFILE_TURNED_OFF, null);
977                 }
978             } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
979                 // turn off LED when user passes through lock screen
980                 mNotificationLight.turnOff();
981             } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
982                 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
983                 // reload per-user settings
984                 mSettingsObserver.update(null);
985                 mUserProfiles.updateCache(context);
986                 // Refresh managed services
987                 mConditionProviders.onUserSwitched(user);
988                 mListeners.onUserSwitched(user);
989                 mAssistants.onUserSwitched(user);
990                 mZenModeHelper.onUserSwitched(user);
991             } else if (action.equals(Intent.ACTION_USER_ADDED)) {
992                 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
993                 if (userId != USER_NULL) {
994                     mUserProfiles.updateCache(context);
995                     if (!mUserProfiles.isManagedProfile(userId)) {
996                         readDefaultApprovedServices(userId);
997                     }
998                 }
999             } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
1000                 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1001                 mZenModeHelper.onUserRemoved(user);
1002                 mRankingHelper.onUserRemoved(user);
1003                 mListeners.onUserRemoved(user);
1004                 mConditionProviders.onUserRemoved(user);
1005                 mAssistants.onUserRemoved(user);
1006                 savePolicyFile();
1007             } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
1008                 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1009                 mConditionProviders.onUserUnlocked(user);
1010                 mListeners.onUserUnlocked(user);
1011                 mAssistants.onUserUnlocked(user);
1012                 mZenModeHelper.onUserUnlocked(user);
1013             }
1014         }
1015     };
1016
1017     private final class SettingsObserver extends ContentObserver {
1018         private final Uri NOTIFICATION_BADGING_URI
1019                 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING);
1020         private final Uri NOTIFICATION_LIGHT_PULSE_URI
1021                 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
1022         private final Uri NOTIFICATION_RATE_LIMIT_URI
1023                 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
1024
1025         SettingsObserver(Handler handler) {
1026             super(handler);
1027         }
1028
1029         void observe() {
1030             ContentResolver resolver = getContext().getContentResolver();
1031             resolver.registerContentObserver(NOTIFICATION_BADGING_URI,
1032                     false, this, UserHandle.USER_ALL);
1033             resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
1034                     false, this, UserHandle.USER_ALL);
1035             resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
1036                     false, this, UserHandle.USER_ALL);
1037             update(null);
1038         }
1039
1040         @Override public void onChange(boolean selfChange, Uri uri) {
1041             update(uri);
1042         }
1043
1044         public void update(Uri uri) {
1045             ContentResolver resolver = getContext().getContentResolver();
1046             if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
1047                 boolean pulseEnabled = Settings.System.getIntForUser(resolver,
1048                             Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT) != 0;
1049                 if (mNotificationPulseEnabled != pulseEnabled) {
1050                     mNotificationPulseEnabled = pulseEnabled;
1051                     updateNotificationPulse();
1052                 }
1053             }
1054             if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
1055                 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
1056                             Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
1057             }
1058             if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) {
1059                 mRankingHelper.updateBadgingEnabled();
1060             }
1061         }
1062     }
1063
1064     private SettingsObserver mSettingsObserver;
1065     protected ZenModeHelper mZenModeHelper;
1066
1067     static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
1068         int[] ar = r.getIntArray(resid);
1069         if (ar == null) {
1070             return def;
1071         }
1072         final int len = ar.length > maxlen ? maxlen : ar.length;
1073         long[] out = new long[len];
1074         for (int i=0; i<len; i++) {
1075             out[i] = ar[i];
1076         }
1077         return out;
1078     }
1079
1080     public NotificationManagerService(Context context) {
1081         super(context);
1082         Notification.processWhitelistToken = WHITELIST_TOKEN;
1083     }
1084
1085     // TODO - replace these methods with a single VisibleForTesting constructor
1086     @VisibleForTesting
1087     void setAudioManager(AudioManager audioMananger) {
1088         mAudioManager = audioMananger;
1089     }
1090
1091     @VisibleForTesting
1092     void setVibrator(Vibrator vibrator) {
1093         mVibrator = vibrator;
1094     }
1095
1096     @VisibleForTesting
1097     void setLights(Light light) {
1098         mNotificationLight = light;
1099         mAttentionLight = light;
1100         mNotificationPulseEnabled = true;
1101     }
1102
1103     @VisibleForTesting
1104     void setScreenOn(boolean on) {
1105         mScreenOn = on;
1106     }
1107
1108     @VisibleForTesting
1109     int getNotificationRecordCount() {
1110         synchronized (mNotificationLock) {
1111             int count = mNotificationList.size() + mNotificationsByKey.size()
1112                     + mSummaryByGroupKey.size() + mEnqueuedNotifications.size();
1113             // subtract duplicates
1114             for (NotificationRecord posted : mNotificationList) {
1115                 if (mNotificationsByKey.containsKey(posted.getKey())) {
1116                     count--;
1117                 }
1118                 if (posted.sbn.isGroup() && posted.getNotification().isGroupSummary()) {
1119                     count--;
1120                 }
1121             }
1122
1123             return count;
1124         }
1125     }
1126
1127     void clearNotifications() {
1128         mEnqueuedNotifications.clear();
1129         mNotificationList.clear();
1130         mNotificationsByKey.clear();
1131         mSummaryByGroupKey.clear();
1132     }
1133
1134     @VisibleForTesting
1135     void addNotification(NotificationRecord r) {
1136         mNotificationList.add(r);
1137         mNotificationsByKey.put(r.sbn.getKey(), r);
1138         if (r.sbn.isGroup()) {
1139             mSummaryByGroupKey.put(r.getGroupKey(), r);
1140         }
1141     }
1142
1143     @VisibleForTesting
1144     void addEnqueuedNotification(NotificationRecord r) {
1145         mEnqueuedNotifications.add(r);
1146     }
1147
1148     @VisibleForTesting
1149     NotificationRecord getNotificationRecord(String key) {
1150         return mNotificationsByKey.get(key);
1151     }
1152
1153
1154     @VisibleForTesting
1155     void setSystemReady(boolean systemReady) {
1156         mSystemReady = systemReady;
1157     }
1158
1159     @VisibleForTesting
1160     void setHandler(WorkerHandler handler) {
1161         mHandler = handler;
1162     }
1163
1164     @VisibleForTesting
1165     void setFallbackVibrationPattern(long[] vibrationPattern) {
1166         mFallbackVibrationPattern = vibrationPattern;
1167     }
1168
1169     @VisibleForTesting
1170     void setPackageManager(IPackageManager packageManager) {
1171         mPackageManager = packageManager;
1172     }
1173
1174     @VisibleForTesting
1175     void setRankingHelper(RankingHelper rankingHelper) {
1176         mRankingHelper = rankingHelper;
1177     }
1178
1179     @VisibleForTesting
1180     void setRankingHandler(RankingHandler rankingHandler) {
1181         mRankingHandler = rankingHandler;
1182     }
1183
1184     @VisibleForTesting
1185     void setIsTelevision(boolean isTelevision) {
1186         mIsTelevision = isTelevision;
1187     }
1188
1189     @VisibleForTesting
1190     void setUsageStats(NotificationUsageStats us) {
1191         mUsageStats = us;
1192     }
1193
1194     @VisibleForTesting
1195     void setAccessibilityManager(AccessibilityManager am) {
1196         mAccessibilityManager = am;
1197     }
1198
1199     // TODO: All tests should use this init instead of the one-off setters above.
1200     @VisibleForTesting
1201     void init(Looper looper, IPackageManager packageManager,
1202             PackageManager packageManagerClient,
1203             LightsManager lightsManager, NotificationListeners notificationListeners,
1204             NotificationAssistants notificationAssistants, ConditionProviders conditionProviders,
1205             ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
1206             NotificationUsageStats usageStats, AtomicFile policyFile,
1207             ActivityManager activityManager, GroupHelper groupHelper) {
1208         Resources resources = getContext().getResources();
1209         mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
1210                 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
1211                 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
1212
1213         mAccessibilityManager =
1214                 (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
1215         mAm = ActivityManager.getService();
1216         mPackageManager = packageManager;
1217         mPackageManagerClient = packageManagerClient;
1218         mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
1219         mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
1220         mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
1221         mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
1222         mCompanionManager = companionManager;
1223         mActivityManager = activityManager;
1224
1225         mHandler = new WorkerHandler(looper);
1226         mRankingThread.start();
1227         String[] extractorNames;
1228         try {
1229             extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
1230         } catch (Resources.NotFoundException e) {
1231             extractorNames = new String[0];
1232         }
1233         mUsageStats = usageStats;
1234         mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
1235         mRankingHelper = new RankingHelper(getContext(),
1236                 mPackageManagerClient,
1237                 mRankingHandler,
1238                 mUsageStats,
1239                 extractorNames);
1240         mConditionProviders = conditionProviders;
1241         mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
1242         mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
1243             @Override
1244             public void onConfigChanged() {
1245                 savePolicyFile();
1246             }
1247
1248             @Override
1249             void onZenModeChanged() {
1250                 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
1251                 getContext().sendBroadcastAsUser(
1252                         new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
1253                                 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
1254                         UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
1255                 synchronized (mNotificationLock) {
1256                     updateInterruptionFilterLocked();
1257                 }
1258             }
1259
1260             @Override
1261             void onPolicyChanged() {
1262                 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
1263             }
1264         });
1265         mSnoozeHelper = snoozeHelper;
1266         mGroupHelper = groupHelper;
1267
1268         // This is a ManagedServices object that keeps track of the listeners.
1269         mListeners = notificationListeners;
1270
1271         // This is a MangedServices object that keeps track of the assistant.
1272         mAssistants = notificationAssistants;
1273
1274         mPolicyFile = policyFile;
1275         loadPolicyFile();
1276
1277         mStatusBar = getLocalService(StatusBarManagerInternal.class);
1278         if (mStatusBar != null) {
1279             mStatusBar.setNotificationDelegate(mNotificationDelegate);
1280         }
1281
1282         mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
1283         mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
1284
1285         mFallbackVibrationPattern = getLongArray(resources,
1286                 R.array.config_notificationFallbackVibePattern,
1287                 VIBRATE_PATTERN_MAXLEN,
1288                 DEFAULT_VIBRATE_PATTERN);
1289         mInCallNotificationUri = Uri.parse("file://" +
1290                 resources.getString(R.string.config_inCallNotificationSound));
1291         mInCallNotificationAudioAttributes = new AudioAttributes.Builder()
1292                 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
1293                 .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
1294                 .build();
1295         mInCallNotificationVolume = resources.getFloat(R.dimen.config_inCallNotificationVolume);
1296
1297         mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
1298
1299         // Don't start allowing notifications until the setup wizard has run once.
1300         // After that, including subsequent boots, init with notifications turned on.
1301         // This works on the first boot because the setup wizard will toggle this
1302         // flag at least once and we'll go back to 0 after that.
1303         if (0 == Settings.Global.getInt(getContext().getContentResolver(),
1304                     Settings.Global.DEVICE_PROVISIONED, 0)) {
1305             mDisableNotificationEffects = true;
1306         }
1307         mZenModeHelper.initZenMode();
1308         mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1309
1310         mUserProfiles.updateCache(getContext());
1311         listenForCallState();
1312
1313         mSettingsObserver = new SettingsObserver(mHandler);
1314
1315         mArchive = new Archive(resources.getInteger(
1316                 R.integer.config_notificationServiceArchiveSize));
1317
1318         mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
1319                 || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
1320     }
1321
1322     @Override
1323     public void onStart() {
1324         SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() {
1325             @Override
1326             public void repost(int userId, NotificationRecord r) {
1327                 try {
1328                     if (DBG) {
1329                         Slog.d(TAG, "Reposting " + r.getKey());
1330                     }
1331                     enqueueNotificationInternal(r.sbn.getPackageName(), r.sbn.getOpPkg(),
1332                             r.sbn.getUid(), r.sbn.getInitialPid(), r.sbn.getTag(), r.sbn.getId(),
1333                             r.sbn.getNotification(), userId);
1334                 } catch (Exception e) {
1335                     Slog.e(TAG, "Cannot un-snooze notification", e);
1336                 }
1337             }
1338         }, mUserProfiles);
1339
1340         final File systemDir = new File(Environment.getDataDirectory(), "system");
1341
1342         init(Looper.myLooper(),
1343                 AppGlobals.getPackageManager(), getContext().getPackageManager(),
1344                 getLocalService(LightsManager.class),
1345                 new NotificationListeners(AppGlobals.getPackageManager()),
1346                 new NotificationAssistants(AppGlobals.getPackageManager()),
1347                 new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()),
1348                 null, snoozeHelper, new NotificationUsageStats(getContext()),
1349                 new AtomicFile(new File(systemDir, "notification_policy.xml")),
1350                 (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE),
1351                 getGroupHelper());
1352
1353         // register for various Intents
1354         IntentFilter filter = new IntentFilter();
1355         filter.addAction(Intent.ACTION_SCREEN_ON);
1356         filter.addAction(Intent.ACTION_SCREEN_OFF);
1357         filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
1358         filter.addAction(Intent.ACTION_USER_PRESENT);
1359         filter.addAction(Intent.ACTION_USER_STOPPED);
1360         filter.addAction(Intent.ACTION_USER_SWITCHED);
1361         filter.addAction(Intent.ACTION_USER_ADDED);
1362         filter.addAction(Intent.ACTION_USER_REMOVED);
1363         filter.addAction(Intent.ACTION_USER_UNLOCKED);
1364         filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
1365         getContext().registerReceiver(mIntentReceiver, filter);
1366
1367         IntentFilter pkgFilter = new IntentFilter();
1368         pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
1369         pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1370         pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
1371         pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1372         pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1373         pkgFilter.addDataScheme("package");
1374         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1375                 null);
1376
1377         IntentFilter suspendedPkgFilter = new IntentFilter();
1378         suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
1379         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1380                 suspendedPkgFilter, null, null);
1381
1382         IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
1383         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1384                 null);
1385
1386         IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
1387         timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
1388         getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter);
1389
1390         IntentFilter settingsRestoredFilter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
1391         getContext().registerReceiver(mRestoreReceiver, settingsRestoredFilter);
1392
1393         IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
1394         getContext().registerReceiver(mLocaleChangeReceiver, localeChangedFilter);
1395
1396         publishBinderService(Context.NOTIFICATION_SERVICE, mService);
1397         publishLocalService(NotificationManagerInternal.class, mInternalService);
1398     }
1399
1400     private GroupHelper getGroupHelper() {
1401         return new GroupHelper(new GroupHelper.Callback() {
1402             @Override
1403             public void addAutoGroup(String key) {
1404                 synchronized (mNotificationLock) {
1405                     addAutogroupKeyLocked(key);
1406                 }
1407             }
1408
1409             @Override
1410             public void removeAutoGroup(String key) {
1411                 synchronized (mNotificationLock) {
1412                     removeAutogroupKeyLocked(key);
1413                 }
1414             }
1415
1416             @Override
1417             public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) {
1418                 createAutoGroupSummary(userId, pkg, triggeringKey);
1419             }
1420
1421             @Override
1422             public void removeAutoGroupSummary(int userId, String pkg) {
1423                 synchronized (mNotificationLock) {
1424                     clearAutogroupSummaryLocked(userId, pkg);
1425                 }
1426             }
1427         });
1428     }
1429
1430     private void sendRegisteredOnlyBroadcast(String action) {
1431         getContext().sendBroadcastAsUser(new Intent(action)
1432                 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
1433     }
1434
1435     @Override
1436     public void onBootPhase(int phase) {
1437         if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1438             // no beeping until we're basically done booting
1439             mSystemReady = true;
1440
1441             // Grab our optional AudioService
1442             mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
1443             mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
1444             mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
1445             mZenModeHelper.onSystemReady();
1446         } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1447             // This observer will force an update when observe is called, causing us to
1448             // bind to listener services.
1449             mSettingsObserver.observe();
1450             mListeners.onBootPhaseAppsCanStart();
1451             mAssistants.onBootPhaseAppsCanStart();
1452             mConditionProviders.onBootPhaseAppsCanStart();
1453         }
1454     }
1455
1456     @GuardedBy("mNotificationLock")
1457     private void updateListenerHintsLocked() {
1458         final int hints = calculateHints();
1459         if (hints == mListenerHints) return;
1460         ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
1461         mListenerHints = hints;
1462         scheduleListenerHintsChanged(hints);
1463     }
1464
1465     @GuardedBy("mNotificationLock")
1466     private void updateEffectsSuppressorLocked() {
1467         final long updatedSuppressedEffects = calculateSuppressedEffects();
1468         if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1469         final List<ComponentName> suppressors = getSuppressors();
1470         ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1471         mEffectsSuppressors = suppressors;
1472         mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
1473         sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
1474     }
1475
1476     private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
1477             boolean fromListener) {
1478         if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
1479             // cancel
1480             cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
1481                     UserHandle.getUserId(uid), REASON_CHANNEL_BANNED,
1482                     null);
1483             if (isUidSystemOrPhone(uid)) {
1484                 int[] profileIds = mUserProfiles.getCurrentProfileIds();
1485                 int N = profileIds.length;
1486                 for (int i = 0; i < N; i++) {
1487                     int profileId = profileIds[i];
1488                     cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
1489                             profileId, REASON_CHANNEL_BANNED,
1490                             null);
1491                 }
1492             }
1493         }
1494         mRankingHelper.updateNotificationChannel(pkg, uid, channel, true);
1495
1496         if (!fromListener) {
1497             final NotificationChannel modifiedChannel =
1498                     mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
1499             mListeners.notifyNotificationChannelChanged(
1500                     pkg, UserHandle.getUserHandleForUid(uid),
1501                     modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
1502         }
1503
1504         savePolicyFile();
1505     }
1506
1507     private ArrayList<ComponentName> getSuppressors() {
1508         ArrayList<ComponentName> names = new ArrayList<ComponentName>();
1509         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1510             ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1511
1512             for (ManagedServiceInfo info : serviceInfoList) {
1513                 names.add(info.component);
1514             }
1515         }
1516
1517         return names;
1518     }
1519
1520     private boolean removeDisabledHints(ManagedServiceInfo info) {
1521         return removeDisabledHints(info, 0);
1522     }
1523
1524     private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
1525         boolean removed = false;
1526
1527         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1528             final int hint = mListenersDisablingEffects.keyAt(i);
1529             final ArraySet<ManagedServiceInfo> listeners =
1530                     mListenersDisablingEffects.valueAt(i);
1531
1532             if (hints == 0 || (hint & hints) == hint) {
1533                 removed = removed || listeners.remove(info);
1534             }
1535         }
1536
1537         return removed;
1538     }
1539
1540     private void addDisabledHints(ManagedServiceInfo info, int hints) {
1541         if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1542             addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
1543         }
1544
1545         if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1546             addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1547         }
1548
1549         if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1550             addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
1551         }
1552     }
1553
1554     private void addDisabledHint(ManagedServiceInfo info, int hint) {
1555         if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
1556             mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
1557         }
1558
1559         ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
1560         hintListeners.add(info);
1561     }
1562
1563     private int calculateHints() {
1564         int hints = 0;
1565         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1566             int hint = mListenersDisablingEffects.keyAt(i);
1567             ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1568
1569             if (!serviceInfoList.isEmpty()) {
1570                 hints |= hint;
1571             }
1572         }
1573
1574         return hints;
1575     }
1576
1577     private long calculateSuppressedEffects() {
1578         int hints = calculateHints();
1579         long suppressedEffects = 0;
1580
1581         if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1582             suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
1583         }
1584
1585         if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1586             suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
1587         }
1588
1589         if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1590             suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
1591         }
1592
1593         return suppressedEffects;
1594     }
1595
1596     @GuardedBy("mNotificationLock")
1597     private void updateInterruptionFilterLocked() {
1598         int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1599         if (interruptionFilter == mInterruptionFilter) return;
1600         mInterruptionFilter = interruptionFilter;
1601         scheduleInterruptionFilterChanged(interruptionFilter);
1602     }
1603
1604     @VisibleForTesting
1605     INotificationManager getBinderService() {
1606         return INotificationManager.Stub.asInterface(mService);
1607     }
1608
1609     @VisibleForTesting
1610     NotificationManagerInternal getInternalService() {
1611         return mInternalService;
1612     }
1613
1614     private final IBinder mService = new INotificationManager.Stub() {
1615         // Toasts
1616         // ============================================================================
1617
1618         @Override
1619         public void enqueueToast(String pkg, ITransientNotification callback, int duration)
1620         {
1621             if (DBG) {
1622                 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1623                         + " duration=" + duration);
1624             }
1625
1626             if (pkg == null || callback == null) {
1627                 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1628                 return ;
1629             }
1630             final boolean isSystemToast = isCallerSystemOrPhone() || ("android".equals(pkg));
1631             final boolean isPackageSuspended =
1632                     isPackageSuspendedForUser(pkg, Binder.getCallingUid());
1633
1634             if (ENABLE_BLOCKED_TOASTS && !isSystemToast &&
1635                     (!areNotificationsEnabledForPackage(pkg, Binder.getCallingUid())
1636                             || isPackageSuspended)) {
1637                 Slog.e(TAG, "Suppressing toast from package " + pkg
1638                         + (isPackageSuspended
1639                                 ? " due to package suspended by administrator."
1640                                 : " by user request."));
1641                 return;
1642             }
1643
1644             synchronized (mToastQueue) {
1645                 int callingPid = Binder.getCallingPid();
1646                 long callingId = Binder.clearCallingIdentity();
1647                 try {
1648                     ToastRecord record;
1649                     int index;
1650                     // All packages aside from the android package can enqueue one toast at a time
1651                     if (!isSystemToast) {
1652                         index = indexOfToastPackageLocked(pkg);
1653                     } else {
1654                         index = indexOfToastLocked(pkg, callback);
1655                     }
1656
1657                     // If the package already has a toast, we update its toast
1658                     // in the queue, we don't move it to the end of the queue.
1659                     if (index >= 0) {
1660                         record = mToastQueue.get(index);
1661                         record.update(duration);
1662                         record.update(callback);
1663                     } else {
1664                         Binder token = new Binder();
1665                         mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, DEFAULT_DISPLAY);
1666                         record = new ToastRecord(callingPid, pkg, callback, duration, token);
1667                         mToastQueue.add(record);
1668                         index = mToastQueue.size() - 1;
1669                     }
1670                     keepProcessAliveIfNeededLocked(callingPid);
1671                     // If it's at index 0, it's the current toast.  It doesn't matter if it's
1672                     // new or just been updated.  Call back and tell it to show itself.
1673                     // If the callback fails, this will remove it from the list, so don't
1674                     // assume that it's valid after this.
1675                     if (index == 0) {
1676                         showNextToastLocked();
1677                     }
1678                 } finally {
1679                     Binder.restoreCallingIdentity(callingId);
1680                 }
1681             }
1682         }
1683
1684         @Override
1685         public void cancelToast(String pkg, ITransientNotification callback) {
1686             Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
1687
1688             if (pkg == null || callback == null) {
1689                 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
1690                 return ;
1691             }
1692
1693             synchronized (mToastQueue) {
1694                 long callingId = Binder.clearCallingIdentity();
1695                 try {
1696                     int index = indexOfToastLocked(pkg, callback);
1697                     if (index >= 0) {
1698                         cancelToastLocked(index);
1699                     } else {
1700                         Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
1701                                 + " callback=" + callback);
1702                     }
1703                 } finally {
1704                     Binder.restoreCallingIdentity(callingId);
1705                 }
1706             }
1707         }
1708
1709         @Override
1710         public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
1711                 Notification notification, int userId) throws RemoteException {
1712             enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
1713                     Binder.getCallingPid(), tag, id, notification, userId);
1714         }
1715
1716         @Override
1717         public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
1718             checkCallerIsSystemOrSameApp(pkg);
1719             userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1720                     Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
1721             // Don't allow client applications to cancel foreground service notis or autobundled
1722             // summaries.
1723             final int mustNotHaveFlags = isCallingUidSystem() ? 0 :
1724                     (Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTOGROUP_SUMMARY);
1725             cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
1726                     mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null);
1727         }
1728
1729         @Override
1730         public void cancelAllNotifications(String pkg, int userId) {
1731             checkCallerIsSystemOrSameApp(pkg);
1732
1733             userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1734                     Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
1735
1736             // Calling from user space, don't allow the canceling of actively
1737             // running foreground services.
1738             cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
1739                     pkg, null, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
1740                     REASON_APP_CANCEL_ALL, null);
1741         }
1742
1743         @Override
1744         public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
1745             checkCallerIsSystem();
1746
1747             mRankingHelper.setEnabled(pkg, uid, enabled);
1748             // Now, cancel any outstanding notifications that are part of a just-disabled app
1749             if (!enabled) {
1750                 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
1751                         UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
1752             }
1753             savePolicyFile();
1754         }
1755
1756         /**
1757          * Use this when you just want to know if notifications are OK for this package.
1758          */
1759         @Override
1760         public boolean areNotificationsEnabled(String pkg) {
1761             return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
1762         }
1763
1764         /**
1765          * Use this when you just want to know if notifications are OK for this package.
1766          */
1767         @Override
1768         public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
1769             checkCallerIsSystemOrSameApp(pkg);
1770             if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) {
1771                 getContext().enforceCallingPermission(
1772                         android.Manifest.permission.INTERACT_ACROSS_USERS,
1773                         "canNotifyAsPackage for uid " + uid);
1774             }
1775
1776             return mRankingHelper.getImportance(pkg, uid) != IMPORTANCE_NONE;
1777         }
1778
1779         @Override
1780         public int getPackageImportance(String pkg) {
1781             checkCallerIsSystemOrSameApp(pkg);
1782             return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
1783         }
1784
1785         @Override
1786         public boolean canShowBadge(String pkg, int uid) {
1787             checkCallerIsSystem();
1788             return mRankingHelper.canShowBadge(pkg, uid);
1789         }
1790
1791         @Override
1792         public void setShowBadge(String pkg, int uid, boolean showBadge) {
1793             checkCallerIsSystem();
1794             mRankingHelper.setShowBadge(pkg, uid, showBadge);
1795             savePolicyFile();
1796         }
1797
1798         @Override
1799         public void createNotificationChannelGroups(String pkg,
1800                 ParceledListSlice channelGroupList) throws RemoteException {
1801             checkCallerIsSystemOrSameApp(pkg);
1802             List<NotificationChannelGroup> groups = channelGroupList.getList();
1803             final int groupSize = groups.size();
1804             for (int i = 0; i < groupSize; i++) {
1805                 final NotificationChannelGroup group = groups.get(i);
1806                 Preconditions.checkNotNull(group, "group in list is null");
1807                 mRankingHelper.createNotificationChannelGroup(pkg, Binder.getCallingUid(), group,
1808                         true /* fromTargetApp */);
1809                 mListeners.notifyNotificationChannelGroupChanged(pkg,
1810                         UserHandle.of(UserHandle.getCallingUserId()), group,
1811                         NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1812             }
1813             savePolicyFile();
1814         }
1815
1816         private void createNotificationChannelsImpl(String pkg, int uid,
1817                 ParceledListSlice channelsList) {
1818             List<NotificationChannel> channels = channelsList.getList();
1819             final int channelsSize = channels.size();
1820             for (int i = 0; i < channelsSize; i++) {
1821                 final NotificationChannel channel = channels.get(i);
1822                 Preconditions.checkNotNull(channel, "channel in list is null");
1823                 mRankingHelper.createNotificationChannel(pkg, uid, channel,
1824                         true /* fromTargetApp */);
1825                 mListeners.notifyNotificationChannelChanged(pkg,
1826                         UserHandle.getUserHandleForUid(uid),
1827                         mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false),
1828                         NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1829             }
1830             savePolicyFile();
1831         }
1832
1833         @Override
1834         public void createNotificationChannels(String pkg,
1835                 ParceledListSlice channelsList) throws RemoteException {
1836             checkCallerIsSystemOrSameApp(pkg);
1837             createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList);
1838         }
1839
1840         @Override
1841         public void createNotificationChannelsForPackage(String pkg, int uid,
1842                 ParceledListSlice channelsList) throws RemoteException {
1843             checkCallerIsSystem();
1844             createNotificationChannelsImpl(pkg, uid, channelsList);
1845         }
1846
1847         @Override
1848         public NotificationChannel getNotificationChannel(String pkg, String channelId) {
1849             checkCallerIsSystemOrSameApp(pkg);
1850             return mRankingHelper.getNotificationChannel(
1851                     pkg, Binder.getCallingUid(), channelId, false /* includeDeleted */);
1852         }
1853
1854         @Override
1855         public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
1856                 String channelId, boolean includeDeleted) {
1857             checkCallerIsSystem();
1858             return mRankingHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted);
1859         }
1860
1861         @Override
1862         public void deleteNotificationChannel(String pkg, String channelId) {
1863             checkCallerIsSystemOrSameApp(pkg);
1864             final int callingUid = Binder.getCallingUid();
1865             if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
1866                 throw new IllegalArgumentException("Cannot delete default channel");
1867             }
1868             cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
1869                     UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
1870             mRankingHelper.deleteNotificationChannel(pkg, callingUid, channelId);
1871             mListeners.notifyNotificationChannelChanged(pkg,
1872                     UserHandle.getUserHandleForUid(callingUid),
1873                     mRankingHelper.getNotificationChannel(pkg, callingUid, channelId, true),
1874                     NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1875             savePolicyFile();
1876         }
1877
1878         @Override
1879         public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
1880                 String pkg) {
1881             checkCallerIsSystemOrSameApp(pkg);
1882             return new ParceledListSlice<>(new ArrayList(
1883                     mRankingHelper.getNotificationChannelGroups(pkg, Binder.getCallingUid())));
1884         }
1885
1886         @Override
1887         public void deleteNotificationChannelGroup(String pkg, String groupId) {
1888             checkCallerIsSystemOrSameApp(pkg);
1889
1890             final int callingUid = Binder.getCallingUid();
1891             NotificationChannelGroup groupToDelete =
1892                     mRankingHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
1893             if (groupToDelete != null) {
1894                 List<NotificationChannel> deletedChannels =
1895                         mRankingHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
1896                 for (int i = 0; i < deletedChannels.size(); i++) {
1897                     final NotificationChannel deletedChannel = deletedChannels.get(i);
1898                     cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
1899                             true,
1900                             UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
1901                             null);
1902                     mListeners.notifyNotificationChannelChanged(pkg,
1903                             UserHandle.getUserHandleForUid(callingUid),
1904                             deletedChannel,
1905                             NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1906                 }
1907                 mListeners.notifyNotificationChannelGroupChanged(
1908                         pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete,
1909                         NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1910                 savePolicyFile();
1911             }
1912         }
1913
1914         @Override
1915         public void updateNotificationChannelForPackage(String pkg, int uid,
1916                 NotificationChannel channel) {
1917             enforceSystemOrSystemUI("Caller not system or systemui");
1918             Preconditions.checkNotNull(channel);
1919             updateNotificationChannelInt(pkg, uid, channel, false);
1920         }
1921
1922         @Override
1923         public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
1924                 int uid, boolean includeDeleted) {
1925             enforceSystemOrSystemUI("getNotificationChannelsForPackage");
1926             return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted);
1927         }
1928
1929         @Override
1930         public int getNumNotificationChannelsForPackage(String pkg, int uid,
1931                 boolean includeDeleted) {
1932             enforceSystemOrSystemUI("getNumNotificationChannelsForPackage");
1933             return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted)
1934                     .getList().size();
1935         }
1936
1937         @Override
1938         public boolean onlyHasDefaultChannel(String pkg, int uid) {
1939             enforceSystemOrSystemUI("onlyHasDefaultChannel");
1940             return mRankingHelper.onlyHasDefaultChannel(pkg, uid);
1941         }
1942
1943         @Override
1944         public int getDeletedChannelCount(String pkg, int uid) {
1945             enforceSystemOrSystemUI("getDeletedChannelCount");
1946             return mRankingHelper.getDeletedChannelCount(pkg, uid);
1947         }
1948
1949         @Override
1950         public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
1951                 String pkg, int uid, boolean includeDeleted) {
1952             checkCallerIsSystem();
1953             return mRankingHelper.getNotificationChannelGroups(pkg, uid, includeDeleted);
1954         }
1955
1956         @Override
1957         public NotificationChannelGroup getNotificationChannelGroupForPackage(
1958                 String groupId, String pkg, int uid) {
1959             enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
1960             return mRankingHelper.getNotificationChannelGroup(groupId, pkg, uid);
1961         }
1962
1963         @Override
1964         public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
1965             checkCallerIsSystemOrSameApp(pkg);
1966             return mRankingHelper.getNotificationChannels(
1967                     pkg, Binder.getCallingUid(), false /* includeDeleted */);
1968         }
1969
1970         @Override
1971         public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
1972             checkCallerIsSystem();
1973
1974             // Cancel posted notifications
1975             cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true,
1976                     UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
1977
1978             final String[] packages = new String[] {packageName};
1979             final int[] uids = new int[] {uid};
1980
1981             // Listener & assistant
1982             mListeners.onPackagesChanged(true, packages, uids);
1983             mAssistants.onPackagesChanged(true, packages, uids);
1984
1985             // Zen
1986             mConditionProviders.onPackagesChanged(true, packages, uids);
1987
1988             // Reset notification preferences
1989             if (!fromApp) {
1990                 mRankingHelper.onPackagesChanged(
1991                         true, UserHandle.getCallingUserId(), packages, uids);
1992             }
1993
1994             savePolicyFile();
1995         }
1996
1997
1998         /**
1999          * System-only API for getting a list of current (i.e. not cleared) notifications.
2000          *
2001          * Requires ACCESS_NOTIFICATIONS which is signature|system.
2002          * @returns A list of all the notifications, in natural order.
2003          */
2004         @Override
2005         public StatusBarNotification[] getActiveNotifications(String callingPkg) {
2006             // enforce() will ensure the calling uid has the correct permission
2007             getContext().enforceCallingOrSelfPermission(
2008                     android.Manifest.permission.ACCESS_NOTIFICATIONS,
2009                     "NotificationManagerService.getActiveNotifications");
2010
2011             StatusBarNotification[] tmp = null;
2012             int uid = Binder.getCallingUid();
2013
2014             // noteOp will check to make sure the callingPkg matches the uid
2015             if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2016                     == AppOpsManager.MODE_ALLOWED) {
2017                 synchronized (mNotificationLock) {
2018                     tmp = new StatusBarNotification[mNotificationList.size()];
2019                     final int N = mNotificationList.size();
2020                     for (int i=0; i<N; i++) {
2021                         tmp[i] = mNotificationList.get(i).sbn;
2022                     }
2023                 }
2024             }
2025             return tmp;
2026         }
2027
2028         /**
2029          * Public API for getting a list of current notifications for the calling package/uid.
2030          *
2031          * Note that since notification posting is done asynchronously, this will not return
2032          * notifications that are in the process of being posted.
2033          *
2034          * @returns A list of all the package's notifications, in natural order.
2035          */
2036         @Override
2037         public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
2038                 int incomingUserId) {
2039             checkCallerIsSystemOrSameApp(pkg);
2040             int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2041                     Binder.getCallingUid(), incomingUserId, true, false,
2042                     "getAppActiveNotifications", pkg);
2043             synchronized (mNotificationLock) {
2044                 final ArrayMap<String, StatusBarNotification> map
2045                         = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
2046                 final int N = mNotificationList.size();
2047                 for (int i = 0; i < N; i++) {
2048                     StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2049                             mNotificationList.get(i).sbn);
2050                     if (sbn != null) {
2051                         map.put(sbn.getKey(), sbn);
2052                     }
2053                 }
2054                 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
2055                     StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn);
2056                     if (sbn != null) {
2057                         map.put(sbn.getKey(), sbn);
2058                     }
2059                 }
2060                 final int M = mEnqueuedNotifications.size();
2061                 for (int i = 0; i < M; i++) {
2062                     StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2063                             mEnqueuedNotifications.get(i).sbn);
2064                     if (sbn != null) {
2065                         map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
2066                     }
2067                 }
2068                 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
2069                 list.addAll(map.values());
2070                 return new ParceledListSlice<StatusBarNotification>(list);
2071             }
2072         }
2073
2074         private StatusBarNotification sanitizeSbn(String pkg, int userId,
2075                 StatusBarNotification sbn) {
2076             if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId) {
2077                 // We could pass back a cloneLight() but clients might get confused and
2078                 // try to send this thing back to notify() again, which would not work
2079                 // very well.
2080                 return new StatusBarNotification(
2081                         sbn.getPackageName(),
2082                         sbn.getOpPkg(),
2083                         sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
2084                         sbn.getNotification().clone(),
2085                         sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
2086             }
2087             return null;
2088         }
2089
2090         /**
2091          * System-only API for getting a list of recent (cleared, no longer shown) notifications.
2092          *
2093          * Requires ACCESS_NOTIFICATIONS which is signature|system.
2094          */
2095         @Override
2096         public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
2097             // enforce() will ensure the calling uid has the correct permission
2098             getContext().enforceCallingOrSelfPermission(
2099                     android.Manifest.permission.ACCESS_NOTIFICATIONS,
2100                     "NotificationManagerService.getHistoricalNotifications");
2101
2102             StatusBarNotification[] tmp = null;
2103             int uid = Binder.getCallingUid();
2104
2105             // noteOp will check to make sure the callingPkg matches the uid
2106             if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2107                     == AppOpsManager.MODE_ALLOWED) {
2108                 synchronized (mArchive) {
2109                     tmp = mArchive.getArray(count);
2110                 }
2111             }
2112             return tmp;
2113         }
2114
2115         /**
2116          * Register a listener binder directly with the notification manager.
2117          *
2118          * Only works with system callers. Apps should extend
2119          * {@link android.service.notification.NotificationListenerService}.
2120          */
2121         @Override
2122         public void registerListener(final INotificationListener listener,
2123                 final ComponentName component, final int userid) {
2124             enforceSystemOrSystemUI("INotificationManager.registerListener");
2125             mListeners.registerService(listener, component, userid);
2126         }
2127
2128         /**
2129          * Remove a listener binder directly
2130          */
2131         @Override
2132         public void unregisterListener(INotificationListener token, int userid) {
2133             mListeners.unregisterService(token, userid);
2134         }
2135
2136         /**
2137          * Allow an INotificationListener to simulate a "clear all" operation.
2138          *
2139          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
2140          *
2141          * @param token The binder for the listener, to check that the caller is allowed
2142          */
2143         @Override
2144         public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
2145             final int callingUid = Binder.getCallingUid();
2146             final int callingPid = Binder.getCallingPid();
2147             long identity = Binder.clearCallingIdentity();
2148             try {
2149                 synchronized (mNotificationLock) {
2150                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2151                     if (keys != null) {
2152                         final int N = keys.length;
2153                         for (int i = 0; i < N; i++) {
2154                             NotificationRecord r = mNotificationsByKey.get(keys[i]);
2155                             if (r == null) continue;
2156                             final int userId = r.sbn.getUserId();
2157                             if (userId != info.userid && userId != UserHandle.USER_ALL &&
2158                                     !mUserProfiles.isCurrentProfile(userId)) {
2159                                 throw new SecurityException("Disallowed call from listener: "
2160                                         + info.service);
2161                             }
2162                             cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2163                                     r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
2164                                     userId);
2165                         }
2166                     } else {
2167                         cancelAllLocked(callingUid, callingPid, info.userid,
2168                                 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
2169                     }
2170                 }
2171             } finally {
2172                 Binder.restoreCallingIdentity(identity);
2173             }
2174         }
2175
2176         /**
2177          * Handle request from an approved listener to re-enable itself.
2178          *
2179          * @param component The componenet to be re-enabled, caller must match package.
2180          */
2181         @Override
2182         public void requestBindListener(ComponentName component) {
2183             checkCallerIsSystemOrSameApp(component.getPackageName());
2184             long identity = Binder.clearCallingIdentity();
2185             try {
2186                 ManagedServices manager =
2187                         mAssistants.isComponentEnabledForCurrentProfiles(component)
2188                         ? mAssistants
2189                         : mListeners;
2190                 manager.setComponentState(component, true);
2191             } finally {
2192                 Binder.restoreCallingIdentity(identity);
2193             }
2194         }
2195
2196         @Override
2197         public void requestUnbindListener(INotificationListener token) {
2198             long identity = Binder.clearCallingIdentity();
2199             try {
2200                 // allow bound services to disable themselves
2201                 synchronized (mNotificationLock) {
2202                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2203                     info.getOwner().setComponentState(info.component, false);
2204                 }
2205             } finally {
2206                 Binder.restoreCallingIdentity(identity);
2207             }
2208         }
2209
2210         @Override
2211         public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
2212             long identity = Binder.clearCallingIdentity();
2213             try {
2214                 synchronized (mNotificationLock) {
2215                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2216                     if (keys != null) {
2217                         final int N = keys.length;
2218                         for (int i = 0; i < N; i++) {
2219                             NotificationRecord r = mNotificationsByKey.get(keys[i]);
2220                             if (r == null) continue;
2221                             final int userId = r.sbn.getUserId();
2222                             if (userId != info.userid && userId != UserHandle.USER_ALL &&
2223                                     !mUserProfiles.isCurrentProfile(userId)) {
2224                                 throw new SecurityException("Disallowed call from listener: "
2225                                         + info.service);
2226                             }
2227                             if (!r.isSeen()) {
2228                                 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
2229                                 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
2230                                         userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM
2231                                                 : userId,
2232                                         UsageEvents.Event.USER_INTERACTION);
2233                                 r.setSeen();
2234                             }
2235                         }
2236                     }
2237                 }
2238             } finally {
2239                 Binder.restoreCallingIdentity(identity);
2240             }
2241         }
2242
2243         /**
2244          * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2245          *
2246          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2247          *
2248          * @param info The binder for the listener, to check that the caller is allowed
2249          */
2250         @GuardedBy("mNotificationLock")
2251         private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
2252                 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
2253             cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
2254                     Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
2255                     true,
2256                     userId, REASON_LISTENER_CANCEL, info);
2257         }
2258
2259         /**
2260          * Allow an INotificationListener to snooze a single notification until a context.
2261          *
2262          * @param token The binder for the listener, to check that the caller is allowed
2263          */
2264         @Override
2265         public void snoozeNotificationUntilContextFromListener(INotificationListener token,
2266                 String key, String snoozeCriterionId) {
2267             long identity = Binder.clearCallingIdentity();
2268             try {
2269                 synchronized (mNotificationLock) {
2270                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2271                     snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info);
2272                 }
2273             } finally {
2274                 Binder.restoreCallingIdentity(identity);
2275             }
2276         }
2277
2278         /**
2279          * Allow an INotificationListener to snooze a single notification until a time.
2280          *
2281          * @param token The binder for the listener, to check that the caller is allowed
2282          */
2283         @Override
2284         public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
2285                 long duration) {
2286             long identity = Binder.clearCallingIdentity();
2287             try {
2288                 synchronized (mNotificationLock) {
2289                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2290                     snoozeNotificationInt(key, duration, null, info);
2291                 }
2292             } finally {
2293                 Binder.restoreCallingIdentity(identity);
2294             }
2295         }
2296
2297         /**
2298          * Allows the notification assistant to un-snooze a single notification.
2299          *
2300          * @param token The binder for the assistant, to check that the caller is allowed
2301          */
2302         @Override
2303         public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
2304             long identity = Binder.clearCallingIdentity();
2305             try {
2306                 synchronized (mNotificationLock) {
2307                     final ManagedServiceInfo info =
2308                             mAssistants.checkServiceTokenLocked(token);
2309                     unsnoozeNotificationInt(key, info);
2310                 }
2311             } finally {
2312                 Binder.restoreCallingIdentity(identity);
2313             }
2314         }
2315
2316         /**
2317          * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2318          *
2319          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2320          *
2321          * @param token The binder for the listener, to check that the caller is allowed
2322          */
2323         @Override
2324         public void cancelNotificationFromListener(INotificationListener token, String pkg,
2325                 String tag, int id) {
2326             final int callingUid = Binder.getCallingUid();
2327             final int callingPid = Binder.getCallingPid();
2328             long identity = Binder.clearCallingIdentity();
2329             try {
2330                 synchronized (mNotificationLock) {
2331                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2332                     if (info.supportsProfiles()) {
2333                         Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
2334                                 + "from " + info.component
2335                                 + " use cancelNotification(key) instead.");
2336                     } else {
2337                         cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2338                                 pkg, tag, id, info.userid);
2339                     }
2340                 }
2341             } finally {
2342                 Binder.restoreCallingIdentity(identity);
2343             }
2344         }
2345
2346         /**
2347          * Allow an INotificationListener to request the list of outstanding notifications seen by
2348          * the current user. Useful when starting up, after which point the listener callbacks
2349          * should be used.
2350          *
2351          * @param token The binder for the listener, to check that the caller is allowed
2352          * @param keys An array of notification keys to fetch, or null to fetch everything
2353          * @returns The return value will contain the notifications specified in keys, in that
2354          *      order, or if keys is null, all the notifications, in natural order.
2355          */
2356         @Override
2357         public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
2358                 INotificationListener token, String[] keys, int trim) {
2359             synchronized (mNotificationLock) {
2360                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2361                 final boolean getKeys = keys != null;
2362                 final int N = getKeys ? keys.length : mNotificationList.size();
2363                 final ArrayList<StatusBarNotification> list
2364                         = new ArrayList<StatusBarNotification>(N);
2365                 for (int i=0; i<N; i++) {
2366                     final NotificationRecord r = getKeys
2367                             ? mNotificationsByKey.get(keys[i])
2368                             : mNotificationList.get(i);
2369                     if (r == null) continue;
2370                     StatusBarNotification sbn = r.sbn;
2371                     if (!isVisibleToListener(sbn, info)) continue;
2372                     StatusBarNotification sbnToSend =
2373                             (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2374                     list.add(sbnToSend);
2375                 }
2376                 return new ParceledListSlice<StatusBarNotification>(list);
2377             }
2378         }
2379
2380         /**
2381          * Allow an INotificationListener to request the list of outstanding snoozed notifications
2382          * seen by the current user. Useful when starting up, after which point the listener
2383          * callbacks should be used.
2384          *
2385          * @param token The binder for the listener, to check that the caller is allowed
2386          * @returns The return value will contain the notifications specified in keys, in that
2387          *      order, or if keys is null, all the notifications, in natural order.
2388          */
2389         @Override
2390         public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
2391                 INotificationListener token, int trim) {
2392             synchronized (mNotificationLock) {
2393                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2394                 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
2395                 final int N = snoozedRecords.size();
2396                 final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
2397                 for (int i=0; i < N; i++) {
2398                     final NotificationRecord r = snoozedRecords.get(i);
2399                     if (r == null) continue;
2400                     StatusBarNotification sbn = r.sbn;
2401                     if (!isVisibleToListener(sbn, info)) continue;
2402                     StatusBarNotification sbnToSend =
2403                             (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2404                     list.add(sbnToSend);
2405                 }
2406                 return new ParceledListSlice<>(list);
2407             }
2408         }
2409
2410         @Override
2411         public void requestHintsFromListener(INotificationListener token, int hints) {
2412             final long identity = Binder.clearCallingIdentity();
2413             try {
2414                 synchronized (mNotificationLock) {
2415                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2416                     final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
2417                             | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
2418                             | HINT_HOST_DISABLE_CALL_EFFECTS;
2419                     final boolean disableEffects = (hints & disableEffectsMask) != 0;
2420                     if (disableEffects) {
2421                         addDisabledHints(info, hints);
2422                     } else {
2423                         removeDisabledHints(info, hints);
2424                     }
2425                     updateListenerHintsLocked();
2426                     updateEffectsSuppressorLocked();
2427                 }
2428             } finally {
2429                 Binder.restoreCallingIdentity(identity);
2430             }
2431         }
2432
2433         @Override
2434         public int getHintsFromListener(INotificationListener token) {
2435             synchronized (mNotificationLock) {
2436                 return mListenerHints;
2437             }
2438         }
2439
2440         @Override
2441         public void requestInterruptionFilterFromListener(INotificationListener token,
2442                 int interruptionFilter) throws RemoteException {
2443             final long identity = Binder.clearCallingIdentity();
2444             try {
2445                 synchronized (mNotificationLock) {
2446                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2447                     mZenModeHelper.requestFromListener(info.component, interruptionFilter);
2448                     updateInterruptionFilterLocked();
2449                 }
2450             } finally {
2451                 Binder.restoreCallingIdentity(identity);
2452             }
2453         }
2454
2455         @Override
2456         public int getInterruptionFilterFromListener(INotificationListener token)
2457                 throws RemoteException {
2458             synchronized (mNotificationLight) {
2459                 return mInterruptionFilter;
2460             }
2461         }
2462
2463         @Override
2464         public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
2465                 throws RemoteException {
2466             synchronized (mNotificationLock) {
2467                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2468                 if (info == null) return;
2469                 mListeners.setOnNotificationPostedTrimLocked(info, trim);
2470             }
2471         }
2472
2473         @Override
2474         public int getZenMode() {
2475             return mZenModeHelper.getZenMode();
2476         }
2477
2478         @Override
2479         public ZenModeConfig getZenModeConfig() {
2480             enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
2481             return mZenModeHelper.getConfig();
2482         }
2483
2484         @Override
2485         public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
2486             enforceSystemOrSystemUI("INotificationManager.setZenMode");
2487             final long identity = Binder.clearCallingIdentity();
2488             try {
2489                 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
2490             } finally {
2491                 Binder.restoreCallingIdentity(identity);
2492             }
2493         }
2494
2495         @Override
2496         public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
2497             enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
2498             return mZenModeHelper.getZenRules();
2499         }
2500
2501         @Override
2502         public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
2503             Preconditions.checkNotNull(id, "Id is null");
2504             enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
2505             return mZenModeHelper.getAutomaticZenRule(id);
2506         }
2507
2508         @Override
2509         public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
2510                 throws RemoteException {
2511             Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2512             Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2513             Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2514             Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2515             enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
2516
2517             return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
2518                     "addAutomaticZenRule");
2519         }
2520
2521         @Override
2522         public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
2523                 throws RemoteException {
2524             Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2525             Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2526             Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2527             Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2528             enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
2529
2530             return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
2531                     "updateAutomaticZenRule");
2532         }
2533
2534         @Override
2535         public boolean removeAutomaticZenRule(String id) throws RemoteException {
2536             Preconditions.checkNotNull(id, "Id is null");
2537             // Verify that they can modify zen rules.
2538             enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
2539
2540             return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
2541         }
2542
2543         @Override
2544         public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
2545             Preconditions.checkNotNull(packageName, "Package name is null");
2546             enforceSystemOrSystemUI("removeAutomaticZenRules");
2547
2548             return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
2549         }
2550
2551         @Override
2552         public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
2553             Preconditions.checkNotNull(owner, "Owner is null");
2554             enforceSystemOrSystemUI("getRuleInstanceCount");
2555
2556             return mZenModeHelper.getCurrentInstanceCount(owner);
2557         }
2558
2559         @Override
2560         public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
2561             enforcePolicyAccess(pkg, "setInterruptionFilter");
2562             final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
2563             if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
2564             final long identity = Binder.clearCallingIdentity();
2565             try {
2566                 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
2567             } finally {
2568                 Binder.restoreCallingIdentity(identity);
2569             }
2570         }
2571
2572         @Override
2573         public void notifyConditions(final String pkg, IConditionProvider provider,
2574                 final Condition[] conditions) {
2575             final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2576             checkCallerIsSystemOrSameApp(pkg);
2577             mHandler.post(new Runnable() {
2578                 @Override
2579                 public void run() {
2580                     mConditionProviders.notifyConditions(pkg, info, conditions);
2581                 }
2582             });
2583         }
2584
2585         @Override
2586         public void requestUnbindProvider(IConditionProvider provider) {
2587             long identity = Binder.clearCallingIdentity();
2588             try {
2589                 // allow bound services to disable themselves
2590                 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2591                 info.getOwner().setComponentState(info.component, false);
2592             } finally {
2593                 Binder.restoreCallingIdentity(identity);
2594             }
2595         }
2596
2597         @Override
2598         public void requestBindProvider(ComponentName component) {
2599             checkCallerIsSystemOrSameApp(component.getPackageName());
2600             long identity = Binder.clearCallingIdentity();
2601             try {
2602                 mConditionProviders.setComponentState(component, true);
2603             } finally {
2604                 Binder.restoreCallingIdentity(identity);
2605             }
2606         }
2607
2608         private void enforceSystemOrSystemUI(String message) {
2609             if (isCallerSystemOrPhone()) return;
2610             getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
2611                     message);
2612         }
2613
2614         private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
2615             try {
2616                 checkCallerIsSystemOrSameApp(pkg);
2617             } catch (SecurityException e) {
2618                 getContext().enforceCallingPermission(
2619                         android.Manifest.permission.STATUS_BAR_SERVICE,
2620                         message);
2621             }
2622         }
2623
2624         private void enforcePolicyAccess(int uid, String method) {
2625             if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2626                     android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2627                 return;
2628             }
2629             boolean accessAllowed = false;
2630             String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
2631             final int packageCount = packages.length;
2632             for (int i = 0; i < packageCount; i++) {
2633                 if (mConditionProviders.isPackageOrComponentAllowed(
2634                         packages[i], UserHandle.getUserId(uid))) {
2635                     accessAllowed = true;
2636                 }
2637             }
2638             if (!accessAllowed) {
2639                 Slog.w(TAG, "Notification policy access denied calling " + method);
2640                 throw new SecurityException("Notification policy access denied");
2641             }
2642         }
2643
2644         private void enforcePolicyAccess(String pkg, String method) {
2645             if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2646                     android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2647                 return;
2648             }
2649             checkCallerIsSameApp(pkg);
2650             if (!checkPolicyAccess(pkg)) {
2651                 Slog.w(TAG, "Notification policy access denied calling " + method);
2652                 throw new SecurityException("Notification policy access denied");
2653             }
2654         }
2655
2656         private boolean checkPackagePolicyAccess(String pkg) {
2657             return mConditionProviders.isPackageOrComponentAllowed(
2658                     pkg, getCallingUserHandle().getIdentifier());
2659         }
2660
2661         private boolean checkPolicyAccess(String pkg) {
2662             try {
2663                 int uid = getContext().getPackageManager().getPackageUidAsUser(
2664                         pkg, UserHandle.getCallingUserId());
2665                 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
2666                         android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
2667                         -1, true)) {
2668                     return true;
2669                 }
2670             } catch (NameNotFoundException e) {
2671                 return false;
2672             }
2673             return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
2674         }
2675
2676         @Override
2677         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2678             if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
2679             final DumpFilter filter = DumpFilter.parseFromArguments(args);
2680             if (filter != null && filter.stats) {
2681                 dumpJson(pw, filter);
2682             } else if (filter != null && filter.proto) {
2683                 dumpProto(fd, filter);
2684             } else {
2685                 dumpImpl(pw, filter);
2686             }
2687         }
2688
2689         @Override
2690         public ComponentName getEffectsSuppressor() {
2691             return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
2692         }
2693
2694         @Override
2695         public boolean matchesCallFilter(Bundle extras) {
2696             enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
2697             return mZenModeHelper.matchesCallFilter(
2698                     Binder.getCallingUserHandle(),
2699                     extras,
2700                     mRankingHelper.findExtractor(ValidateNotificationPeople.class),
2701                     MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
2702                     MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
2703         }
2704
2705         @Override
2706         public boolean isSystemConditionProviderEnabled(String path) {
2707             enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
2708             return mConditionProviders.isSystemProviderEnabled(path);
2709         }
2710
2711         // Backup/restore interface
2712         @Override
2713         public byte[] getBackupPayload(int user) {
2714             if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
2715             //TODO: http://b/22388012
2716             if (user != UserHandle.USER_SYSTEM) {
2717                 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
2718                 return null;
2719             }
2720             synchronized(mPolicyFile) {
2721                 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
2722                 try {
2723                     writePolicyXml(baos, true /*forBackup*/);
2724                     return baos.toByteArray();
2725                 } catch (IOException e) {
2726                     Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
2727                 }
2728             }
2729             return null;
2730         }
2731
2732         @Override
2733         public void applyRestore(byte[] payload, int user) {
2734             if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
2735                     + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
2736             if (payload == null) {
2737                 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
2738                 return;
2739             }
2740             //TODO: http://b/22388012
2741             if (user != UserHandle.USER_SYSTEM) {
2742                 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
2743                 return;
2744             }
2745             synchronized(mPolicyFile) {
2746                 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
2747                 try {
2748                     readPolicyXml(bais, true /*forRestore*/);
2749                     savePolicyFile();
2750                 } catch (NumberFormatException | XmlPullParserException | IOException e) {
2751                     Slog.w(TAG, "applyRestore: error reading payload", e);
2752                 }
2753             }
2754         }
2755
2756         @Override
2757         public boolean isNotificationPolicyAccessGranted(String pkg) {
2758             return checkPolicyAccess(pkg);
2759         }
2760
2761         @Override
2762         public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
2763             enforceSystemOrSystemUIOrSamePackage(pkg,
2764                     "request policy access status for another package");
2765             return checkPolicyAccess(pkg);
2766         }
2767
2768         @Override
2769         public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
2770                 throws RemoteException {
2771             setNotificationPolicyAccessGrantedForUser(
2772                     pkg, getCallingUserHandle().getIdentifier(), granted);
2773         }
2774
2775         @Override
2776         public void setNotificationPolicyAccessGrantedForUser(
2777                 String pkg, int userId, boolean granted) {
2778             checkCallerIsSystemOrShell();
2779             final long identity = Binder.clearCallingIdentity();
2780             try {
2781                 if (!mActivityManager.isLowRamDevice()) {
2782                     mConditionProviders.setPackageOrComponentEnabled(
2783                             pkg, userId, true, granted);
2784
2785                     getContext().sendBroadcastAsUser(new Intent(
2786                             NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
2787                                     .setPackage(pkg)
2788                                     .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
2789                             UserHandle.of(userId), null);
2790                     savePolicyFile();
2791                 }
2792             } finally {
2793                 Binder.restoreCallingIdentity(identity);
2794             }
2795         }
2796
2797         @Override
2798         public Policy getNotificationPolicy(String pkg) {
2799             enforcePolicyAccess(pkg, "getNotificationPolicy");
2800             final long identity = Binder.clearCallingIdentity();
2801             try {
2802                 return mZenModeHelper.getNotificationPolicy();
2803             } finally {
2804                 Binder.restoreCallingIdentity(identity);
2805             }
2806         }
2807
2808         @Override
2809         public void setNotificationPolicy(String pkg, Policy policy) {
2810             enforcePolicyAccess(pkg, "setNotificationPolicy");
2811             final long identity = Binder.clearCallingIdentity();
2812             try {
2813                 mZenModeHelper.setNotificationPolicy(policy);
2814             } finally {
2815                 Binder.restoreCallingIdentity(identity);
2816             }
2817         }
2818
2819         @Override
2820         public List<String> getEnabledNotificationListenerPackages() {
2821             checkCallerIsSystem();
2822             return mListeners.getAllowedPackages(getCallingUserHandle().getIdentifier());
2823         }
2824
2825         @Override
2826         public List<ComponentName> getEnabledNotificationListeners(int userId) {
2827             checkCallerIsSystem();
2828             return mListeners.getAllowedComponents(userId);
2829         }
2830
2831         @Override
2832         public boolean isNotificationListenerAccessGranted(ComponentName listener) {
2833             Preconditions.checkNotNull(listener);
2834             checkCallerIsSystemOrSameApp(listener.getPackageName());
2835             return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
2836                     getCallingUserHandle().getIdentifier());
2837         }
2838
2839         @Override
2840         public boolean isNotificationListenerAccessGrantedForUser(ComponentName listener,
2841                 int userId) {
2842             Preconditions.checkNotNull(listener);
2843             checkCallerIsSystem();
2844             return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
2845                     userId);
2846         }
2847
2848         @Override
2849         public boolean isNotificationAssistantAccessGranted(ComponentName assistant) {
2850             Preconditions.checkNotNull(assistant);
2851             checkCallerIsSystemOrSameApp(assistant.getPackageName());
2852             return mAssistants.isPackageOrComponentAllowed(assistant.flattenToString(),
2853                     getCallingUserHandle().getIdentifier());
2854         }
2855
2856         @Override
2857         public void setNotificationListenerAccessGranted(ComponentName listener,
2858                 boolean granted) throws RemoteException {
2859             setNotificationListenerAccessGrantedForUser(
2860                     listener, getCallingUserHandle().getIdentifier(), granted);
2861         }
2862
2863         @Override
2864         public void setNotificationAssistantAccessGranted(ComponentName assistant,
2865                 boolean granted) throws RemoteException {
2866             setNotificationAssistantAccessGrantedForUser(
2867                     assistant, getCallingUserHandle().getIdentifier(), granted);
2868         }
2869
2870         @Override
2871         public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
2872                 boolean granted) throws RemoteException {
2873             Preconditions.checkNotNull(listener);
2874             checkCallerIsSystemOrShell();
2875             final long identity = Binder.clearCallingIdentity();
2876             try {
2877                 if (!mActivityManager.isLowRamDevice()) {
2878                     mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
2879                             userId, false, granted);
2880                     mListeners.setPackageOrComponentEnabled(listener.flattenToString(),
2881                             userId, true, granted);
2882
2883                     getContext().sendBroadcastAsUser(new Intent(
2884                             NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
2885                                     .setPackage(listener.getPackageName())
2886                                     .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
2887                             UserHandle.of(userId), null);
2888
2889                     savePolicyFile();
2890                 }
2891             } finally {
2892                 Binder.restoreCallingIdentity(identity);
2893             }
2894         }
2895
2896         @Override
2897         public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
2898                 int userId, boolean granted) throws RemoteException {
2899             Preconditions.checkNotNull(assistant);
2900             checkCallerIsSystemOrShell();
2901             final long identity = Binder.clearCallingIdentity();
2902             try {
2903                 if (!mActivityManager.isLowRamDevice()) {
2904                     mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
2905                             userId, false, granted);
2906                     mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
2907                             userId, true, granted);
2908
2909                     getContext().sendBroadcastAsUser(new Intent(
2910                             NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
2911                                     .setPackage(assistant.getPackageName())
2912                                     .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
2913                             UserHandle.of(userId), null);
2914
2915                     savePolicyFile();
2916                 }
2917             } finally {
2918                 Binder.restoreCallingIdentity(identity);
2919             }
2920         }
2921
2922         @Override
2923         public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
2924                 Adjustment adjustment) throws RemoteException {
2925             final long identity = Binder.clearCallingIdentity();
2926             try {
2927                 synchronized (mNotificationLock) {
2928                     mAssistants.checkServiceTokenLocked(token);
2929                     int N = mEnqueuedNotifications.size();
2930                     for (int i = 0; i < N; i++) {
2931                         final NotificationRecord n = mEnqueuedNotifications.get(i);
2932                         if (Objects.equals(adjustment.getKey(), n.getKey())
2933                                 && Objects.equals(adjustment.getUser(), n.getUserId())) {
2934                             applyAdjustment(n, adjustment);
2935                             break;
2936                         }
2937                     }
2938                 }
2939             } finally {
2940                 Binder.restoreCallingIdentity(identity);
2941             }
2942         }
2943
2944         @Override
2945         public void applyAdjustmentFromAssistant(INotificationListener token,
2946                 Adjustment adjustment) throws RemoteException {
2947             final long identity = Binder.clearCallingIdentity();
2948             try {
2949                 synchronized (mNotificationLock) {
2950                     mAssistants.checkServiceTokenLocked(token);
2951                     NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2952                     applyAdjustment(n, adjustment);
2953                 }
2954                 mRankingHandler.requestSort();
2955             } finally {
2956                 Binder.restoreCallingIdentity(identity);
2957             }
2958         }
2959
2960         @Override
2961         public void applyAdjustmentsFromAssistant(INotificationListener token,
2962                 List<Adjustment> adjustments) throws RemoteException {
2963
2964             final long identity = Binder.clearCallingIdentity();
2965             try {
2966                 synchronized (mNotificationLock) {
2967                     mAssistants.checkServiceTokenLocked(token);
2968                     for (Adjustment adjustment : adjustments) {
2969                         NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2970                         applyAdjustment(n, adjustment);
2971                     }
2972                 }
2973                 mRankingHandler.requestSort();
2974             } finally {
2975                 Binder.restoreCallingIdentity(identity);
2976             }
2977         }
2978
2979         @Override
2980         public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
2981                 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
2982             Preconditions.checkNotNull(channel);
2983             Preconditions.checkNotNull(pkg);
2984             Preconditions.checkNotNull(user);
2985
2986             verifyPrivilegedListener(token, user);
2987             updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
2988         }
2989
2990         @Override
2991         public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
2992                 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
2993             Preconditions.checkNotNull(pkg);
2994             Preconditions.checkNotNull(user);
2995             verifyPrivilegedListener(token, user);
2996
2997             return mRankingHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user),
2998                     false /* includeDeleted */);
2999         }
3000
3001         @Override
3002         public ParceledListSlice<NotificationChannelGroup>
3003                 getNotificationChannelGroupsFromPrivilegedListener(
3004                 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
3005             Preconditions.checkNotNull(pkg);
3006             Preconditions.checkNotNull(user);
3007             verifyPrivilegedListener(token, user);
3008
3009             List<NotificationChannelGroup> groups = new ArrayList<>();
3010             groups.addAll(mRankingHelper.getNotificationChannelGroups(
3011                     pkg, getUidForPackageAndUser(pkg, user)));
3012             return new ParceledListSlice<>(groups);
3013         }
3014
3015         private void verifyPrivilegedListener(INotificationListener token, UserHandle user) {
3016             ManagedServiceInfo info;
3017             synchronized (mNotificationLock) {
3018                 info = mListeners.checkServiceTokenLocked(token);
3019             }
3020             if (!hasCompanionDevice(info)) {
3021                 throw new SecurityException(info + " does not have access");
3022             }
3023             if (!info.enabledAndUserMatches(user.getIdentifier())) {
3024                 throw new SecurityException(info + " does not have access");
3025             }
3026         }
3027
3028         private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
3029             int uid = 0;
3030             long identity = Binder.clearCallingIdentity();
3031             try {
3032                 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
3033             } finally {
3034                 Binder.restoreCallingIdentity(identity);
3035             }
3036             return uid;
3037         }
3038
3039         @Override
3040         public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
3041                 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
3042                 throws RemoteException {
3043             new ShellCmd().exec(this, in, out, err, args, callback, resultReceiver);
3044         }
3045     };
3046
3047     private void applyAdjustment(NotificationRecord r, Adjustment adjustment) {
3048         if (r == null) {
3049             return;
3050         }
3051         if (adjustment.getSignals() != null) {
3052             Bundle.setDefusable(adjustment.getSignals(), true);
3053             r.addAdjustment(adjustment);
3054         }
3055     }
3056
3057     @GuardedBy("mNotificationLock")
3058     void addAutogroupKeyLocked(String key) {
3059         NotificationRecord r = mNotificationsByKey.get(key);
3060         if (r == null) {
3061             return;
3062         }
3063         if (r.sbn.getOverrideGroupKey() == null) {
3064             addAutoGroupAdjustment(r, GroupHelper.AUTOGROUP_KEY);
3065             EventLogTags.writeNotificationAutogrouped(key);
3066             mRankingHandler.requestSort();
3067         }
3068     }
3069
3070     @GuardedBy("mNotificationLock")
3071     void removeAutogroupKeyLocked(String key) {
3072         NotificationRecord r = mNotificationsByKey.get(key);
3073         if (r == null) {
3074             return;
3075         }
3076         if (r.sbn.getOverrideGroupKey() != null) {
3077             addAutoGroupAdjustment(r, null);
3078             EventLogTags.writeNotificationUnautogrouped(key);
3079             mRankingHandler.requestSort();
3080         }
3081     }
3082
3083     private void addAutoGroupAdjustment(NotificationRecord r, String overrideGroupKey) {
3084         Bundle signals = new Bundle();
3085         signals.putString(Adjustment.KEY_GROUP_KEY, overrideGroupKey);
3086         Adjustment adjustment =
3087                 new Adjustment(r.sbn.getPackageName(), r.getKey(), signals, "", r.sbn.getUserId());
3088         r.addAdjustment(adjustment);
3089     }
3090
3091     // Clears the 'fake' auto-group summary.
3092     @GuardedBy("mNotificationLock")
3093     private void clearAutogroupSummaryLocked(int userId, String pkg) {
3094         ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3095         if (summaries != null && summaries.containsKey(pkg)) {
3096             // Clear summary.
3097             final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
3098             if (removed != null) {
3099                 boolean wasPosted = removeFromNotificationListsLocked(removed);
3100                 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED, wasPosted, null);
3101             }
3102         }
3103     }
3104
3105     @GuardedBy("mNotificationLock")
3106     private boolean hasAutoGroupSummaryLocked(StatusBarNotification sbn) {
3107         ArrayMap<String, String> summaries = mAutobundledSummaries.get(sbn.getUserId());
3108         return summaries != null && summaries.containsKey(sbn.getPackageName());
3109     }
3110
3111     // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
3112     private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
3113         NotificationRecord summaryRecord = null;
3114         synchronized (mNotificationLock) {
3115             NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
3116             if (notificationRecord == null) {
3117                 // The notification could have been cancelled again already. A successive
3118                 // adjustment will post a summary if needed.
3119                 return;
3120             }
3121             final StatusBarNotification adjustedSbn = notificationRecord.sbn;
3122             userId = adjustedSbn.getUser().getIdentifier();
3123             ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3124             if (summaries == null) {
3125                 summaries = new ArrayMap<>();
3126             }
3127             mAutobundledSummaries.put(userId, summaries);
3128             if (!summaries.containsKey(pkg)) {
3129                 // Add summary
3130                 final ApplicationInfo appInfo =
3131                        adjustedSbn.getNotification().extras.getParcelable(
3132                                Notification.EXTRA_BUILDER_APPLICATION_INFO);
3133                 final Bundle extras = new Bundle();
3134                 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
3135                 final String channelId = notificationRecord.getChannel().getId();
3136                 final Notification summaryNotification =
3137                         new Notification.Builder(getContext(), channelId)
3138                                 .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
3139                                 .setGroupSummary(true)
3140                                 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN)
3141                                 .setGroup(GroupHelper.AUTOGROUP_KEY)
3142                                 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
3143                                 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
3144                                 .setColor(adjustedSbn.getNotification().color)
3145                                 .setLocalOnly(true)
3146                                 .build();
3147                 summaryNotification.extras.putAll(extras);
3148                 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
3149                 if (appIntent != null) {
3150                     summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
3151                             getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
3152                 }
3153                 final StatusBarNotification summarySbn =
3154                         new StatusBarNotification(adjustedSbn.getPackageName(),
3155                                 adjustedSbn.getOpPkg(),
3156                                 Integer.MAX_VALUE,
3157                                 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
3158                                 adjustedSbn.getInitialPid(), summaryNotification,
3159                                 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
3160                                 System.currentTimeMillis());
3161                 summaryRecord = new NotificationRecord(getContext(), summarySbn,
3162                         notificationRecord.getChannel());
3163                 summaries.put(pkg, summarySbn.getKey());
3164             }
3165         }
3166         if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
3167                 summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord, true)) {
3168             mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
3169         }
3170     }
3171
3172     private String disableNotificationEffects(NotificationRecord record) {
3173         if (mDisableNotificationEffects) {
3174             return "booleanState";
3175         }
3176         if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
3177             return "listenerHints";
3178         }
3179         if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
3180             return "callState";
3181         }
3182         return null;
3183     };
3184
3185     private void dumpJson(PrintWriter pw, DumpFilter filter) {
3186         JSONObject dump = new JSONObject();
3187         try {
3188             dump.put("service", "Notification Manager");
3189             dump.put("bans", mRankingHelper.dumpBansJson(filter));
3190             dump.put("ranking", mRankingHelper.dumpJson(filter));
3191             dump.put("stats", mUsageStats.dumpJson(filter));
3192             dump.put("channels", mRankingHelper.dumpChannelsJson(filter));
3193         } catch (JSONException e) {
3194             e.printStackTrace();
3195         }
3196         pw.println(dump);
3197     }
3198
3199     private void dumpProto(FileDescriptor fd, DumpFilter filter) {
3200         final ProtoOutputStream proto = new ProtoOutputStream(fd);
3201         synchronized (mNotificationLock) {
3202             long records = proto.start(NotificationServiceDumpProto.RECORDS);
3203             int N = mNotificationList.size();
3204             if (N > 0) {
3205                 for (int i = 0; i < N; i++) {
3206                     final NotificationRecord nr = mNotificationList.get(i);
3207                     if (filter.filtered && !filter.matches(nr.sbn)) continue;
3208                     nr.dump(proto, filter.redact);
3209                     proto.write(NotificationRecordProto.STATE, NotificationServiceProto.POSTED);
3210                 }
3211             }
3212             N = mEnqueuedNotifications.size();
3213             if (N > 0) {
3214                 for (int i = 0; i < N; i++) {
3215                     final NotificationRecord nr = mEnqueuedNotifications.get(i);
3216                     if (filter.filtered && !filter.matches(nr.sbn)) continue;
3217                     nr.dump(proto, filter.redact);
3218                     proto.write(NotificationRecordProto.STATE, NotificationServiceProto.ENQUEUED);
3219                 }
3220             }
3221             List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
3222             N = snoozed.size();
3223             if (N > 0) {
3224                 for (int i = 0; i < N; i++) {
3225                     final NotificationRecord nr = snoozed.get(i);
3226                     if (filter.filtered && !filter.matches(nr.sbn)) continue;
3227                     nr.dump(proto, filter.redact);
3228                     proto.write(NotificationRecordProto.STATE, NotificationServiceProto.SNOOZED);
3229                 }
3230             }
3231             proto.end(records);
3232         }
3233
3234         long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
3235         mZenModeHelper.dump(proto);
3236         for (ComponentName suppressor : mEffectsSuppressors) {
3237             proto.write(ZenModeProto.SUPPRESSORS, suppressor.toString());
3238         }
3239         proto.end(zenLog);
3240
3241         proto.flush();
3242     }
3243
3244     void dumpImpl(PrintWriter pw, DumpFilter filter) {
3245         pw.print("Current Notification Manager state");
3246         if (filter.filtered) {
3247             pw.print(" (filtered to "); pw.print(filter); pw.print(")");
3248         }
3249         pw.println(':');
3250         int N;
3251         final boolean zenOnly = filter.filtered && filter.zen;
3252
3253         if (!zenOnly) {
3254             synchronized (mToastQueue) {
3255                 N = mToastQueue.size();
3256                 if (N > 0) {
3257                     pw.println("  Toast Queue:");
3258                     for (int i=0; i<N; i++) {
3259                         mToastQueue.get(i).dump(pw, "    ", filter);
3260                     }
3261                     pw.println("  ");
3262                 }
3263             }
3264         }
3265
3266         synchronized (mNotificationLock) {
3267             if (!zenOnly) {
3268                 N = mNotificationList.size();
3269                 if (N > 0) {
3270                     pw.println("  Notification List:");
3271                     for (int i=0; i<N; i++) {
3272                         final NotificationRecord nr = mNotificationList.get(i);
3273                         if (filter.filtered && !filter.matches(nr.sbn)) continue;
3274                         nr.dump(pw, "    ", getContext(), filter.redact);
3275                     }
3276                     pw.println("  ");
3277                 }
3278
3279                 if (!filter.filtered) {
3280                     N = mLights.size();
3281                     if (N > 0) {
3282                         pw.println("  Lights List:");
3283                         for (int i=0; i<N; i++) {
3284                             if (i == N - 1) {
3285                                 pw.print("  > ");
3286                             } else {
3287                                 pw.print("    ");
3288                             }
3289                             pw.println(mLights.get(i));
3290                         }
3291                         pw.println("  ");
3292                     }
3293                     pw.println("  mUseAttentionLight=" + mUseAttentionLight);
3294                     pw.println("  mNotificationPulseEnabled=" + mNotificationPulseEnabled);
3295                     pw.println("  mSoundNotificationKey=" + mSoundNotificationKey);
3296                     pw.println("  mVibrateNotificationKey=" + mVibrateNotificationKey);
3297                     pw.println("  mDisableNotificationEffects=" + mDisableNotificationEffects);
3298                     pw.println("  mCallState=" + callStateToString(mCallState));
3299                     pw.println("  mSystemReady=" + mSystemReady);
3300                     pw.println("  mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
3301                 }
3302                 pw.println("  mArchive=" + mArchive.toString());
3303                 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
3304                 int j=0;
3305                 while (iter.hasNext()) {
3306                     final StatusBarNotification sbn = iter.next();
3307                     if (filter != null && !filter.matches(sbn)) continue;
3308                     pw.println("    " + sbn);
3309                     if (++j >= 5) {
3310                         if (iter.hasNext()) pw.println("    ...");
3311                         break;
3312                     }
3313                 }
3314
3315                 if (!zenOnly) {
3316                     N = mEnqueuedNotifications.size();
3317                     if (N > 0) {
3318                         pw.println("  Enqueued Notification List:");
3319                         for (int i = 0; i < N; i++) {
3320                             final NotificationRecord nr = mEnqueuedNotifications.get(i);
3321                             if (filter.filtered && !filter.matches(nr.sbn)) continue;
3322                             nr.dump(pw, "    ", getContext(), filter.redact);
3323                         }
3324                         pw.println("  ");
3325                     }
3326
3327                     mSnoozeHelper.dump(pw, filter);
3328                 }
3329             }
3330
3331             if (!zenOnly) {
3332                 pw.println("\n  Ranking Config:");
3333                 mRankingHelper.dump(pw, "    ", filter);
3334
3335                 pw.println("\n  Notification listeners:");
3336                 mListeners.dump(pw, filter);
3337                 pw.print("    mListenerHints: "); pw.println(mListenerHints);
3338                 pw.print("    mListenersDisablingEffects: (");
3339                 N = mListenersDisablingEffects.size();
3340                 for (int i = 0; i < N; i++) {
3341                     final int hint = mListenersDisablingEffects.keyAt(i);
3342                     if (i > 0) pw.print(';');
3343                     pw.print("hint[" + hint + "]:");
3344
3345                     final ArraySet<ManagedServiceInfo> listeners =
3346                             mListenersDisablingEffects.valueAt(i);
3347                     final int listenerSize = listeners.size();
3348
3349                     for (int j = 0; j < listenerSize; j++) {
3350                         if (i > 0) pw.print(',');
3351                         final ManagedServiceInfo listener = listeners.valueAt(i);
3352                         pw.print(listener.component);
3353                     }
3354                 }
3355                 pw.println(')');
3356                 pw.println("\n  Notification assistant services:");
3357                 mAssistants.dump(pw, filter);
3358             }
3359
3360             if (!filter.filtered || zenOnly) {
3361                 pw.println("\n  Zen Mode:");
3362                 pw.print("    mInterruptionFilter="); pw.println(mInterruptionFilter);
3363                 mZenModeHelper.dump(pw, "    ");
3364
3365                 pw.println("\n  Zen Log:");
3366                 ZenLog.dump(pw, "    ");
3367             }
3368
3369             pw.println("\n  Condition providers:");
3370             mConditionProviders.dump(pw, filter);
3371
3372             pw.println("\n  Group summaries:");
3373             for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
3374                 NotificationRecord r = entry.getValue();
3375                 pw.println("    " + entry.getKey() + " -> " + r.getKey());
3376                 if (mNotificationsByKey.get(r.getKey()) != r) {
3377                     pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
3378                     r.dump(pw, "      ", getContext(), filter.redact);
3379                 }
3380             }
3381
3382             if (!zenOnly) {
3383                 pw.println("\n  Usage Stats:");
3384                 mUsageStats.dump(pw, "    ", filter);
3385             }
3386         }
3387     }
3388
3389     /**
3390      * The private API only accessible to the system process.
3391      */
3392     private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
3393         @Override
3394         public NotificationChannel getNotificationChannel(String pkg, int uid, String
3395                 channelId) {
3396             return mRankingHelper.getNotificationChannel(pkg, uid, channelId, false);
3397         }
3398
3399         @Override
3400         public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
3401                 String tag, int id, Notification notification, int userId) {
3402             enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
3403                     userId);
3404         }
3405
3406         @Override
3407         public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
3408                 int userId) {
3409             checkCallerIsSystem();
3410             mHandler.post(new Runnable() {
3411                 @Override
3412                 public void run() {
3413                     synchronized (mNotificationLock) {
3414                         removeForegroundServiceFlagByListLocked(
3415                                 mEnqueuedNotifications, pkg, notificationId, userId);
3416                         removeForegroundServiceFlagByListLocked(
3417                                 mNotificationList, pkg, notificationId, userId);
3418                     }
3419                 }
3420             });
3421         }
3422
3423         @GuardedBy("mNotificationLock")
3424         private void removeForegroundServiceFlagByListLocked(
3425                 ArrayList<NotificationRecord> notificationList, String pkg, int notificationId,
3426                 int userId) {
3427             NotificationRecord r = findNotificationByListLocked(
3428                     notificationList, pkg, null, notificationId, userId);
3429             if (r == null) {
3430                 return;
3431             }
3432             StatusBarNotification sbn = r.sbn;
3433             // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
3434             // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
3435             // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
3436             // initially *and* force remove FLAG_FOREGROUND_SERVICE.
3437             sbn.getNotification().flags =
3438                     (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
3439             mRankingHelper.sort(mNotificationList);
3440             mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
3441         }
3442     };
3443
3444     void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
3445             final int callingPid, final String tag, final int id, final Notification notification,
3446             int incomingUserId) {
3447         if (DBG) {
3448             Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
3449                     + " notification=" + notification);
3450         }
3451         checkCallerIsSystemOrSameApp(pkg);
3452
3453         final int userId = ActivityManager.handleIncomingUser(callingPid,
3454                 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
3455         final UserHandle user = new UserHandle(userId);
3456
3457         if (pkg == null || notification == null) {
3458             throw new IllegalArgumentException("null not allowed: pkg=" + pkg
3459                     + " id=" + id + " notification=" + notification);
3460         }
3461
3462         // The system can post notifications for any package, let us resolve that.
3463         final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);
3464
3465         // Fix the notification as best we can.
3466         try {
3467             final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
3468                     pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
3469                     (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
3470             Notification.addFieldsFromContext(ai, notification);
3471
3472             int canColorize = mPackageManagerClient.checkPermission(
3473                     android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, pkg);
3474             if (canColorize == PERMISSION_GRANTED) {
3475                 notification.flags |= Notification.FLAG_CAN_COLORIZE;
3476             } else {
3477                 notification.flags &= ~Notification.FLAG_CAN_COLORIZE;
3478             }
3479
3480         } catch (NameNotFoundException e) {
3481             Slog.e(TAG, "Cannot create a context for sending app", e);
3482             return;
3483         }
3484
3485         mUsageStats.registerEnqueuedByApp(pkg);
3486
3487         // setup local book-keeping
3488         String channelId = notification.getChannelId();
3489         if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
3490             channelId = (new Notification.TvExtender(notification)).getChannelId();
3491         }
3492         final NotificationChannel channel = mRankingHelper.getNotificationChannel(pkg,
3493                 notificationUid, channelId, false /* includeDeleted */);
3494         if (channel == null) {
3495             final String noChannelStr = "No Channel found for "
3496                     + "pkg=" + pkg
3497                     + ", channelId=" + channelId
3498                     + ", id=" + id
3499                     + ", tag=" + tag
3500                     + ", opPkg=" + opPkg
3501                     + ", callingUid=" + callingUid
3502                     + ", userId=" + userId
3503                     + ", incomingUserId=" + incomingUserId
3504                     + ", notificationUid=" + notificationUid
3505                     + ", notification=" + notification;
3506             Log.e(TAG, noChannelStr);
3507             doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
3508                     "Failed to post notification on channel \"" + channelId + "\"\n" +
3509                     "See log for more details");
3510             return;
3511         }
3512
3513         final StatusBarNotification n = new StatusBarNotification(
3514                 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
3515                 user, null, System.currentTimeMillis());
3516         final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
3517
3518         if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0
3519                 && (channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
3520                 && (r.getImportance() == IMPORTANCE_MIN || r.getImportance() == IMPORTANCE_NONE)) {
3521             // Increase the importance of foreground service notifications unless the user had an
3522             // opinion otherwise
3523             if (TextUtils.isEmpty(channelId)
3524                     || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
3525                 r.setImportance(IMPORTANCE_LOW, "Bumped for foreground service");
3526             } else {
3527                 channel.setImportance(IMPORTANCE_LOW);
3528                 mRankingHelper.updateNotificationChannel(pkg, notificationUid, channel, false);
3529                 r.updateNotificationChannel(channel);
3530             }
3531         }
3532
3533         if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
3534                 r.sbn.getOverrideGroupKey() != null)) {
3535             return;
3536         }
3537
3538         // Whitelist pending intents.
3539         if (notification.allPendingIntents != null) {
3540             final int intentCount = notification.allPendingIntents.size();
3541             if (intentCount > 0) {
3542                 final ActivityManagerInternal am = LocalServices
3543                         .getService(ActivityManagerInternal.class);
3544                 final long duration = LocalServices.getService(
3545                         DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
3546                 for (int i = 0; i < intentCount; i++) {
3547                     PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
3548                     if (pendingIntent != null) {
3549                         am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
3550                                 WHITELIST_TOKEN, duration);
3551                     }
3552                 }
3553             }
3554         }
3555
3556         mHandler.post(new EnqueueNotificationRunnable(userId, r));
3557     }
3558
3559     private void doChannelWarningToast(CharSequence toastText) {
3560         final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
3561         final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
3562                 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
3563         if (warningEnabled) {
3564             Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
3565                     Toast.LENGTH_SHORT);
3566             toast.show();
3567         }
3568     }
3569
3570     private int resolveNotificationUid(String opPackageName, int callingUid, int userId) {
3571         // The system can post notifications on behalf of any package it wants
3572         if (isCallerSystemOrPhone() && opPackageName != null && !"android".equals(opPackageName)) {
3573             try {
3574                 return getContext().getPackageManager()
3575                         .getPackageUidAsUser(opPackageName, userId);
3576             } catch (NameNotFoundException e) {
3577                 /* ignore */
3578             }
3579         }
3580         return callingUid;
3581     }
3582
3583     /**
3584      * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
3585      *
3586      * Has side effects.
3587      */
3588     private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag,
3589             NotificationRecord r, boolean isAutogroup) {
3590         final String pkg = r.sbn.getPackageName();
3591         final String dialerPackage =
3592                 getContext().getSystemService(TelecomManager.class).getSystemDialerPackage();
3593         final boolean isSystemNotification =
3594                 isUidSystemOrPhone(callingUid) || ("android".equals(pkg))
3595                 || TextUtils.equals(pkg, dialerPackage);
3596         final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
3597
3598         // Limit the number of notifications that any given package except the android
3599         // package or a registered listener can enqueue.  Prevents DOS attacks and deals with leaks.
3600         if (!isSystemNotification && !isNotificationFromListener) {
3601             synchronized (mNotificationLock) {
3602                 if (mNotificationsByKey.get(r.sbn.getKey()) == null && isCallerInstantApp(pkg)) {
3603                     // Ephemeral apps have some special constraints for notifications.
3604                     // They are not allowed to create new notifications however they are allowed to
3605                     // update notifications created by the system (e.g. a foreground service
3606                     // notification).
3607                     throw new SecurityException("Instant app " + pkg
3608                             + " cannot create notifications");
3609                 }
3610
3611                 // rate limit updates that aren't completed progress notifications
3612                 if (mNotificationsByKey.get(r.sbn.getKey()) != null
3613                         && !r.getNotification().hasCompletedProgress()
3614                         && !isAutogroup) {
3615
3616                     final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
3617                     if (appEnqueueRate > mMaxPackageEnqueueRate) {
3618                         mUsageStats.registerOverRateQuota(pkg);
3619                         final long now = SystemClock.elapsedRealtime();
3620                         if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
3621                             Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
3622                                     + ". Shedding " + r.sbn.getKey() + ". package=" + pkg);
3623                             mLastOverRateLogTime = now;
3624                         }
3625                         return false;
3626                     }
3627                 }
3628
3629                 // limit the number of outstanding notificationrecords an app can have
3630                 int count = getNotificationCountLocked(pkg, userId, id, tag);
3631                 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
3632                     mUsageStats.registerOverCountQuota(pkg);
3633                     Slog.e(TAG, "Package has already posted or enqueued " + count
3634                             + " notifications.  Not showing more.  package=" + pkg);
3635                     return false;
3636                 }
3637             }
3638         }
3639
3640         // snoozed apps
3641         if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
3642             MetricsLogger.action(r.getLogMaker()
3643                     .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
3644                     .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
3645             if (DBG) {
3646                 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
3647             }
3648             mSnoozeHelper.update(userId, r);
3649             savePolicyFile();
3650             return false;
3651         }
3652
3653
3654         // blocked apps
3655         if (isBlocked(r, mUsageStats)) {
3656             return false;
3657         }
3658
3659         return true;
3660     }
3661
3662     protected int getNotificationCountLocked(String pkg, int userId, int excludedId,
3663             String excludedTag) {
3664         int count = 0;
3665         final int N = mNotificationList.size();
3666         for (int i = 0; i < N; i++) {
3667             final NotificationRecord existing = mNotificationList.get(i);
3668             if (existing.sbn.getPackageName().equals(pkg)
3669                     && existing.sbn.getUserId() == userId) {
3670                 if (existing.sbn.getId() == excludedId
3671                         && TextUtils.equals(existing.sbn.getTag(), excludedTag)) {
3672                     continue;
3673                 }
3674                 count++;
3675             }
3676         }
3677         final int M = mEnqueuedNotifications.size();
3678         for (int i = 0; i < M; i++) {
3679             final NotificationRecord existing = mEnqueuedNotifications.get(i);
3680             if (existing.sbn.getPackageName().equals(pkg)
3681                     && existing.sbn.getUserId() == userId) {
3682                 count++;
3683             }
3684         }
3685         return count;
3686     }
3687
3688     protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
3689         final String pkg = r.sbn.getPackageName();
3690         final int callingUid = r.sbn.getUid();
3691
3692         final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
3693         if (isPackageSuspended) {
3694             Slog.e(TAG, "Suppressing notification from package due to package "
3695                     + "suspended by administrator.");
3696             usageStats.registerSuspendedByAdmin(r);
3697             return isPackageSuspended;
3698         }
3699
3700         final boolean isBlocked =
3701                 mRankingHelper.getImportance(pkg, callingUid) == NotificationManager.IMPORTANCE_NONE
3702                 || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE;
3703         if (isBlocked) {
3704             Slog.e(TAG, "Suppressing notification from package by user request.");
3705             usageStats.registerBlocked(r);
3706         }
3707         return isBlocked;
3708     }
3709
3710     protected class SnoozeNotificationRunnable implements Runnable {
3711         private final String mKey;
3712         private final long mDuration;
3713         private final String mSnoozeCriterionId;
3714
3715         SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) {
3716             mKey = key;
3717             mDuration = duration;
3718             mSnoozeCriterionId = snoozeCriterionId;
3719         }
3720
3721         @Override
3722         public void run() {
3723             synchronized (mNotificationLock) {
3724                 final NotificationRecord r = findNotificationByKeyLocked(mKey);
3725                 if (r != null) {
3726                     snoozeLocked(r);
3727                 }
3728             }
3729         }
3730
3731         @GuardedBy("mNotificationLock")
3732         void snoozeLocked(NotificationRecord r) {
3733             if (r.sbn.isGroup()) {
3734                 final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked(
3735                         r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId());
3736                 if (r.getNotification().isGroupSummary()) {
3737                     // snooze summary and all children
3738                     for (int i = 0; i < groupNotifications.size(); i++) {
3739                         snoozeNotificationLocked(groupNotifications.get(i));
3740                     }
3741                 } else {
3742                     // if there is a valid summary for this group, and we are snoozing the only
3743                     // child, also snooze the summary
3744                     if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) {
3745                         if (groupNotifications.size() != 2) {
3746                             snoozeNotificationLocked(r);
3747                         } else {
3748                             // snooze summary and the one child
3749                             for (int i = 0; i < groupNotifications.size(); i++) {
3750                                 snoozeNotificationLocked(groupNotifications.get(i));
3751                             }
3752                         }
3753                     } else {
3754                         snoozeNotificationLocked(r);
3755                     }
3756                 }
3757             } else {
3758                 // just snooze the one notification
3759                 snoozeNotificationLocked(r);
3760             }
3761         }
3762
3763         @GuardedBy("mNotificationLock")
3764         void snoozeNotificationLocked(NotificationRecord r) {
3765             MetricsLogger.action(r.getLogMaker()
3766                     .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
3767                     .setType(MetricsEvent.TYPE_CLOSE)
3768                     .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS,
3769                             mDuration)
3770                     .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
3771                             mSnoozeCriterionId == null ? 0 : 1));
3772             boolean wasPosted = removeFromNotificationListsLocked(r);
3773             cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null);
3774             updateLightsLocked();
3775             if (mSnoozeCriterionId != null) {
3776                 mAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
3777                 mSnoozeHelper.snooze(r);
3778             } else {
3779                 mSnoozeHelper.snooze(r, mDuration);
3780             }
3781             savePolicyFile();
3782         }
3783     }
3784
3785     protected class EnqueueNotificationRunnable implements Runnable {
3786         private final NotificationRecord r;
3787         private final int userId;
3788
3789         EnqueueNotificationRunnable(int userId, NotificationRecord r) {
3790             this.userId = userId;
3791             this.r = r;
3792         };
3793
3794         @Override
3795         public void run() {
3796             synchronized (mNotificationLock) {
3797                 mEnqueuedNotifications.add(r);
3798                 scheduleTimeoutLocked(r);
3799
3800                 final StatusBarNotification n = r.sbn;
3801                 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
3802                 NotificationRecord old = mNotificationsByKey.get(n.getKey());
3803                 if (old != null) {
3804                     // Retain ranking information from previous record
3805                     r.copyRankingInformation(old);
3806                 }
3807
3808                 final int callingUid = n.getUid();
3809                 final int callingPid = n.getInitialPid();
3810                 final Notification notification = n.getNotification();
3811                 final String pkg = n.getPackageName();
3812                 final int id = n.getId();
3813                 final String tag = n.getTag();
3814
3815                 // Handle grouped notifications and bail out early if we
3816                 // can to avoid extracting signals.
3817                 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
3818
3819                 // if this is a group child, unsnooze parent summary
3820                 if (n.isGroup() && notification.isGroupChild()) {
3821                     mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
3822                 }
3823
3824                 // This conditional is a dirty hack to limit the logging done on
3825                 //     behalf of the download manager without affecting other apps.
3826                 if (!pkg.equals("com.android.providers.downloads")
3827                         || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
3828                     int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
3829                     if (old != null) {
3830                         enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
3831                     }
3832                     EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
3833                             pkg, id, tag, userId, notification.toString(),
3834                             enqueueStatus);
3835                 }
3836
3837                 mRankingHelper.extractSignals(r);
3838
3839                 // tell the assistant service about the notification
3840                 if (mAssistants.isEnabled()) {
3841                     mAssistants.onNotificationEnqueued(r);
3842                     mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
3843                             DELAY_FOR_ASSISTANT_TIME);
3844                 } else {
3845                     mHandler.post(new PostNotificationRunnable(r.getKey()));
3846                 }
3847             }
3848         }
3849     }
3850
3851     protected class PostNotificationRunnable implements Runnable {
3852         private final String key;
3853
3854         PostNotificationRunnable(String key) {
3855             this.key = key;
3856         }
3857
3858         @Override
3859         public void run() {
3860             synchronized (mNotificationLock) {
3861                 try {
3862                     NotificationRecord r = null;
3863                     int N = mEnqueuedNotifications.size();
3864                     for (int i = 0; i < N; i++) {
3865                         final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
3866                         if (Objects.equals(key, enqueued.getKey())) {
3867                             r = enqueued;
3868                             break;
3869                         }
3870                     }
3871                     if (r == null) {
3872                         Slog.i(TAG, "Cannot find enqueued record for key: " + key);
3873                         return;
3874                     }
3875                     NotificationRecord old = mNotificationsByKey.get(key);
3876                     final StatusBarNotification n = r.sbn;
3877                     final Notification notification = n.getNotification();
3878                     int index = indexOfNotificationLocked(n.getKey());
3879                     if (index < 0) {
3880                         mNotificationList.add(r);
3881                         mUsageStats.registerPostedByApp(r);
3882                     } else {
3883                         old = mNotificationList.get(index);
3884                         mNotificationList.set(index, r);
3885                         mUsageStats.registerUpdatedByApp(r, old);
3886                         // Make sure we don't lose the foreground service state.
3887                         notification.flags |=
3888                                 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
3889                         r.isUpdate = true;
3890                     }
3891
3892                     mNotificationsByKey.put(n.getKey(), r);
3893
3894                     // Ensure if this is a foreground service that the proper additional
3895                     // flags are set.
3896                     if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
3897                         notification.flags |= Notification.FLAG_ONGOING_EVENT
3898                                 | Notification.FLAG_NO_CLEAR;
3899                     }
3900
3901                     applyZenModeLocked(r);
3902                     mRankingHelper.sort(mNotificationList);
3903
3904                     if (notification.getSmallIcon() != null) {
3905                         StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
3906                         mListeners.notifyPostedLocked(n, oldSbn);
3907                         if (oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())) {
3908                             mHandler.post(new Runnable() {
3909                                 @Override
3910                                 public void run() {
3911                                     mGroupHelper.onNotificationPosted(
3912                                             n, hasAutoGroupSummaryLocked(n));
3913                                 }
3914                             });
3915                         }
3916                     } else {
3917                         Slog.e(TAG, "Not posting notification without small icon: " + notification);
3918                         if (old != null && !old.isCanceled) {
3919                             mListeners.notifyRemovedLocked(n,
3920                                     NotificationListenerService.REASON_ERROR);
3921                             mHandler.post(new Runnable() {
3922                                 @Override
3923                                 public void run() {
3924                                     mGroupHelper.onNotificationRemoved(n);
3925                                 }
3926                             });
3927                         }
3928                         // ATTENTION: in a future release we will bail out here
3929                         // so that we do not play sounds, show lights, etc. for invalid
3930                         // notifications
3931                         Slog.e(TAG, "WARNING: In a future release this will crash the app: "
3932                                 + n.getPackageName());
3933                     }
3934
3935                     buzzBeepBlinkLocked(r);
3936                 } finally {
3937                     int N = mEnqueuedNotifications.size();
3938                     for (int i = 0; i < N; i++) {
3939                         final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
3940                         if (Objects.equals(key, enqueued.getKey())) {
3941                             mEnqueuedNotifications.remove(i);
3942                             break;
3943                         }
3944                     }
3945                 }
3946             }
3947         }
3948     }
3949
3950     /**
3951      * Ensures that grouped notification receive their special treatment.
3952      *
3953      * <p>Cancels group children if the new notification causes a group to lose
3954      * its summary.</p>
3955      *
3956      * <p>Updates mSummaryByGroupKey.</p>
3957      */
3958     @GuardedBy("mNotificationLock")
3959     private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
3960             int callingUid, int callingPid) {
3961         StatusBarNotification sbn = r.sbn;
3962         Notification n = sbn.getNotification();
3963         if (n.isGroupSummary() && !sbn.isAppGroup())  {
3964             // notifications without a group shouldn't be a summary, otherwise autobundling can
3965             // lead to bugs
3966             n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
3967         }
3968
3969         String group = sbn.getGroupKey();
3970         boolean isSummary = n.isGroupSummary();
3971
3972         Notification oldN = old != null ? old.sbn.getNotification() : null;
3973         String oldGroup = old != null ? old.sbn.getGroupKey() : null;
3974         boolean oldIsSummary = old != null && oldN.isGroupSummary();
3975
3976         if (oldIsSummary) {
3977             NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
3978             if (removedSummary != old) {
3979                 String removedKey =
3980                         removedSummary != null ? removedSummary.getKey() : "<null>";
3981                 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
3982                         ", removed=" + removedKey);
3983             }
3984         }
3985         if (isSummary) {
3986             mSummaryByGroupKey.put(group, r);
3987         }
3988
3989         // Clear out group children of the old notification if the update
3990         // causes the group summary to go away. This happens when the old
3991         // notification was a summary and the new one isn't, or when the old
3992         // notification was a summary and its group key changed.
3993         if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
3994             cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */,
3995                     null);
3996         }
3997     }
3998
3999     @VisibleForTesting
4000     @GuardedBy("mNotificationLock")
4001     void scheduleTimeoutLocked(NotificationRecord record) {
4002         if (record.getNotification().getTimeoutAfter() > 0) {
4003             final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
4004                     REQUEST_CODE_TIMEOUT,
4005                     new Intent(ACTION_NOTIFICATION_TIMEOUT)
4006                             .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
4007                                     .appendPath(record.getKey()).build())
4008                             .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
4009                             .putExtra(EXTRA_KEY, record.getKey()),
4010                     PendingIntent.FLAG_UPDATE_CURRENT);
4011             mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
4012                     SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
4013         }
4014     }
4015
4016     @VisibleForTesting
4017     @GuardedBy("mNotificationLock")
4018     void buzzBeepBlinkLocked(NotificationRecord record) {
4019         boolean buzz = false;
4020         boolean beep = false;
4021         boolean blink = false;
4022
4023         final Notification notification = record.sbn.getNotification();
4024         final String key = record.getKey();
4025
4026         // Should this notification make noise, vibe, or use the LED?
4027         final boolean aboveThreshold =
4028                 record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
4029
4030         // Remember if this notification already owns the notification channels.
4031         boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
4032         boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
4033         // These are set inside the conditional if the notification is allowed to make noise.
4034         boolean hasValidVibrate = false;
4035         boolean hasValidSound = false;
4036         boolean sentAccessibilityEvent = false;
4037         // If the notification will appear in the status bar, it should send an accessibility
4038         // event
4039         if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) {
4040             sendAccessibilityEvent(notification, record.sbn.getPackageName());
4041             sentAccessibilityEvent = true;
4042         }
4043
4044         if (aboveThreshold && isNotificationForCurrentUser(record)) {
4045
4046             if (mSystemReady && mAudioManager != null) {
4047                 Uri soundUri = record.getSound();
4048                 hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
4049                 long[] vibration = record.getVibration();
4050                 // Demote sound to vibration if vibration missing & phone in vibration mode.
4051                 if (vibration == null
4052                         && hasValidSound
4053                         && (mAudioManager.getRingerModeInternal()
4054                         == AudioManager.RINGER_MODE_VIBRATE)
4055                         && mAudioManager.getStreamVolume(
4056                         AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) == 0) {
4057                     vibration = mFallbackVibrationPattern;
4058                 }
4059                 hasValidVibrate = vibration != null;
4060
4061                 boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
4062                 if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
4063                     if (!sentAccessibilityEvent) {
4064                         sendAccessibilityEvent(notification, record.sbn.getPackageName());
4065                         sentAccessibilityEvent = true;
4066                     }
4067                     if (DBG) Slog.v(TAG, "Interrupting!");
4068                     if (hasValidSound) {
4069                         mSoundNotificationKey = key;
4070                         if (mInCall) {
4071                             playInCallNotification();
4072                             beep = true;
4073                         } else {
4074                             beep = playSound(record, soundUri);
4075                         }
4076                     }
4077
4078                     final boolean ringerModeSilent =
4079                             mAudioManager.getRingerModeInternal()
4080                                     == AudioManager.RINGER_MODE_SILENT;
4081                     if (!mInCall && hasValidVibrate && !ringerModeSilent) {
4082                         mVibrateNotificationKey = key;
4083
4084                         buzz = playVibration(record, vibration, hasValidSound);
4085                     }
4086                 }
4087             }
4088         }
4089         // If a notification is updated to remove the actively playing sound or vibrate,
4090         // cancel that feedback now
4091         if (wasBeep && !hasValidSound) {
4092             clearSoundLocked();
4093         }
4094         if (wasBuzz && !hasValidVibrate) {
4095             clearVibrateLocked();
4096         }
4097
4098         // light
4099         // release the light
4100         boolean wasShowLights = mLights.remove(key);
4101         if (record.getLight() != null && aboveThreshold
4102                 && ((record.getSuppressedVisualEffects()
4103                 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
4104             mLights.add(key);
4105             updateLightsLocked();
4106             if (mUseAttentionLight) {
4107                 mAttentionLight.pulse();
4108             }
4109             blink = true;
4110         } else if (wasShowLights) {
4111             updateLightsLocked();
4112         }
4113         if (buzz || beep || blink) {
4114             MetricsLogger.action(record.getLogMaker()
4115                     .setCategory(MetricsEvent.NOTIFICATION_ALERT)
4116                     .setType(MetricsEvent.TYPE_OPEN)
4117                     .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
4118             EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
4119         }
4120     }
4121
4122     @GuardedBy("mNotificationLock")
4123     boolean shouldMuteNotificationLocked(final NotificationRecord record) {
4124         // Suppressed because it's a silent update
4125         final Notification notification = record.getNotification();
4126         if(record.isUpdate
4127                 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
4128             return true;
4129         }
4130
4131         // muted by listener
4132         final String disableEffects = disableNotificationEffects(record);
4133         if (disableEffects != null) {
4134             ZenLog.traceDisableEffects(record, disableEffects);
4135             return true;
4136         }
4137
4138         // suppressed due to DND
4139         if (record.isIntercepted()) {
4140             return true;
4141         }
4142
4143         // Suppressed because another notification in its group handles alerting
4144         if (record.sbn.isGroup()) {
4145             return notification.suppressAlertingDueToGrouping();
4146         }
4147
4148         // Suppressed for being too recently noisy
4149         final String pkg = record.sbn.getPackageName();
4150         if (mUsageStats.isAlertRateLimited(pkg)) {
4151             Slog.e(TAG, "Muting recently noisy " + record.getKey());
4152             return true;
4153         }
4154
4155         return false;
4156     }
4157
4158     private boolean playSound(final NotificationRecord record, Uri soundUri) {
4159         boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
4160         // do not play notifications if there is a user of exclusive audio focus
4161         // or the device is in vibrate mode
4162         if (!mAudioManager.isAudioFocusExclusive() && (mAudioManager.getRingerModeInternal()
4163                 != AudioManager.RINGER_MODE_VIBRATE || mAudioManager.getStreamVolume(
4164                 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) {
4165             final long identity = Binder.clearCallingIdentity();
4166             try {
4167                 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4168                 if (player != null) {
4169                     if (DBG) Slog.v(TAG, "Playing sound " + soundUri
4170                             + " with attributes " + record.getAudioAttributes());
4171                     player.playAsync(soundUri, record.sbn.getUser(), looping,
4172                             record.getAudioAttributes());
4173                     return true;
4174                 }
4175             } catch (RemoteException e) {
4176             } finally {
4177                 Binder.restoreCallingIdentity(identity);
4178             }
4179         }
4180         return false;
4181     }
4182
4183     private boolean playVibration(final NotificationRecord record, long[] vibration,
4184             boolean delayVibForSound) {
4185         // Escalate privileges so we can use the vibrator even if the
4186         // notifying app does not have the VIBRATE permission.
4187         long identity = Binder.clearCallingIdentity();
4188         try {
4189             final VibrationEffect effect;
4190             try {
4191                 final boolean insistent =
4192                         (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
4193                 effect = VibrationEffect.createWaveform(
4194                         vibration, insistent ? 0 : -1 /*repeatIndex*/);
4195             } catch (IllegalArgumentException e) {
4196                 Slog.e(TAG, "Error creating vibration waveform with pattern: " +
4197                         Arrays.toString(vibration));
4198                 return false;
4199             }
4200             if (delayVibForSound) {
4201                 new Thread(() -> {
4202                     // delay the vibration by the same amount as the notification sound
4203                     final int waitMs = mAudioManager.getFocusRampTimeMs(
4204                             AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
4205                             record.getAudioAttributes());
4206                     if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms");
4207                     try {
4208                         Thread.sleep(waitMs);
4209                     } catch (InterruptedException e) { }
4210                     mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
4211                             effect, record.getAudioAttributes());
4212                 }).start();
4213             } else {
4214                 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
4215                         effect, record.getAudioAttributes());
4216             }
4217             return true;
4218         } finally{
4219             Binder.restoreCallingIdentity(identity);
4220         }
4221     }
4222
4223     private boolean isNotificationForCurrentUser(NotificationRecord record) {
4224         final int currentUser;
4225         final long token = Binder.clearCallingIdentity();
4226         try {
4227             currentUser = ActivityManager.getCurrentUser();
4228         } finally {
4229             Binder.restoreCallingIdentity(token);
4230         }
4231         return (record.getUserId() == UserHandle.USER_ALL ||
4232                 record.getUserId() == currentUser ||
4233                 mUserProfiles.isCurrentProfile(record.getUserId()));
4234     }
4235
4236     protected void playInCallNotification() {
4237         new Thread() {
4238             @Override
4239             public void run() {
4240                 final long identity = Binder.clearCallingIdentity();
4241                 try {
4242                     final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4243                     if (player != null) {
4244                         player.play(new Binder(), mInCallNotificationUri,
4245                                 mInCallNotificationAudioAttributes,
4246                                 mInCallNotificationVolume, false);
4247                     }
4248                 } catch (RemoteException e) {
4249                 } finally {
4250                     Binder.restoreCallingIdentity(identity);
4251                 }
4252             }
4253         }.start();
4254     }
4255
4256     @GuardedBy("mToastQueue")
4257     void showNextToastLocked() {
4258         ToastRecord record = mToastQueue.get(0);
4259         while (record != null) {
4260             if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
4261             try {
4262                 record.callback.show(record.token);
4263                 scheduleTimeoutLocked(record);
4264                 return;
4265             } catch (RemoteException e) {
4266                 Slog.w(TAG, "Object died trying to show notification " + record.callback
4267                         + " in package " + record.pkg);
4268                 // remove it from the list and let the process die
4269                 int index = mToastQueue.indexOf(record);
4270                 if (index >= 0) {
4271                     mToastQueue.remove(index);
4272                 }
4273                 keepProcessAliveIfNeededLocked(record.pid);
4274                 if (mToastQueue.size() > 0) {
4275                     record = mToastQueue.get(0);
4276                 } else {
4277                     record = null;
4278                 }
4279             }
4280         }
4281     }
4282
4283     @GuardedBy("mToastQueue")
4284     void cancelToastLocked(int index) {
4285         ToastRecord record = mToastQueue.get(index);
4286         try {
4287             record.callback.hide();
4288         } catch (RemoteException e) {
4289             Slog.w(TAG, "Object died trying to hide notification " + record.callback
4290                     + " in package " + record.pkg);
4291             // don't worry about this, we're about to remove it from
4292             // the list anyway
4293         }
4294
4295         ToastRecord lastToast = mToastQueue.remove(index);
4296         mWindowManagerInternal.removeWindowToken(lastToast.token, true, DEFAULT_DISPLAY);
4297
4298         keepProcessAliveIfNeededLocked(record.pid);
4299         if (mToastQueue.size() > 0) {
4300             // Show the next one. If the callback fails, this will remove
4301             // it from the list, so don't assume that the list hasn't changed
4302             // after this point.
4303             showNextToastLocked();
4304         }
4305     }
4306
4307     @GuardedBy("mToastQueue")
4308     private void scheduleTimeoutLocked(ToastRecord r)
4309     {
4310         mHandler.removeCallbacksAndMessages(r);
4311         Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
4312         long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
4313         mHandler.sendMessageDelayed(m, delay);
4314     }
4315
4316     private void handleTimeout(ToastRecord record)
4317     {
4318         if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
4319         synchronized (mToastQueue) {
4320             int index = indexOfToastLocked(record.pkg, record.callback);
4321             if (index >= 0) {
4322                 cancelToastLocked(index);
4323             }
4324         }
4325     }
4326
4327     @GuardedBy("mToastQueue")
4328     int indexOfToastLocked(String pkg, ITransientNotification callback)
4329     {
4330         IBinder cbak = callback.asBinder();
4331         ArrayList<ToastRecord> list = mToastQueue;
4332         int len = list.size();
4333         for (int i=0; i<len; i++) {
4334             ToastRecord r = list.get(i);
4335             if (r.pkg.equals(pkg) && r.callback.asBinder().equals(cbak)) {
4336                 return i;
4337             }
4338         }
4339         return -1;
4340     }
4341
4342     @GuardedBy("mToastQueue")
4343     int indexOfToastPackageLocked(String pkg)
4344     {
4345         ArrayList<ToastRecord> list = mToastQueue;
4346         int len = list.size();
4347         for (int i=0; i<len; i++) {
4348             ToastRecord r = list.get(i);
4349             if (r.pkg.equals(pkg)) {
4350                 return i;
4351             }
4352         }
4353         return -1;
4354     }
4355
4356     @GuardedBy("mToastQueue")
4357     void keepProcessAliveIfNeededLocked(int pid)
4358     {
4359         int toastCount = 0; // toasts from this pid
4360         ArrayList<ToastRecord> list = mToastQueue;
4361         int N = list.size();
4362         for (int i=0; i<N; i++) {
4363             ToastRecord r = list.get(i);
4364             if (r.pid == pid) {
4365                 toastCount++;
4366             }
4367         }
4368         try {
4369             mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
4370         } catch (RemoteException e) {
4371             // Shouldn't happen.
4372         }
4373     }
4374
4375     private void handleRankingReconsideration(Message message) {
4376         if (!(message.obj instanceof RankingReconsideration)) return;
4377         RankingReconsideration recon = (RankingReconsideration) message.obj;
4378         recon.run();
4379         boolean changed;
4380         synchronized (mNotificationLock) {
4381             final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
4382             if (record == null) {
4383                 return;
4384             }
4385             int indexBefore = findNotificationRecordIndexLocked(record);
4386             boolean interceptBefore = record.isIntercepted();
4387             float contactAffinityBefore = record.getContactAffinity();
4388             int visibilityBefore = record.getPackageVisibilityOverride();
4389             recon.applyChangesLocked(record);
4390             applyZenModeLocked(record);
4391             mRankingHelper.sort(mNotificationList);
4392             int indexAfter = findNotificationRecordIndexLocked(record);
4393             boolean interceptAfter = record.isIntercepted();
4394             float contactAffinityAfter = record.getContactAffinity();
4395             int visibilityAfter = record.getPackageVisibilityOverride();
4396             changed = indexBefore != indexAfter || interceptBefore != interceptAfter
4397                     || visibilityBefore != visibilityAfter;
4398             if (interceptBefore && !interceptAfter
4399                     && Float.compare(contactAffinityBefore, contactAffinityAfter) != 0) {
4400                 buzzBeepBlinkLocked(record);
4401             }
4402         }
4403         if (changed) {
4404             mHandler.scheduleSendRankingUpdate();
4405         }
4406     }
4407
4408     void handleRankingSort() {
4409         if (mRankingHelper == null) return;
4410         synchronized (mNotificationLock) {
4411             final int N = mNotificationList.size();
4412             // Any field that can change via one of the extractors needs to be added here.
4413             ArrayList<String> orderBefore = new ArrayList<>(N);
4414             int[] visibilities = new int[N];
4415             boolean[] showBadges = new boolean[N];
4416             ArrayList<NotificationChannel> channelBefore = new ArrayList<>(N);
4417             ArrayList<String> groupKeyBefore = new ArrayList<>(N);
4418             ArrayList<ArrayList<String>> overridePeopleBefore = new ArrayList<>(N);
4419             ArrayList<ArrayList<SnoozeCriterion>> snoozeCriteriaBefore = new ArrayList<>(N);
4420             for (int i = 0; i < N; i++) {
4421                 final NotificationRecord r = mNotificationList.get(i);
4422                 orderBefore.add(r.getKey());
4423                 visibilities[i] = r.getPackageVisibilityOverride();
4424                 showBadges[i] = r.canShowBadge();
4425                 channelBefore.add(r.getChannel());
4426                 groupKeyBefore.add(r.getGroupKey());
4427                 overridePeopleBefore.add(r.getPeopleOverride());
4428                 snoozeCriteriaBefore.add(r.getSnoozeCriteria());
4429                 mRankingHelper.extractSignals(r);
4430             }
4431             mRankingHelper.sort(mNotificationList);
4432             for (int i = 0; i < N; i++) {
4433                 final NotificationRecord r = mNotificationList.get(i);
4434                 if (!orderBefore.get(i).equals(r.getKey())
4435                         || visibilities[i] != r.getPackageVisibilityOverride()
4436                         || showBadges[i] != r.canShowBadge()
4437                         || !Objects.equals(channelBefore.get(i), r.getChannel())
4438                         || !Objects.equals(groupKeyBefore.get(i), r.getGroupKey())
4439                         || !Objects.equals(overridePeopleBefore.get(i), r.getPeopleOverride())
4440                         || !Objects.equals(snoozeCriteriaBefore.get(i), r.getSnoozeCriteria())) {
4441                     mHandler.scheduleSendRankingUpdate();
4442                     return;
4443                 }
4444             }
4445         }
4446     }
4447
4448     @GuardedBy("mNotificationLock")
4449     private void recordCallerLocked(NotificationRecord record) {
4450         if (mZenModeHelper.isCall(record)) {
4451             mZenModeHelper.recordCaller(record);
4452         }
4453     }
4454
4455     // let zen mode evaluate this record
4456     @GuardedBy("mNotificationLock")
4457     private void applyZenModeLocked(NotificationRecord record) {
4458         record.setIntercepted(mZenModeHelper.shouldIntercept(record));
4459         if (record.isIntercepted()) {
4460             int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
4461                     ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
4462                     | (mZenModeHelper.shouldSuppressWhenScreenOn()
4463                     ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
4464             record.setSuppressedVisualEffects(suppressed);
4465         } else {
4466             record.setSuppressedVisualEffects(0);
4467         }
4468     }
4469
4470     @GuardedBy("mNotificationLock")
4471     private int findNotificationRecordIndexLocked(NotificationRecord target) {
4472         return mRankingHelper.indexOf(mNotificationList, target);
4473     }
4474
4475     private void handleSendRankingUpdate() {
4476         synchronized (mNotificationLock) {
4477             mListeners.notifyRankingUpdateLocked();
4478         }
4479     }
4480
4481     private void scheduleListenerHintsChanged(int state) {
4482         mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
4483         mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
4484     }
4485
4486     private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
4487         mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
4488         mHandler.obtainMessage(
4489                 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
4490                 listenerInterruptionFilter,
4491                 0).sendToTarget();
4492     }
4493
4494     private void handleListenerHintsChanged(int hints) {
4495         synchronized (mNotificationLock) {
4496             mListeners.notifyListenerHintsChangedLocked(hints);
4497         }
4498     }
4499
4500     private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
4501         synchronized (mNotificationLock) {
4502             mListeners.notifyInterruptionFilterChanged(interruptionFilter);
4503         }
4504     }
4505
4506     protected class WorkerHandler extends Handler
4507     {
4508         public WorkerHandler(Looper looper) {
4509             super(looper);
4510         }
4511
4512         @Override
4513         public void handleMessage(Message msg)
4514         {
4515             switch (msg.what)
4516             {
4517                 case MESSAGE_TIMEOUT:
4518                     handleTimeout((ToastRecord)msg.obj);
4519                     break;
4520                 case MESSAGE_SAVE_POLICY_FILE:
4521                     handleSavePolicyFile();
4522                     break;
4523                 case MESSAGE_SEND_RANKING_UPDATE:
4524                     handleSendRankingUpdate();
4525                     break;
4526                 case MESSAGE_LISTENER_HINTS_CHANGED:
4527                     handleListenerHintsChanged(msg.arg1);
4528                     break;
4529                 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
4530                     handleListenerInterruptionFilterChanged(msg.arg1);
4531                     break;
4532             }
4533         }
4534
4535         protected void scheduleSendRankingUpdate() {
4536             if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
4537                 Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE);
4538                 sendMessage(m);
4539             }
4540         }
4541
4542     }
4543
4544     private final class RankingHandlerWorker extends Handler implements RankingHandler
4545     {
4546         public RankingHandlerWorker(Looper looper) {
4547             super(looper);
4548         }
4549
4550         @Override
4551         public void handleMessage(Message msg) {
4552             switch (msg.what) {
4553                 case MESSAGE_RECONSIDER_RANKING:
4554                     handleRankingReconsideration(msg);
4555                     break;
4556                 case MESSAGE_RANKING_SORT:
4557                     handleRankingSort();
4558                     break;
4559             }
4560         }
4561
4562         public void requestSort() {
4563             removeMessages(MESSAGE_RANKING_SORT);
4564             Message msg = Message.obtain();
4565             msg.what = MESSAGE_RANKING_SORT;
4566             sendMessage(msg);
4567         }
4568
4569         public void requestReconsideration(RankingReconsideration recon) {
4570             Message m = Message.obtain(this,
4571                     NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
4572             long delay = recon.getDelay(TimeUnit.MILLISECONDS);
4573             sendMessageDelayed(m, delay);
4574         }
4575     }
4576
4577     // Notifications
4578     // ============================================================================
4579     static int clamp(int x, int low, int high) {
4580         return (x < low) ? low : ((x > high) ? high : x);
4581     }
4582
4583     void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
4584         if (!mAccessibilityManager.isEnabled()) {
4585             return;
4586         }
4587
4588         AccessibilityEvent event =
4589             AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
4590         event.setPackageName(packageName);
4591         event.setClassName(Notification.class.getName());
4592         event.setParcelableData(notification);
4593         CharSequence tickerText = notification.tickerText;
4594         if (!TextUtils.isEmpty(tickerText)) {
4595             event.getText().add(tickerText);
4596         }
4597
4598         mAccessibilityManager.sendAccessibilityEvent(event);
4599     }
4600
4601     /**
4602      * Removes all NotificationsRecords with the same key as the given notification record
4603      * from both lists. Do not call this method while iterating over either list.
4604      */
4605     @GuardedBy("mNotificationLock")
4606     private boolean removeFromNotificationListsLocked(NotificationRecord r) {
4607         // Remove from both lists, either list could have a separate Record for what is
4608         // effectively the same notification.
4609         boolean wasPosted = false;
4610         NotificationRecord recordInList = null;
4611         if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))
4612                 != null) {
4613             mNotificationList.remove(recordInList);
4614             mNotificationsByKey.remove(recordInList.sbn.getKey());
4615             wasPosted = true;
4616         }
4617         while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
4618                 != null) {
4619             mEnqueuedNotifications.remove(recordInList);
4620         }
4621         return wasPosted;
4622     }
4623
4624     @GuardedBy("mNotificationLock")
4625     private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
4626             boolean wasPosted, String listenerName) {
4627         final String canceledKey = r.getKey();
4628
4629         // Record caller.
4630         recordCallerLocked(r);
4631
4632         // tell the app
4633         if (sendDelete) {
4634             if (r.getNotification().deleteIntent != null) {
4635                 try {
4636                     r.getNotification().deleteIntent.send();
4637                 } catch (PendingIntent.CanceledException ex) {
4638                     // do nothing - there's no relevant way to recover, and
4639                     //     no reason to let this propagate
4640                     Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
4641                 }
4642             }
4643         }
4644
4645         // Only cancel these if this notification actually got to be posted.
4646         if (wasPosted) {
4647             // status bar
4648             if (r.getNotification().getSmallIcon() != null) {
4649                 if (reason != REASON_SNOOZED) {
4650                     r.isCanceled = true;
4651                 }
4652                 mListeners.notifyRemovedLocked(r.sbn, reason);
4653                 mHandler.post(new Runnable() {
4654                     @Override
4655                     public void run() {
4656                         mGroupHelper.onNotificationRemoved(r.sbn);
4657                     }
4658                 });
4659             }
4660
4661             // sound
4662             if (canceledKey.equals(mSoundNotificationKey)) {
4663                 mSoundNotificationKey = null;
4664                 final long identity = Binder.clearCallingIdentity();
4665                 try {
4666                     final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4667                     if (player != null) {
4668                         player.stopAsync();
4669                     }
4670                 } catch (RemoteException e) {
4671                 } finally {
4672                     Binder.restoreCallingIdentity(identity);
4673                 }
4674             }
4675
4676             // vibrate
4677             if (canceledKey.equals(mVibrateNotificationKey)) {
4678                 mVibrateNotificationKey = null;
4679                 long identity = Binder.clearCallingIdentity();
4680                 try {
4681                     mVibrator.cancel();
4682                 }
4683                 finally {
4684                     Binder.restoreCallingIdentity(identity);
4685                 }
4686             }
4687
4688             // light
4689             mLights.remove(canceledKey);
4690         }
4691
4692         // Record usage stats
4693         // TODO: add unbundling stats?
4694         switch (reason) {
4695             case REASON_CANCEL:
4696             case REASON_CANCEL_ALL:
4697             case REASON_LISTENER_CANCEL:
4698             case REASON_LISTENER_CANCEL_ALL:
4699                 mUsageStats.registerDismissedByUser(r);
4700                 break;
4701             case REASON_APP_CANCEL:
4702             case REASON_APP_CANCEL_ALL:
4703                 mUsageStats.registerRemovedByApp(r);
4704                 break;
4705         }
4706
4707         String groupKey = r.getGroupKey();
4708         NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
4709         if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
4710             mSummaryByGroupKey.remove(groupKey);
4711         }
4712         final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
4713         if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
4714             summaries.remove(r.sbn.getPackageName());
4715         }
4716
4717         // Save it for users of getHistoricalNotifications()
4718         mArchive.record(r.sbn);
4719
4720         final long now = System.currentTimeMillis();
4721         MetricsLogger.action(r.getLogMaker(now)
4722                 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
4723                 .setType(MetricsEvent.TYPE_DISMISS)
4724                 .setSubtype(reason));
4725         EventLogTags.writeNotificationCanceled(canceledKey, reason,
4726                 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), listenerName);
4727     }
4728
4729     /**
4730      * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
4731      * and none of the {@code mustNotHaveFlags}.
4732      */
4733     void cancelNotification(final int callingUid, final int callingPid,
4734             final String pkg, final String tag, final int id,
4735             final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
4736             final int userId, final int reason, final ManagedServiceInfo listener) {
4737         // In enqueueNotificationInternal notifications are added by scheduling the
4738         // work on the worker handler. Hence, we also schedule the cancel on this
4739         // handler to avoid a scenario where an add notification call followed by a
4740         // remove notification call ends up in not removing the notification.
4741         mHandler.post(new Runnable() {
4742             @Override
4743             public void run() {
4744                 String listenerName = listener == null ? null : listener.component.toShortString();
4745                 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
4746                         userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
4747
4748                 synchronized (mNotificationLock) {
4749                     // If the notification is currently enqueued, repost this runnable so it has a
4750                     // chance to notify listeners
4751                     if ((findNotificationByListLocked(
4752                             mEnqueuedNotifications, pkg, tag, id, userId)) != null) {
4753                         mHandler.post(this);
4754                     }
4755                     // Look for the notification in the posted list, since we already checked enq
4756                     NotificationRecord r = findNotificationByListLocked(
4757                             mNotificationList, pkg, tag, id, userId);
4758                     if (r != null) {
4759                         // The notification was found, check if it should be removed.
4760
4761                         // Ideally we'd do this in the caller of this method. However, that would
4762                         // require the caller to also find the notification.
4763                         if (reason == REASON_CLICK) {
4764                             mUsageStats.registerClickedByUser(r);
4765                         }
4766
4767                         if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
4768                             return;
4769                         }
4770                         if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
4771                             return;
4772                         }
4773
4774                         // Cancel the notification.
4775                         boolean wasPosted = removeFromNotificationListsLocked(r);
4776                         cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
4777                         cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
4778                                 sendDelete, null);
4779                         updateLightsLocked();
4780                     } else {
4781                         // No notification was found, assume that it is snoozed and cancel it.
4782                         if (reason != REASON_SNOOZED) {
4783                             final boolean wasSnoozed = mSnoozeHelper.cancel(userId, pkg, tag, id);
4784                             if (wasSnoozed) {
4785                                 savePolicyFile();
4786                             }
4787                         }
4788                     }
4789                 }
4790             }
4791         });
4792     }
4793
4794     /**
4795      * Determine whether the userId applies to the notification in question, either because
4796      * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
4797      */
4798     private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
4799         return
4800                 // looking for USER_ALL notifications? match everything
4801                    userId == UserHandle.USER_ALL
4802                 // a notification sent to USER_ALL matches any query
4803                 || r.getUserId() == UserHandle.USER_ALL
4804                 // an exact user match
4805                 || r.getUserId() == userId;
4806     }
4807
4808     /**
4809      * Determine whether the userId applies to the notification in question, either because
4810      * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
4811      * because it matches one of the users profiles.
4812      */
4813     private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
4814         return notificationMatchesUserId(r, userId)
4815                 || mUserProfiles.isCurrentProfile(r.getUserId());
4816     }
4817
4818     /**
4819      * Cancels all notifications from a given package that have all of the
4820      * {@code mustHaveFlags}.
4821      */
4822     void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
4823             int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
4824             ManagedServiceInfo listener) {
4825         mHandler.post(new Runnable() {
4826             @Override
4827             public void run() {
4828                 String listenerName = listener == null ? null : listener.component.toShortString();
4829                 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
4830                         pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
4831                         listenerName);
4832
4833                 // Why does this parameter exist? Do we actually want to execute the above if doit
4834                 // is false?
4835                 if (!doit) {
4836                     return;
4837                 }
4838
4839                 synchronized (mNotificationLock) {
4840                     FlagChecker flagChecker = (int flags) -> {
4841                         if ((flags & mustHaveFlags) != mustHaveFlags) {
4842                             return false;
4843                         }
4844                         if ((flags & mustNotHaveFlags) != 0) {
4845                             return false;
4846                         }
4847                         return true;
4848                     };
4849                     cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
4850                             pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
4851                             false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
4852                             listenerName, true /* wasPosted */);
4853                     cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
4854                             callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
4855                             flagChecker, false /*includeCurrentProfiles*/, userId,
4856                             false /*sendDelete*/, reason, listenerName, false /* wasPosted */);
4857                     mSnoozeHelper.cancel(userId, pkg);
4858                 }
4859             }
4860         });
4861     }
4862
4863     private interface FlagChecker {
4864         // Returns false if these flags do not pass the defined flag test.
4865         public boolean apply(int flags);
4866     }
4867
4868     @GuardedBy("mNotificationLock")
4869     private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
4870             int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
4871             String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
4872             boolean sendDelete, int reason, String listenerName, boolean wasPosted) {
4873         ArrayList<NotificationRecord> canceledNotifications = null;
4874         for (int i = notificationList.size() - 1; i >= 0; --i) {
4875             NotificationRecord r = notificationList.get(i);
4876             if (includeCurrentProfiles) {
4877                 if (!notificationMatchesCurrentProfiles(r, userId)) {
4878                     continue;
4879                 }
4880             } else if (!notificationMatchesUserId(r, userId)) {
4881                 continue;
4882             }
4883             // Don't remove notifications to all, if there's no package name specified
4884             if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
4885                 continue;
4886             }
4887             if (!flagChecker.apply(r.getFlags())) {
4888                 continue;
4889             }
4890             if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
4891                 continue;
4892             }
4893             if (channelId != null && !channelId.equals(r.getChannel().getId())) {
4894                 continue;
4895             }
4896             if (canceledNotifications == null) {
4897                 canceledNotifications = new ArrayList<>();
4898             }
4899             notificationList.remove(i);
4900             mNotificationsByKey.remove(r.getKey());
4901             canceledNotifications.add(r);
4902             cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
4903         }
4904         if (canceledNotifications != null) {
4905             final int M = canceledNotifications.size();
4906             for (int i = 0; i < M; i++) {
4907                 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
4908                         listenerName, false /* sendDelete */, flagChecker);
4909             }
4910             updateLightsLocked();
4911         }
4912     }
4913
4914     void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
4915             ManagedServiceInfo listener) {
4916         String listenerName = listener == null ? null : listener.component.toShortString();
4917         if (duration <= 0 && snoozeCriterionId == null || key == null) {
4918             return;
4919         }
4920
4921         if (DBG) {
4922             Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
4923                     snoozeCriterionId, listenerName));
4924         }
4925         // Needs to post so that it can cancel notifications not yet enqueued.
4926         mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
4927     }
4928
4929     void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
4930         String listenerName = listener == null ? null : listener.component.toShortString();
4931         if (DBG) {
4932             Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
4933         }
4934         mSnoozeHelper.repost(key);
4935         savePolicyFile();
4936     }
4937
4938     @GuardedBy("mNotificationLock")
4939     void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
4940             ManagedServiceInfo listener, boolean includeCurrentProfiles) {
4941         mHandler.post(new Runnable() {
4942             @Override
4943             public void run() {
4944                 synchronized (mNotificationLock) {
4945                     String listenerName =
4946                             listener == null ? null : listener.component.toShortString();
4947                     EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
4948                             null, userId, 0, 0, reason, listenerName);
4949
4950                     FlagChecker flagChecker = (int flags) -> {
4951                         if ((flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR))
4952                                 != 0) {
4953                             return false;
4954                         }
4955                         return true;
4956                     };
4957
4958                     cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
4959                             null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
4960                             includeCurrentProfiles, userId, true /*sendDelete*/, reason,
4961                             listenerName, true);
4962                     cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
4963                             callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
4964                             flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
4965                             reason, listenerName, false);
4966                     mSnoozeHelper.cancel(userId, includeCurrentProfiles);
4967                 }
4968             }
4969         });
4970     }
4971
4972     // Warning: The caller is responsible for invoking updateLightsLocked().
4973     @GuardedBy("mNotificationLock")
4974     private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
4975             String listenerName, boolean sendDelete, FlagChecker flagChecker) {
4976         Notification n = r.getNotification();
4977         if (!n.isGroupSummary()) {
4978             return;
4979         }
4980
4981         String pkg = r.sbn.getPackageName();
4982
4983         if (pkg == null) {
4984             if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
4985             return;
4986         }
4987
4988         cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
4989                 sendDelete, true, flagChecker);
4990         cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
4991                 listenerName, sendDelete, false, flagChecker);
4992     }
4993
4994     @GuardedBy("mNotificationLock")
4995     private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
4996             NotificationRecord parentNotification, int callingUid, int callingPid,
4997             String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker) {
4998         final String pkg = parentNotification.sbn.getPackageName();
4999         final int userId = parentNotification.getUserId();
5000         final int reason = REASON_GROUP_SUMMARY_CANCELED;
5001         for (int i = notificationList.size() - 1; i >= 0; i--) {
5002             final NotificationRecord childR = notificationList.get(i);
5003             final StatusBarNotification childSbn = childR.sbn;
5004             if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
5005                     childR.getGroupKey().equals(parentNotification.getGroupKey())
5006                     && (childR.getFlags() & Notification.FLAG_FOREGROUND_SERVICE) == 0
5007                     && (flagChecker == null || flagChecker.apply(childR.getFlags()))) {
5008                 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
5009                         childSbn.getTag(), userId, 0, 0, reason, listenerName);
5010                 notificationList.remove(i);
5011                 mNotificationsByKey.remove(childR.getKey());
5012                 cancelNotificationLocked(childR, sendDelete, reason, wasPosted, listenerName);
5013             }
5014         }
5015     }
5016
5017     @GuardedBy("mNotificationLock")
5018     void updateLightsLocked()
5019     {
5020         // handle notification lights
5021         NotificationRecord ledNotification = null;
5022         while (ledNotification == null && !mLights.isEmpty()) {
5023             final String owner = mLights.get(mLights.size() - 1);
5024             ledNotification = mNotificationsByKey.get(owner);
5025             if (ledNotification == null) {
5026                 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
5027                 mLights.remove(owner);
5028             }
5029         }
5030
5031         // Don't flash while we are in a call or screen is on
5032         if (ledNotification == null || mInCall || mScreenOn) {
5033             mNotificationLight.turnOff();
5034         } else {
5035             NotificationRecord.Light light = ledNotification.getLight();
5036             if (light != null && mNotificationPulseEnabled) {
5037                 // pulse repeatedly
5038                 mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
5039                         light.onMs, light.offMs);
5040             }
5041         }
5042     }
5043
5044     @GuardedBy("mNotificationLock")
5045     @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
5046             String groupKey, int userId) {
5047         List<NotificationRecord> records = new ArrayList<>();
5048         records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
5049         records.addAll(
5050                 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
5051         return records;
5052     }
5053
5054
5055     @GuardedBy("mNotificationLock")
5056     private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
5057             ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
5058         List<NotificationRecord> records = new ArrayList<>();
5059         final int len = list.size();
5060         for (int i = 0; i < len; i++) {
5061             NotificationRecord r = list.get(i);
5062             if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey)
5063                     && r.sbn.getPackageName().equals(pkg)) {
5064                 records.add(r);
5065             }
5066         }
5067         return records;
5068     }
5069
5070     // Searches both enqueued and posted notifications by key.
5071     // TODO: need to combine a bunch of these getters with slightly different behavior.
5072     // TODO: Should enqueuing just add to mNotificationsByKey instead?
5073     @GuardedBy("mNotificationLock")
5074     private NotificationRecord findNotificationByKeyLocked(String key) {
5075         NotificationRecord r;
5076         if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
5077             return r;
5078         }
5079         if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
5080             return r;
5081         }
5082         return null;
5083     }
5084
5085     @GuardedBy("mNotificationLock")
5086     NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
5087         NotificationRecord r;
5088         if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
5089             return r;
5090         }
5091         if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
5092                 != null) {
5093             return r;
5094         }
5095         return null;
5096     }
5097
5098     @GuardedBy("mNotificationLock")
5099     private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
5100             String pkg, String tag, int id, int userId) {
5101         final int len = list.size();
5102         for (int i = 0; i < len; i++) {
5103             NotificationRecord r = list.get(i);
5104             if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
5105                     TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
5106                 return r;
5107             }
5108         }
5109         return null;
5110     }
5111
5112     @GuardedBy("mNotificationLock")
5113     private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
5114             String key) {
5115         final int N = list.size();
5116         for (int i = 0; i < N; i++) {
5117             if (key.equals(list.get(i).getKey())) {
5118                 return list.get(i);
5119             }
5120         }
5121         return null;
5122     }
5123
5124     @GuardedBy("mNotificationLock")
5125     int indexOfNotificationLocked(String key) {
5126         final int N = mNotificationList.size();
5127         for (int i = 0; i < N; i++) {
5128             if (key.equals(mNotificationList.get(i).getKey())) {
5129                 return i;
5130             }
5131         }
5132         return -1;
5133     }
5134
5135     private void updateNotificationPulse() {
5136         synchronized (mNotificationLock) {
5137             updateLightsLocked();
5138         }
5139     }
5140
5141     protected boolean isCallingUidSystem() {
5142         final int uid = Binder.getCallingUid();
5143         return uid == Process.SYSTEM_UID;
5144     }
5145
5146     protected boolean isUidSystemOrPhone(int uid) {
5147         final int appid = UserHandle.getAppId(uid);
5148         return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
5149     }
5150
5151     // TODO: Most calls should probably move to isCallerSystem.
5152     protected boolean isCallerSystemOrPhone() {
5153         return isUidSystemOrPhone(Binder.getCallingUid());
5154     }
5155
5156     private void checkCallerIsSystemOrShell() {
5157         if (Binder.getCallingUid() == Process.SHELL_UID) {
5158             return;
5159         }
5160         checkCallerIsSystem();
5161     }
5162
5163     private void checkCallerIsSystem() {
5164         if (isCallerSystemOrPhone()) {
5165             return;
5166         }
5167         throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
5168     }
5169
5170     private void checkCallerIsSystemOrSameApp(String pkg) {
5171         if (isCallerSystemOrPhone()) {
5172             return;
5173         }
5174         checkCallerIsSameApp(pkg);
5175     }
5176
5177     private boolean isCallerInstantApp(String pkg) {
5178         // System is always allowed to act for ephemeral apps.
5179         if (isCallerSystemOrPhone()) {
5180             return false;
5181         }
5182
5183         mAppOps.checkPackage(Binder.getCallingUid(), pkg);
5184
5185         try {
5186             ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0,
5187                     UserHandle.getCallingUserId());
5188             if (ai == null) {
5189                 throw new SecurityException("Unknown package " + pkg);
5190             }
5191             return ai.isInstantApp();
5192         } catch (RemoteException re) {
5193             throw new SecurityException("Unknown package " + pkg, re);
5194         }
5195
5196     }
5197
5198     private void checkCallerIsSameApp(String pkg) {
5199         final int uid = Binder.getCallingUid();
5200         try {
5201             ApplicationInfo ai = mPackageManager.getApplicationInfo(
5202                     pkg, 0, UserHandle.getCallingUserId());
5203             if (ai == null) {
5204                 throw new SecurityException("Unknown package " + pkg);
5205             }
5206             if (!UserHandle.isSameApp(ai.uid, uid)) {
5207                 throw new SecurityException("Calling uid " + uid + " gave package "
5208                         + pkg + " which is owned by uid " + ai.uid);
5209             }
5210         } catch (RemoteException re) {
5211             throw new SecurityException("Unknown package " + pkg + "\n" + re);
5212         }
5213     }
5214
5215     private static String callStateToString(int state) {
5216         switch (state) {
5217             case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
5218             case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
5219             case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
5220             default: return "CALL_STATE_UNKNOWN_" + state;
5221         }
5222     }
5223
5224     private void listenForCallState() {
5225         TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
5226             @Override
5227             public void onCallStateChanged(int state, String incomingNumber) {
5228                 if (mCallState == state) return;
5229                 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
5230                 mCallState = state;
5231             }
5232         }, PhoneStateListener.LISTEN_CALL_STATE);
5233     }
5234
5235     /**
5236      * Generates a NotificationRankingUpdate from 'sbns', considering only
5237      * notifications visible to the given listener.
5238      */
5239     @GuardedBy("mNotificationLock")
5240     private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
5241         final int N = mNotificationList.size();
5242         ArrayList<String> keys = new ArrayList<String>(N);
5243         ArrayList<String> interceptedKeys = new ArrayList<String>(N);
5244         ArrayList<Integer> importance = new ArrayList<>(N);
5245         Bundle overrideGroupKeys = new Bundle();
5246         Bundle visibilityOverrides = new Bundle();
5247         Bundle suppressedVisualEffects = new Bundle();
5248         Bundle explanation = new Bundle();
5249         Bundle channels = new Bundle();
5250         Bundle overridePeople = new Bundle();
5251         Bundle snoozeCriteria = new Bundle();
5252         Bundle showBadge = new Bundle();
5253         for (int i = 0; i < N; i++) {
5254             NotificationRecord record = mNotificationList.get(i);
5255             if (!isVisibleToListener(record.sbn, info)) {
5256                 continue;
5257             }
5258             final String key = record.sbn.getKey();
5259             keys.add(key);
5260             importance.add(record.getImportance());
5261             if (record.getImportanceExplanation() != null) {
5262                 explanation.putCharSequence(key, record.getImportanceExplanation());
5263             }
5264             if (record.isIntercepted()) {
5265                 interceptedKeys.add(key);
5266
5267             }
5268             suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
5269             if (record.getPackageVisibilityOverride()
5270                     != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
5271                 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
5272             }
5273             overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
5274             channels.putParcelable(key, record.getChannel());
5275             overridePeople.putStringArrayList(key, record.getPeopleOverride());
5276             snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria());
5277             showBadge.putBoolean(key, record.canShowBadge());
5278         }
5279         final int M = keys.size();
5280         String[] keysAr = keys.toArray(new String[M]);
5281         String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
5282         int[] importanceAr = new int[M];
5283         for (int i = 0; i < M; i++) {
5284             importanceAr[i] = importance.get(i);
5285         }
5286         return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
5287                 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
5288                 channels, overridePeople, snoozeCriteria, showBadge);
5289     }
5290
5291     boolean hasCompanionDevice(ManagedServiceInfo info) {
5292         if (mCompanionManager == null) {
5293             mCompanionManager = getCompanionManager();
5294         }
5295         // Companion mgr doesn't exist on all device types
5296         if (mCompanionManager == null) {
5297             return false;
5298         }
5299         long identity = Binder.clearCallingIdentity();
5300         try {
5301             List<String> associations = mCompanionManager.getAssociations(
5302                     info.component.getPackageName(), info.userid);
5303             if (!ArrayUtils.isEmpty(associations)) {
5304                 return true;
5305             }
5306         } catch (SecurityException se) {
5307             // Not a privileged listener
5308         } catch (RemoteException re) {
5309             Slog.e(TAG, "Cannot reach companion device service", re);
5310         } catch (Exception e) {
5311             Slog.e(TAG, "Cannot verify listener " + info, e);
5312         } finally {
5313             Binder.restoreCallingIdentity(identity);
5314         }
5315         return false;
5316     }
5317
5318     protected ICompanionDeviceManager getCompanionManager() {
5319         return ICompanionDeviceManager.Stub.asInterface(
5320                 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
5321     }
5322
5323     private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
5324         if (!listener.enabledAndUserMatches(sbn.getUserId())) {
5325             return false;
5326         }
5327         // TODO: remove this for older listeners.
5328         return true;
5329     }
5330
5331     private boolean isPackageSuspendedForUser(String pkg, int uid) {
5332         int userId = UserHandle.getUserId(uid);
5333         try {
5334             return mPackageManager.isPackageSuspendedForUser(pkg, userId);
5335         } catch (RemoteException re) {
5336             throw new SecurityException("Could not talk to package manager service");
5337         } catch (IllegalArgumentException ex) {
5338             // Package not found.
5339             return false;
5340         }
5341     }
5342
5343     private class TrimCache {
5344         StatusBarNotification heavy;
5345         StatusBarNotification sbnClone;
5346         StatusBarNotification sbnCloneLight;
5347
5348         TrimCache(StatusBarNotification sbn) {
5349             heavy = sbn;
5350         }
5351
5352         StatusBarNotification ForListener(ManagedServiceInfo info) {
5353             if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
5354                 if (sbnCloneLight == null) {
5355                     sbnCloneLight = heavy.cloneLight();
5356                 }
5357                 return sbnCloneLight;
5358             } else {
5359                 if (sbnClone == null) {
5360                     sbnClone = heavy.clone();
5361                 }
5362                 return sbnClone;
5363             }
5364         }
5365     }
5366
5367     public class NotificationAssistants extends ManagedServices {
5368         static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
5369
5370         public NotificationAssistants(IPackageManager pm) {
5371             super(getContext(), mNotificationLock, mUserProfiles, pm);
5372         }
5373
5374         @Override
5375         protected Config getConfig() {
5376             Config c = new Config();
5377             c.caption = "notification assistant service";
5378             c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
5379             c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS;
5380             c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
5381             c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
5382             c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
5383             c.clientLabel = R.string.notification_ranker_binding_label;
5384             return c;
5385         }
5386
5387         @Override
5388         protected IInterface asInterface(IBinder binder) {
5389             return INotificationListener.Stub.asInterface(binder);
5390         }
5391
5392         @Override
5393         protected boolean checkType(IInterface service) {
5394             return service instanceof INotificationListener;
5395         }
5396
5397         @Override
5398         protected void onServiceAdded(ManagedServiceInfo info) {
5399             mListeners.registerGuestService(info);
5400         }
5401
5402         @Override
5403         @GuardedBy("mNotificationLock")
5404         protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
5405             mListeners.unregisterService(removed.service, removed.userid);
5406         }
5407
5408         public void onNotificationEnqueued(final NotificationRecord r) {
5409             final StatusBarNotification sbn = r.sbn;
5410             TrimCache trimCache = new TrimCache(sbn);
5411
5412             // There should be only one, but it's a list, so while we enforce
5413             // singularity elsewhere, we keep it general here, to avoid surprises.
5414             for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
5415                 boolean sbnVisible = isVisibleToListener(sbn, info);
5416                 if (!sbnVisible) {
5417                     continue;
5418                 }
5419
5420                 final int importance = r.getImportance();
5421                 final boolean fromUser = r.isImportanceFromUser();
5422                 final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
5423                 mHandler.post(new Runnable() {
5424                     @Override
5425                     public void run() {
5426                         notifyEnqueued(info, sbnToPost);
5427                     }
5428                 });
5429             }
5430         }
5431
5432         private void notifyEnqueued(final ManagedServiceInfo info,
5433                 final StatusBarNotification sbn) {
5434             final INotificationListener assistant = (INotificationListener) info.service;
5435             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5436             try {
5437                 assistant.onNotificationEnqueued(sbnHolder);
5438             } catch (RemoteException ex) {
5439                 Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
5440             }
5441         }
5442
5443         /**
5444          * asynchronously notify the assistant that a notification has been snoozed until a
5445          * context
5446          */
5447         @GuardedBy("mNotificationLock")
5448         public void notifyAssistantSnoozedLocked(final StatusBarNotification sbn,
5449                 final String snoozeCriterionId) {
5450             TrimCache trimCache = new TrimCache(sbn);
5451             for (final ManagedServiceInfo info : getServices()) {
5452                 final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
5453                 mHandler.post(new Runnable() {
5454                     @Override
5455                     public void run() {
5456                         final INotificationListener assistant =
5457                                 (INotificationListener) info.service;
5458                         StatusBarNotificationHolder sbnHolder
5459                                 = new StatusBarNotificationHolder(sbnToPost);
5460                         try {
5461                             assistant.onNotificationSnoozedUntilContext(
5462                                     sbnHolder, snoozeCriterionId);
5463                         } catch (RemoteException ex) {
5464                             Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
5465                         }
5466                     }
5467                 });
5468             }
5469         }
5470
5471         public boolean isEnabled() {
5472             return !getServices().isEmpty();
5473         }
5474     }
5475
5476     public class NotificationListeners extends ManagedServices {
5477         static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners";
5478
5479         private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
5480
5481         public NotificationListeners(IPackageManager pm) {
5482             super(getContext(), mNotificationLock, mUserProfiles, pm);
5483
5484         }
5485
5486         @Override
5487         protected Config getConfig() {
5488             Config c = new Config();
5489             c.caption = "notification listener";
5490             c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
5491             c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS;
5492             c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
5493             c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
5494             c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
5495             c.clientLabel = R.string.notification_listener_binding_label;
5496             return c;
5497         }
5498
5499         @Override
5500         protected IInterface asInterface(IBinder binder) {
5501             return INotificationListener.Stub.asInterface(binder);
5502         }
5503
5504         @Override
5505         protected boolean checkType(IInterface service) {
5506             return service instanceof INotificationListener;
5507         }
5508
5509         @Override
5510         public void onServiceAdded(ManagedServiceInfo info) {
5511             final INotificationListener listener = (INotificationListener) info.service;
5512             final NotificationRankingUpdate update;
5513             synchronized (mNotificationLock) {
5514                 update = makeRankingUpdateLocked(info);
5515             }
5516             try {
5517                 listener.onListenerConnected(update);
5518             } catch (RemoteException e) {
5519                 // we tried
5520             }
5521         }
5522
5523         @Override
5524         @GuardedBy("mNotificationLock")
5525         protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
5526             if (removeDisabledHints(removed)) {
5527                 updateListenerHintsLocked();
5528                 updateEffectsSuppressorLocked();
5529             }
5530             mLightTrimListeners.remove(removed);
5531         }
5532
5533         @GuardedBy("mNotificationLock")
5534         public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
5535             if (trim == TRIM_LIGHT) {
5536                 mLightTrimListeners.add(info);
5537             } else {
5538                 mLightTrimListeners.remove(info);
5539             }
5540         }
5541
5542         public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
5543             return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
5544         }
5545
5546         /**
5547          * asynchronously notify all listeners about a new notification
5548          *
5549          * <p>
5550          * Also takes care of removing a notification that has been visible to a listener before,
5551          * but isn't anymore.
5552          */
5553         @GuardedBy("mNotificationLock")
5554         public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
5555             // Lazily initialized snapshots of the notification.
5556             TrimCache trimCache = new TrimCache(sbn);
5557
5558             for (final ManagedServiceInfo info : getServices()) {
5559                 boolean sbnVisible = isVisibleToListener(sbn, info);
5560                 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
5561                 // This notification hasn't been and still isn't visible -> ignore.
5562                 if (!oldSbnVisible && !sbnVisible) {
5563                     continue;
5564                 }
5565                 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
5566
5567                 // This notification became invisible -> remove the old one.
5568                 if (oldSbnVisible && !sbnVisible) {
5569                     final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
5570                     mHandler.post(new Runnable() {
5571                         @Override
5572                         public void run() {
5573                             notifyRemoved(info, oldSbnLightClone, update, REASON_USER_STOPPED);
5574                         }
5575                     });
5576                     continue;
5577                 }
5578
5579                 final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
5580                 mHandler.post(new Runnable() {
5581                     @Override
5582                     public void run() {
5583                         notifyPosted(info, sbnToPost, update);
5584                     }
5585                 });
5586             }
5587         }
5588
5589         /**
5590          * asynchronously notify all listeners about a removed notification
5591          */
5592         @GuardedBy("mNotificationLock")
5593         public void notifyRemovedLocked(StatusBarNotification sbn, int reason) {
5594             // make a copy in case changes are made to the underlying Notification object
5595             // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
5596             // notification
5597             final StatusBarNotification sbnLight = sbn.cloneLight();
5598             for (final ManagedServiceInfo info : getServices()) {
5599                 if (!isVisibleToListener(sbn, info)) {
5600                     continue;
5601                 }
5602                 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
5603                 mHandler.post(new Runnable() {
5604                     @Override
5605                     public void run() {
5606                         notifyRemoved(info, sbnLight, update, reason);
5607                     }
5608                 });
5609             }
5610         }
5611
5612         /**
5613          * asynchronously notify all listeners about a reordering of notifications
5614          */
5615         @GuardedBy("mNotificationLock")
5616         public void notifyRankingUpdateLocked() {
5617             for (final ManagedServiceInfo serviceInfo : getServices()) {
5618                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5619                     continue;
5620                 }
5621                 final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
5622                 mHandler.post(new Runnable() {
5623                     @Override
5624                     public void run() {
5625                         notifyRankingUpdate(serviceInfo, update);
5626                     }
5627                 });
5628             }
5629         }
5630
5631         @GuardedBy("mNotificationLock")
5632         public void notifyListenerHintsChangedLocked(final int hints) {
5633             for (final ManagedServiceInfo serviceInfo : getServices()) {
5634                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5635                     continue;
5636                 }
5637                 mHandler.post(new Runnable() {
5638                     @Override
5639                     public void run() {
5640                         notifyListenerHintsChanged(serviceInfo, hints);
5641                     }
5642                 });
5643             }
5644         }
5645
5646         public void notifyInterruptionFilterChanged(final int interruptionFilter) {
5647             for (final ManagedServiceInfo serviceInfo : getServices()) {
5648                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5649                     continue;
5650                 }
5651                 mHandler.post(new Runnable() {
5652                     @Override
5653                     public void run() {
5654                         notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
5655                     }
5656                 });
5657             }
5658         }
5659
5660         protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user,
5661                 final NotificationChannel channel, final int modificationType) {
5662             if (channel == null) {
5663                 return;
5664             }
5665             for (final ManagedServiceInfo serviceInfo : getServices()) {
5666                 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
5667                     continue;
5668                 }
5669
5670                 BackgroundThread.getHandler().post(() -> {
5671                     if (hasCompanionDevice(serviceInfo)) {
5672                         notifyNotificationChannelChanged(
5673                                 serviceInfo, pkg, user, channel, modificationType);
5674                     }
5675                 });
5676             }
5677         }
5678
5679         protected void notifyNotificationChannelGroupChanged(
5680                 final String pkg, final UserHandle user, final NotificationChannelGroup group,
5681                 final int modificationType) {
5682             if (group == null) {
5683                 return;
5684             }
5685             for (final ManagedServiceInfo serviceInfo : getServices()) {
5686                 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
5687                     continue;
5688                 }
5689
5690                 BackgroundThread.getHandler().post(() -> {
5691                     if (hasCompanionDevice(serviceInfo)) {
5692                         notifyNotificationChannelGroupChanged(
5693                                 serviceInfo, pkg, user, group, modificationType);
5694                     }
5695                 });
5696             }
5697         }
5698
5699         private void notifyPosted(final ManagedServiceInfo info,
5700                 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
5701             final INotificationListener listener = (INotificationListener) info.service;
5702             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5703             try {
5704                 listener.onNotificationPosted(sbnHolder, rankingUpdate);
5705             } catch (RemoteException ex) {
5706                 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
5707             }
5708         }
5709
5710         private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
5711                 NotificationRankingUpdate rankingUpdate, int reason) {
5712             if (!info.enabledAndUserMatches(sbn.getUserId())) {
5713                 return;
5714             }
5715             final INotificationListener listener = (INotificationListener) info.service;
5716             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5717             try {
5718                 listener.onNotificationRemoved(sbnHolder, rankingUpdate, reason);
5719             } catch (RemoteException ex) {
5720                 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
5721             }
5722         }
5723
5724         private void notifyRankingUpdate(ManagedServiceInfo info,
5725                                          NotificationRankingUpdate rankingUpdate) {
5726             final INotificationListener listener = (INotificationListener) info.service;
5727             try {
5728                 listener.onNotificationRankingUpdate(rankingUpdate);
5729             } catch (RemoteException ex) {
5730                 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
5731             }
5732         }
5733
5734         private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
5735             final INotificationListener listener = (INotificationListener) info.service;
5736             try {
5737                 listener.onListenerHintsChanged(hints);
5738             } catch (RemoteException ex) {
5739                 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
5740             }
5741         }
5742
5743         private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
5744                 int interruptionFilter) {
5745             final INotificationListener listener = (INotificationListener) info.service;
5746             try {
5747                 listener.onInterruptionFilterChanged(interruptionFilter);
5748             } catch (RemoteException ex) {
5749                 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
5750             }
5751         }
5752
5753         void notifyNotificationChannelChanged(ManagedServiceInfo info,
5754                 final String pkg, final UserHandle user, final NotificationChannel channel,
5755                 final int modificationType) {
5756             final INotificationListener listener = (INotificationListener) info.service;
5757             try {
5758                 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
5759             } catch (RemoteException ex) {
5760                 Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
5761             }
5762         }
5763
5764         private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
5765                 final String pkg, final UserHandle user, final NotificationChannelGroup group,
5766                 final int modificationType) {
5767             final INotificationListener listener = (INotificationListener) info.service;
5768             try {
5769                 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
5770             } catch (RemoteException ex) {
5771                 Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
5772             }
5773         }
5774
5775         public boolean isListenerPackage(String packageName) {
5776             if (packageName == null) {
5777                 return false;
5778             }
5779             // TODO: clean up locking object later
5780             synchronized (mNotificationLock) {
5781                 for (final ManagedServiceInfo serviceInfo : getServices()) {
5782                     if (packageName.equals(serviceInfo.component.getPackageName())) {
5783                         return true;
5784                     }
5785                 }
5786             }
5787             return false;
5788         }
5789     }
5790
5791     public static final class DumpFilter {
5792         public boolean filtered = false;
5793         public String pkgFilter;
5794         public boolean zen;
5795         public long since;
5796         public boolean stats;
5797         public boolean redact = true;
5798         public boolean proto = false;
5799
5800         public static DumpFilter parseFromArguments(String[] args) {
5801             final DumpFilter filter = new DumpFilter();
5802             for (int ai = 0; ai < args.length; ai++) {
5803                 final String a = args[ai];
5804                 if ("--proto".equals(args[0])) {
5805                     filter.proto = true;
5806                 }
5807                 if ("--noredact".equals(a) || "--reveal".equals(a)) {
5808                     filter.redact = false;
5809                 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
5810                     if (ai < args.length-1) {
5811                         ai++;
5812                         filter.pkgFilter = args[ai].trim().toLowerCase();
5813                         if (filter.pkgFilter.isEmpty()) {
5814                             filter.pkgFilter = null;
5815                         } else {
5816                             filter.filtered = true;
5817                         }
5818                     }
5819                 } else if ("--zen".equals(a) || "zen".equals(a)) {
5820                     filter.filtered = true;
5821                     filter.zen = true;
5822                 } else if ("--stats".equals(a)) {
5823                     filter.stats = true;
5824                     if (ai < args.length-1) {
5825                         ai++;
5826                         filter.since = Long.parseLong(args[ai]);
5827                     } else {
5828                         filter.since = 0;
5829                     }
5830                 }
5831             }
5832             return filter;
5833         }
5834
5835         public boolean matches(StatusBarNotification sbn) {
5836             if (!filtered) return true;
5837             return zen ? true : sbn != null
5838                     && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
5839         }
5840
5841         public boolean matches(ComponentName component) {
5842             if (!filtered) return true;
5843             return zen ? true : component != null && matches(component.getPackageName());
5844         }
5845
5846         public boolean matches(String pkg) {
5847             if (!filtered) return true;
5848             return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
5849         }
5850
5851         @Override
5852         public String toString() {
5853             return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
5854         }
5855     }
5856
5857     /**
5858      * Wrapper for a StatusBarNotification object that allows transfer across a oneway
5859      * binder without sending large amounts of data over a oneway transaction.
5860      */
5861     private static final class StatusBarNotificationHolder
5862             extends IStatusBarNotificationHolder.Stub {
5863         private StatusBarNotification mValue;
5864
5865         public StatusBarNotificationHolder(StatusBarNotification value) {
5866             mValue = value;
5867         }
5868
5869         /** Get the held value and clear it. This function should only be called once per holder */
5870         @Override
5871         public StatusBarNotification get() {
5872             StatusBarNotification value = mValue;
5873             mValue = null;
5874             return value;
5875         }
5876     }
5877
5878     private class ShellCmd extends ShellCommand {
5879         public static final String USAGE = "help\n"
5880                 + "allow_listener COMPONENT [user_id]\n"
5881                 + "disallow_listener COMPONENT [user_id]\n"
5882                 + "set_assistant COMPONENT\n"
5883                 + "remove_assistant COMPONENT\n"
5884                 + "allow_dnd PACKAGE\n"
5885                 + "disallow_dnd PACKAGE";
5886
5887         @Override
5888         public int onCommand(String cmd) {
5889             if (cmd == null) {
5890                 return handleDefaultCommands(cmd);
5891             }
5892             final PrintWriter pw = getOutPrintWriter();
5893             try {
5894                 switch (cmd) {
5895                     case "allow_dnd": {
5896                         getBinderService().setNotificationPolicyAccessGranted(
5897                                 getNextArgRequired(), true);
5898                     }
5899                     break;
5900
5901                     case "disallow_dnd": {
5902                         getBinderService().setNotificationPolicyAccessGranted(
5903                                 getNextArgRequired(), false);
5904                     }
5905                     break;
5906                     case "allow_listener": {
5907                         ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
5908                         if (cn == null) {
5909                             pw.println("Invalid listener - must be a ComponentName");
5910                             return -1;
5911                         }
5912                         String userId = getNextArg();
5913                         if (userId == null) {
5914                             getBinderService().setNotificationListenerAccessGranted(cn, true);
5915                         } else {
5916                             getBinderService().setNotificationListenerAccessGrantedForUser(
5917                                     cn, Integer.parseInt(userId), true);
5918                         }
5919                     }
5920                     break;
5921                     case "disallow_listener": {
5922                         ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
5923                         if (cn == null) {
5924                             pw.println("Invalid listener - must be a ComponentName");
5925                             return -1;
5926                         }
5927                         String userId = getNextArg();
5928                         if (userId == null) {
5929                             getBinderService().setNotificationListenerAccessGranted(cn, false);
5930                         } else {
5931                             getBinderService().setNotificationListenerAccessGrantedForUser(
5932                                     cn, Integer.parseInt(userId), false);
5933                         }
5934                     }
5935                     break;
5936                     case "allow_assistant": {
5937                         ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
5938                         if (cn == null) {
5939                             pw.println("Invalid assistant - must be a ComponentName");
5940                             return -1;
5941                         }
5942                         getBinderService().setNotificationAssistantAccessGranted(cn, true);
5943                     }
5944                     break;
5945                     case "disallow_assistant": {
5946                         ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
5947                         if (cn == null) {
5948                             pw.println("Invalid assistant - must be a ComponentName");
5949                             return -1;
5950                         }
5951                         getBinderService().setNotificationAssistantAccessGranted(cn, false);
5952                     }
5953                     break;
5954
5955                     default:
5956                         return handleDefaultCommands(cmd);
5957                 }
5958             } catch (Exception e) {
5959                 pw.println("Error occurred. Check logcat for details. " + e.getMessage());
5960                 Slog.e(TAG, "Error running shell command", e);
5961             }
5962             return 0;
5963         }
5964
5965         @Override
5966         public void onHelp() {
5967             getOutPrintWriter().println(USAGE);
5968         }
5969     }
5970 }