OSDN Git Service

Merge "Fix Layout.primaryIsTrailingPreviousAllLineOffsets" into oc-dev am: 8abe600b81
[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                     // Look for the notification, searching both the posted and enqueued lists.
4750                     NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
4751                     if (r != null) {
4752                         // The notification was found, check if it should be removed.
4753
4754                         // Ideally we'd do this in the caller of this method. However, that would
4755                         // require the caller to also find the notification.
4756                         if (reason == REASON_CLICK) {
4757                             mUsageStats.registerClickedByUser(r);
4758                         }
4759
4760                         if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
4761                             return;
4762                         }
4763                         if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
4764                             return;
4765                         }
4766
4767                         // Cancel the notification.
4768                         boolean wasPosted = removeFromNotificationListsLocked(r);
4769                         cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
4770                         cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
4771                                 sendDelete, null);
4772                         updateLightsLocked();
4773                     } else {
4774                         // No notification was found, assume that it is snoozed and cancel it.
4775                         if (reason != REASON_SNOOZED) {
4776                             final boolean wasSnoozed = mSnoozeHelper.cancel(userId, pkg, tag, id);
4777                             if (wasSnoozed) {
4778                                 savePolicyFile();
4779                             }
4780                         }
4781                     }
4782                 }
4783             }
4784         });
4785     }
4786
4787     /**
4788      * Determine whether the userId applies to the notification in question, either because
4789      * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
4790      */
4791     private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
4792         return
4793                 // looking for USER_ALL notifications? match everything
4794                    userId == UserHandle.USER_ALL
4795                 // a notification sent to USER_ALL matches any query
4796                 || r.getUserId() == UserHandle.USER_ALL
4797                 // an exact user match
4798                 || r.getUserId() == userId;
4799     }
4800
4801     /**
4802      * Determine whether the userId applies to the notification in question, either because
4803      * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
4804      * because it matches one of the users profiles.
4805      */
4806     private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
4807         return notificationMatchesUserId(r, userId)
4808                 || mUserProfiles.isCurrentProfile(r.getUserId());
4809     }
4810
4811     /**
4812      * Cancels all notifications from a given package that have all of the
4813      * {@code mustHaveFlags}.
4814      */
4815     void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
4816             int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
4817             ManagedServiceInfo listener) {
4818         mHandler.post(new Runnable() {
4819             @Override
4820             public void run() {
4821                 String listenerName = listener == null ? null : listener.component.toShortString();
4822                 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
4823                         pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
4824                         listenerName);
4825
4826                 // Why does this parameter exist? Do we actually want to execute the above if doit
4827                 // is false?
4828                 if (!doit) {
4829                     return;
4830                 }
4831
4832                 synchronized (mNotificationLock) {
4833                     FlagChecker flagChecker = (int flags) -> {
4834                         if ((flags & mustHaveFlags) != mustHaveFlags) {
4835                             return false;
4836                         }
4837                         if ((flags & mustNotHaveFlags) != 0) {
4838                             return false;
4839                         }
4840                         return true;
4841                     };
4842                     cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
4843                             pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
4844                             false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
4845                             listenerName, true /* wasPosted */);
4846                     cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
4847                             callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
4848                             flagChecker, false /*includeCurrentProfiles*/, userId,
4849                             false /*sendDelete*/, reason, listenerName, false /* wasPosted */);
4850                     mSnoozeHelper.cancel(userId, pkg);
4851                 }
4852             }
4853         });
4854     }
4855
4856     private interface FlagChecker {
4857         // Returns false if these flags do not pass the defined flag test.
4858         public boolean apply(int flags);
4859     }
4860
4861     @GuardedBy("mNotificationLock")
4862     private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
4863             int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
4864             String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
4865             boolean sendDelete, int reason, String listenerName, boolean wasPosted) {
4866         ArrayList<NotificationRecord> canceledNotifications = null;
4867         for (int i = notificationList.size() - 1; i >= 0; --i) {
4868             NotificationRecord r = notificationList.get(i);
4869             if (includeCurrentProfiles) {
4870                 if (!notificationMatchesCurrentProfiles(r, userId)) {
4871                     continue;
4872                 }
4873             } else if (!notificationMatchesUserId(r, userId)) {
4874                 continue;
4875             }
4876             // Don't remove notifications to all, if there's no package name specified
4877             if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
4878                 continue;
4879             }
4880             if (!flagChecker.apply(r.getFlags())) {
4881                 continue;
4882             }
4883             if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
4884                 continue;
4885             }
4886             if (channelId != null && !channelId.equals(r.getChannel().getId())) {
4887                 continue;
4888             }
4889             if (canceledNotifications == null) {
4890                 canceledNotifications = new ArrayList<>();
4891             }
4892             notificationList.remove(i);
4893             mNotificationsByKey.remove(r.getKey());
4894             canceledNotifications.add(r);
4895             cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
4896         }
4897         if (canceledNotifications != null) {
4898             final int M = canceledNotifications.size();
4899             for (int i = 0; i < M; i++) {
4900                 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
4901                         listenerName, false /* sendDelete */, flagChecker);
4902             }
4903             updateLightsLocked();
4904         }
4905     }
4906
4907     void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
4908             ManagedServiceInfo listener) {
4909         String listenerName = listener == null ? null : listener.component.toShortString();
4910         if (duration <= 0 && snoozeCriterionId == null || key == null) {
4911             return;
4912         }
4913
4914         if (DBG) {
4915             Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
4916                     snoozeCriterionId, listenerName));
4917         }
4918         // Needs to post so that it can cancel notifications not yet enqueued.
4919         mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
4920     }
4921
4922     void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
4923         String listenerName = listener == null ? null : listener.component.toShortString();
4924         if (DBG) {
4925             Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
4926         }
4927         mSnoozeHelper.repost(key);
4928         savePolicyFile();
4929     }
4930
4931     @GuardedBy("mNotificationLock")
4932     void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
4933             ManagedServiceInfo listener, boolean includeCurrentProfiles) {
4934         mHandler.post(new Runnable() {
4935             @Override
4936             public void run() {
4937                 synchronized (mNotificationLock) {
4938                     String listenerName =
4939                             listener == null ? null : listener.component.toShortString();
4940                     EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
4941                             null, userId, 0, 0, reason, listenerName);
4942
4943                     FlagChecker flagChecker = (int flags) -> {
4944                         if ((flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR))
4945                                 != 0) {
4946                             return false;
4947                         }
4948                         return true;
4949                     };
4950
4951                     cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
4952                             null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
4953                             includeCurrentProfiles, userId, true /*sendDelete*/, reason,
4954                             listenerName, true);
4955                     cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
4956                             callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
4957                             flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
4958                             reason, listenerName, false);
4959                     mSnoozeHelper.cancel(userId, includeCurrentProfiles);
4960                 }
4961             }
4962         });
4963     }
4964
4965     // Warning: The caller is responsible for invoking updateLightsLocked().
4966     @GuardedBy("mNotificationLock")
4967     private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
4968             String listenerName, boolean sendDelete, FlagChecker flagChecker) {
4969         Notification n = r.getNotification();
4970         if (!n.isGroupSummary()) {
4971             return;
4972         }
4973
4974         String pkg = r.sbn.getPackageName();
4975
4976         if (pkg == null) {
4977             if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
4978             return;
4979         }
4980
4981         cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
4982                 sendDelete, true, flagChecker);
4983         cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
4984                 listenerName, sendDelete, false, flagChecker);
4985     }
4986
4987     @GuardedBy("mNotificationLock")
4988     private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
4989             NotificationRecord parentNotification, int callingUid, int callingPid,
4990             String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker) {
4991         final String pkg = parentNotification.sbn.getPackageName();
4992         final int userId = parentNotification.getUserId();
4993         final int reason = REASON_GROUP_SUMMARY_CANCELED;
4994         for (int i = notificationList.size() - 1; i >= 0; i--) {
4995             final NotificationRecord childR = notificationList.get(i);
4996             final StatusBarNotification childSbn = childR.sbn;
4997             if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
4998                     childR.getGroupKey().equals(parentNotification.getGroupKey())
4999                     && (childR.getFlags() & Notification.FLAG_FOREGROUND_SERVICE) == 0
5000                     && (flagChecker == null || flagChecker.apply(childR.getFlags()))) {
5001                 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
5002                         childSbn.getTag(), userId, 0, 0, reason, listenerName);
5003                 notificationList.remove(i);
5004                 mNotificationsByKey.remove(childR.getKey());
5005                 cancelNotificationLocked(childR, sendDelete, reason, wasPosted, listenerName);
5006             }
5007         }
5008     }
5009
5010     @GuardedBy("mNotificationLock")
5011     void updateLightsLocked()
5012     {
5013         // handle notification lights
5014         NotificationRecord ledNotification = null;
5015         while (ledNotification == null && !mLights.isEmpty()) {
5016             final String owner = mLights.get(mLights.size() - 1);
5017             ledNotification = mNotificationsByKey.get(owner);
5018             if (ledNotification == null) {
5019                 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
5020                 mLights.remove(owner);
5021             }
5022         }
5023
5024         // Don't flash while we are in a call or screen is on
5025         if (ledNotification == null || mInCall || mScreenOn) {
5026             mNotificationLight.turnOff();
5027         } else {
5028             NotificationRecord.Light light = ledNotification.getLight();
5029             if (light != null && mNotificationPulseEnabled) {
5030                 // pulse repeatedly
5031                 mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
5032                         light.onMs, light.offMs);
5033             }
5034         }
5035     }
5036
5037     @GuardedBy("mNotificationLock")
5038     @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
5039             String groupKey, int userId) {
5040         List<NotificationRecord> records = new ArrayList<>();
5041         records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
5042         records.addAll(
5043                 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
5044         return records;
5045     }
5046
5047
5048     @GuardedBy("mNotificationLock")
5049     private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
5050             ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
5051         List<NotificationRecord> records = new ArrayList<>();
5052         final int len = list.size();
5053         for (int i = 0; i < len; i++) {
5054             NotificationRecord r = list.get(i);
5055             if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey)
5056                     && r.sbn.getPackageName().equals(pkg)) {
5057                 records.add(r);
5058             }
5059         }
5060         return records;
5061     }
5062
5063     // Searches both enqueued and posted notifications by key.
5064     // TODO: need to combine a bunch of these getters with slightly different behavior.
5065     // TODO: Should enqueuing just add to mNotificationsByKey instead?
5066     @GuardedBy("mNotificationLock")
5067     private NotificationRecord findNotificationByKeyLocked(String key) {
5068         NotificationRecord r;
5069         if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
5070             return r;
5071         }
5072         if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
5073             return r;
5074         }
5075         return null;
5076     }
5077
5078     @GuardedBy("mNotificationLock")
5079     NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
5080         NotificationRecord r;
5081         if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
5082             return r;
5083         }
5084         if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
5085                 != null) {
5086             return r;
5087         }
5088         return null;
5089     }
5090
5091     @GuardedBy("mNotificationLock")
5092     private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
5093             String pkg, String tag, int id, int userId) {
5094         final int len = list.size();
5095         for (int i = 0; i < len; i++) {
5096             NotificationRecord r = list.get(i);
5097             if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
5098                     TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
5099                 return r;
5100             }
5101         }
5102         return null;
5103     }
5104
5105     @GuardedBy("mNotificationLock")
5106     private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
5107             String key) {
5108         final int N = list.size();
5109         for (int i = 0; i < N; i++) {
5110             if (key.equals(list.get(i).getKey())) {
5111                 return list.get(i);
5112             }
5113         }
5114         return null;
5115     }
5116
5117     @GuardedBy("mNotificationLock")
5118     int indexOfNotificationLocked(String key) {
5119         final int N = mNotificationList.size();
5120         for (int i = 0; i < N; i++) {
5121             if (key.equals(mNotificationList.get(i).getKey())) {
5122                 return i;
5123             }
5124         }
5125         return -1;
5126     }
5127
5128     private void updateNotificationPulse() {
5129         synchronized (mNotificationLock) {
5130             updateLightsLocked();
5131         }
5132     }
5133
5134     protected boolean isCallingUidSystem() {
5135         final int uid = Binder.getCallingUid();
5136         return uid == Process.SYSTEM_UID;
5137     }
5138
5139     protected boolean isUidSystemOrPhone(int uid) {
5140         final int appid = UserHandle.getAppId(uid);
5141         return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
5142     }
5143
5144     // TODO: Most calls should probably move to isCallerSystem.
5145     protected boolean isCallerSystemOrPhone() {
5146         return isUidSystemOrPhone(Binder.getCallingUid());
5147     }
5148
5149     private void checkCallerIsSystemOrShell() {
5150         if (Binder.getCallingUid() == Process.SHELL_UID) {
5151             return;
5152         }
5153         checkCallerIsSystem();
5154     }
5155
5156     private void checkCallerIsSystem() {
5157         if (isCallerSystemOrPhone()) {
5158             return;
5159         }
5160         throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
5161     }
5162
5163     private void checkCallerIsSystemOrSameApp(String pkg) {
5164         if (isCallerSystemOrPhone()) {
5165             return;
5166         }
5167         checkCallerIsSameApp(pkg);
5168     }
5169
5170     private boolean isCallerInstantApp(String pkg) {
5171         // System is always allowed to act for ephemeral apps.
5172         if (isCallerSystemOrPhone()) {
5173             return false;
5174         }
5175
5176         mAppOps.checkPackage(Binder.getCallingUid(), pkg);
5177
5178         try {
5179             ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0,
5180                     UserHandle.getCallingUserId());
5181             if (ai == null) {
5182                 throw new SecurityException("Unknown package " + pkg);
5183             }
5184             return ai.isInstantApp();
5185         } catch (RemoteException re) {
5186             throw new SecurityException("Unknown package " + pkg, re);
5187         }
5188
5189     }
5190
5191     private void checkCallerIsSameApp(String pkg) {
5192         final int uid = Binder.getCallingUid();
5193         try {
5194             ApplicationInfo ai = mPackageManager.getApplicationInfo(
5195                     pkg, 0, UserHandle.getCallingUserId());
5196             if (ai == null) {
5197                 throw new SecurityException("Unknown package " + pkg);
5198             }
5199             if (!UserHandle.isSameApp(ai.uid, uid)) {
5200                 throw new SecurityException("Calling uid " + uid + " gave package "
5201                         + pkg + " which is owned by uid " + ai.uid);
5202             }
5203         } catch (RemoteException re) {
5204             throw new SecurityException("Unknown package " + pkg + "\n" + re);
5205         }
5206     }
5207
5208     private static String callStateToString(int state) {
5209         switch (state) {
5210             case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
5211             case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
5212             case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
5213             default: return "CALL_STATE_UNKNOWN_" + state;
5214         }
5215     }
5216
5217     private void listenForCallState() {
5218         TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
5219             @Override
5220             public void onCallStateChanged(int state, String incomingNumber) {
5221                 if (mCallState == state) return;
5222                 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
5223                 mCallState = state;
5224             }
5225         }, PhoneStateListener.LISTEN_CALL_STATE);
5226     }
5227
5228     /**
5229      * Generates a NotificationRankingUpdate from 'sbns', considering only
5230      * notifications visible to the given listener.
5231      */
5232     @GuardedBy("mNotificationLock")
5233     private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
5234         final int N = mNotificationList.size();
5235         ArrayList<String> keys = new ArrayList<String>(N);
5236         ArrayList<String> interceptedKeys = new ArrayList<String>(N);
5237         ArrayList<Integer> importance = new ArrayList<>(N);
5238         Bundle overrideGroupKeys = new Bundle();
5239         Bundle visibilityOverrides = new Bundle();
5240         Bundle suppressedVisualEffects = new Bundle();
5241         Bundle explanation = new Bundle();
5242         Bundle channels = new Bundle();
5243         Bundle overridePeople = new Bundle();
5244         Bundle snoozeCriteria = new Bundle();
5245         Bundle showBadge = new Bundle();
5246         for (int i = 0; i < N; i++) {
5247             NotificationRecord record = mNotificationList.get(i);
5248             if (!isVisibleToListener(record.sbn, info)) {
5249                 continue;
5250             }
5251             final String key = record.sbn.getKey();
5252             keys.add(key);
5253             importance.add(record.getImportance());
5254             if (record.getImportanceExplanation() != null) {
5255                 explanation.putCharSequence(key, record.getImportanceExplanation());
5256             }
5257             if (record.isIntercepted()) {
5258                 interceptedKeys.add(key);
5259
5260             }
5261             suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
5262             if (record.getPackageVisibilityOverride()
5263                     != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
5264                 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
5265             }
5266             overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
5267             channels.putParcelable(key, record.getChannel());
5268             overridePeople.putStringArrayList(key, record.getPeopleOverride());
5269             snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria());
5270             showBadge.putBoolean(key, record.canShowBadge());
5271         }
5272         final int M = keys.size();
5273         String[] keysAr = keys.toArray(new String[M]);
5274         String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
5275         int[] importanceAr = new int[M];
5276         for (int i = 0; i < M; i++) {
5277             importanceAr[i] = importance.get(i);
5278         }
5279         return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
5280                 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
5281                 channels, overridePeople, snoozeCriteria, showBadge);
5282     }
5283
5284     boolean hasCompanionDevice(ManagedServiceInfo info) {
5285         if (mCompanionManager == null) {
5286             mCompanionManager = getCompanionManager();
5287         }
5288         // Companion mgr doesn't exist on all device types
5289         if (mCompanionManager == null) {
5290             return false;
5291         }
5292         long identity = Binder.clearCallingIdentity();
5293         try {
5294             List<String> associations = mCompanionManager.getAssociations(
5295                     info.component.getPackageName(), info.userid);
5296             if (!ArrayUtils.isEmpty(associations)) {
5297                 return true;
5298             }
5299         } catch (SecurityException se) {
5300             // Not a privileged listener
5301         } catch (RemoteException re) {
5302             Slog.e(TAG, "Cannot reach companion device service", re);
5303         } catch (Exception e) {
5304             Slog.e(TAG, "Cannot verify listener " + info, e);
5305         } finally {
5306             Binder.restoreCallingIdentity(identity);
5307         }
5308         return false;
5309     }
5310
5311     protected ICompanionDeviceManager getCompanionManager() {
5312         return ICompanionDeviceManager.Stub.asInterface(
5313                 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
5314     }
5315
5316     private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
5317         if (!listener.enabledAndUserMatches(sbn.getUserId())) {
5318             return false;
5319         }
5320         // TODO: remove this for older listeners.
5321         return true;
5322     }
5323
5324     private boolean isPackageSuspendedForUser(String pkg, int uid) {
5325         int userId = UserHandle.getUserId(uid);
5326         try {
5327             return mPackageManager.isPackageSuspendedForUser(pkg, userId);
5328         } catch (RemoteException re) {
5329             throw new SecurityException("Could not talk to package manager service");
5330         } catch (IllegalArgumentException ex) {
5331             // Package not found.
5332             return false;
5333         }
5334     }
5335
5336     private class TrimCache {
5337         StatusBarNotification heavy;
5338         StatusBarNotification sbnClone;
5339         StatusBarNotification sbnCloneLight;
5340
5341         TrimCache(StatusBarNotification sbn) {
5342             heavy = sbn;
5343         }
5344
5345         StatusBarNotification ForListener(ManagedServiceInfo info) {
5346             if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
5347                 if (sbnCloneLight == null) {
5348                     sbnCloneLight = heavy.cloneLight();
5349                 }
5350                 return sbnCloneLight;
5351             } else {
5352                 if (sbnClone == null) {
5353                     sbnClone = heavy.clone();
5354                 }
5355                 return sbnClone;
5356             }
5357         }
5358     }
5359
5360     public class NotificationAssistants extends ManagedServices {
5361         static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
5362
5363         public NotificationAssistants(IPackageManager pm) {
5364             super(getContext(), mNotificationLock, mUserProfiles, pm);
5365         }
5366
5367         @Override
5368         protected Config getConfig() {
5369             Config c = new Config();
5370             c.caption = "notification assistant service";
5371             c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
5372             c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS;
5373             c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
5374             c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
5375             c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
5376             c.clientLabel = R.string.notification_ranker_binding_label;
5377             return c;
5378         }
5379
5380         @Override
5381         protected IInterface asInterface(IBinder binder) {
5382             return INotificationListener.Stub.asInterface(binder);
5383         }
5384
5385         @Override
5386         protected boolean checkType(IInterface service) {
5387             return service instanceof INotificationListener;
5388         }
5389
5390         @Override
5391         protected void onServiceAdded(ManagedServiceInfo info) {
5392             mListeners.registerGuestService(info);
5393         }
5394
5395         @Override
5396         @GuardedBy("mNotificationLock")
5397         protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
5398             mListeners.unregisterService(removed.service, removed.userid);
5399         }
5400
5401         public void onNotificationEnqueued(final NotificationRecord r) {
5402             final StatusBarNotification sbn = r.sbn;
5403             TrimCache trimCache = new TrimCache(sbn);
5404
5405             // There should be only one, but it's a list, so while we enforce
5406             // singularity elsewhere, we keep it general here, to avoid surprises.
5407             for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
5408                 boolean sbnVisible = isVisibleToListener(sbn, info);
5409                 if (!sbnVisible) {
5410                     continue;
5411                 }
5412
5413                 final int importance = r.getImportance();
5414                 final boolean fromUser = r.isImportanceFromUser();
5415                 final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
5416                 mHandler.post(new Runnable() {
5417                     @Override
5418                     public void run() {
5419                         notifyEnqueued(info, sbnToPost);
5420                     }
5421                 });
5422             }
5423         }
5424
5425         private void notifyEnqueued(final ManagedServiceInfo info,
5426                 final StatusBarNotification sbn) {
5427             final INotificationListener assistant = (INotificationListener) info.service;
5428             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5429             try {
5430                 assistant.onNotificationEnqueued(sbnHolder);
5431             } catch (RemoteException ex) {
5432                 Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
5433             }
5434         }
5435
5436         /**
5437          * asynchronously notify the assistant that a notification has been snoozed until a
5438          * context
5439          */
5440         @GuardedBy("mNotificationLock")
5441         public void notifyAssistantSnoozedLocked(final StatusBarNotification sbn,
5442                 final String snoozeCriterionId) {
5443             TrimCache trimCache = new TrimCache(sbn);
5444             for (final ManagedServiceInfo info : getServices()) {
5445                 final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
5446                 mHandler.post(new Runnable() {
5447                     @Override
5448                     public void run() {
5449                         final INotificationListener assistant =
5450                                 (INotificationListener) info.service;
5451                         StatusBarNotificationHolder sbnHolder
5452                                 = new StatusBarNotificationHolder(sbnToPost);
5453                         try {
5454                             assistant.onNotificationSnoozedUntilContext(
5455                                     sbnHolder, snoozeCriterionId);
5456                         } catch (RemoteException ex) {
5457                             Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
5458                         }
5459                     }
5460                 });
5461             }
5462         }
5463
5464         public boolean isEnabled() {
5465             return !getServices().isEmpty();
5466         }
5467     }
5468
5469     public class NotificationListeners extends ManagedServices {
5470         static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners";
5471
5472         private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
5473
5474         public NotificationListeners(IPackageManager pm) {
5475             super(getContext(), mNotificationLock, mUserProfiles, pm);
5476
5477         }
5478
5479         @Override
5480         protected Config getConfig() {
5481             Config c = new Config();
5482             c.caption = "notification listener";
5483             c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
5484             c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS;
5485             c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
5486             c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
5487             c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
5488             c.clientLabel = R.string.notification_listener_binding_label;
5489             return c;
5490         }
5491
5492         @Override
5493         protected IInterface asInterface(IBinder binder) {
5494             return INotificationListener.Stub.asInterface(binder);
5495         }
5496
5497         @Override
5498         protected boolean checkType(IInterface service) {
5499             return service instanceof INotificationListener;
5500         }
5501
5502         @Override
5503         public void onServiceAdded(ManagedServiceInfo info) {
5504             final INotificationListener listener = (INotificationListener) info.service;
5505             final NotificationRankingUpdate update;
5506             synchronized (mNotificationLock) {
5507                 update = makeRankingUpdateLocked(info);
5508             }
5509             try {
5510                 listener.onListenerConnected(update);
5511             } catch (RemoteException e) {
5512                 // we tried
5513             }
5514         }
5515
5516         @Override
5517         @GuardedBy("mNotificationLock")
5518         protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
5519             if (removeDisabledHints(removed)) {
5520                 updateListenerHintsLocked();
5521                 updateEffectsSuppressorLocked();
5522             }
5523             mLightTrimListeners.remove(removed);
5524         }
5525
5526         @GuardedBy("mNotificationLock")
5527         public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
5528             if (trim == TRIM_LIGHT) {
5529                 mLightTrimListeners.add(info);
5530             } else {
5531                 mLightTrimListeners.remove(info);
5532             }
5533         }
5534
5535         public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
5536             return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
5537         }
5538
5539         /**
5540          * asynchronously notify all listeners about a new notification
5541          *
5542          * <p>
5543          * Also takes care of removing a notification that has been visible to a listener before,
5544          * but isn't anymore.
5545          */
5546         @GuardedBy("mNotificationLock")
5547         public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
5548             // Lazily initialized snapshots of the notification.
5549             TrimCache trimCache = new TrimCache(sbn);
5550
5551             for (final ManagedServiceInfo info : getServices()) {
5552                 boolean sbnVisible = isVisibleToListener(sbn, info);
5553                 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
5554                 // This notification hasn't been and still isn't visible -> ignore.
5555                 if (!oldSbnVisible && !sbnVisible) {
5556                     continue;
5557                 }
5558                 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
5559
5560                 // This notification became invisible -> remove the old one.
5561                 if (oldSbnVisible && !sbnVisible) {
5562                     final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
5563                     mHandler.post(new Runnable() {
5564                         @Override
5565                         public void run() {
5566                             notifyRemoved(info, oldSbnLightClone, update, REASON_USER_STOPPED);
5567                         }
5568                     });
5569                     continue;
5570                 }
5571
5572                 final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
5573                 mHandler.post(new Runnable() {
5574                     @Override
5575                     public void run() {
5576                         notifyPosted(info, sbnToPost, update);
5577                     }
5578                 });
5579             }
5580         }
5581
5582         /**
5583          * asynchronously notify all listeners about a removed notification
5584          */
5585         @GuardedBy("mNotificationLock")
5586         public void notifyRemovedLocked(StatusBarNotification sbn, int reason) {
5587             // make a copy in case changes are made to the underlying Notification object
5588             // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
5589             // notification
5590             final StatusBarNotification sbnLight = sbn.cloneLight();
5591             for (final ManagedServiceInfo info : getServices()) {
5592                 if (!isVisibleToListener(sbn, info)) {
5593                     continue;
5594                 }
5595                 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
5596                 mHandler.post(new Runnable() {
5597                     @Override
5598                     public void run() {
5599                         notifyRemoved(info, sbnLight, update, reason);
5600                     }
5601                 });
5602             }
5603         }
5604
5605         /**
5606          * asynchronously notify all listeners about a reordering of notifications
5607          */
5608         @GuardedBy("mNotificationLock")
5609         public void notifyRankingUpdateLocked() {
5610             for (final ManagedServiceInfo serviceInfo : getServices()) {
5611                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5612                     continue;
5613                 }
5614                 final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
5615                 mHandler.post(new Runnable() {
5616                     @Override
5617                     public void run() {
5618                         notifyRankingUpdate(serviceInfo, update);
5619                     }
5620                 });
5621             }
5622         }
5623
5624         @GuardedBy("mNotificationLock")
5625         public void notifyListenerHintsChangedLocked(final int hints) {
5626             for (final ManagedServiceInfo serviceInfo : getServices()) {
5627                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5628                     continue;
5629                 }
5630                 mHandler.post(new Runnable() {
5631                     @Override
5632                     public void run() {
5633                         notifyListenerHintsChanged(serviceInfo, hints);
5634                     }
5635                 });
5636             }
5637         }
5638
5639         public void notifyInterruptionFilterChanged(final int interruptionFilter) {
5640             for (final ManagedServiceInfo serviceInfo : getServices()) {
5641                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5642                     continue;
5643                 }
5644                 mHandler.post(new Runnable() {
5645                     @Override
5646                     public void run() {
5647                         notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
5648                     }
5649                 });
5650             }
5651         }
5652
5653         protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user,
5654                 final NotificationChannel channel, final int modificationType) {
5655             if (channel == null) {
5656                 return;
5657             }
5658             for (final ManagedServiceInfo serviceInfo : getServices()) {
5659                 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
5660                     continue;
5661                 }
5662
5663                 BackgroundThread.getHandler().post(() -> {
5664                     if (hasCompanionDevice(serviceInfo)) {
5665                         notifyNotificationChannelChanged(
5666                                 serviceInfo, pkg, user, channel, modificationType);
5667                     }
5668                 });
5669             }
5670         }
5671
5672         protected void notifyNotificationChannelGroupChanged(
5673                 final String pkg, final UserHandle user, final NotificationChannelGroup group,
5674                 final int modificationType) {
5675             if (group == null) {
5676                 return;
5677             }
5678             for (final ManagedServiceInfo serviceInfo : getServices()) {
5679                 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
5680                     continue;
5681                 }
5682
5683                 BackgroundThread.getHandler().post(() -> {
5684                     if (hasCompanionDevice(serviceInfo)) {
5685                         notifyNotificationChannelGroupChanged(
5686                                 serviceInfo, pkg, user, group, modificationType);
5687                     }
5688                 });
5689             }
5690         }
5691
5692         private void notifyPosted(final ManagedServiceInfo info,
5693                 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
5694             final INotificationListener listener = (INotificationListener) info.service;
5695             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5696             try {
5697                 listener.onNotificationPosted(sbnHolder, rankingUpdate);
5698             } catch (RemoteException ex) {
5699                 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
5700             }
5701         }
5702
5703         private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
5704                 NotificationRankingUpdate rankingUpdate, int reason) {
5705             if (!info.enabledAndUserMatches(sbn.getUserId())) {
5706                 return;
5707             }
5708             final INotificationListener listener = (INotificationListener) info.service;
5709             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5710             try {
5711                 listener.onNotificationRemoved(sbnHolder, rankingUpdate, reason);
5712             } catch (RemoteException ex) {
5713                 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
5714             }
5715         }
5716
5717         private void notifyRankingUpdate(ManagedServiceInfo info,
5718                                          NotificationRankingUpdate rankingUpdate) {
5719             final INotificationListener listener = (INotificationListener) info.service;
5720             try {
5721                 listener.onNotificationRankingUpdate(rankingUpdate);
5722             } catch (RemoteException ex) {
5723                 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
5724             }
5725         }
5726
5727         private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
5728             final INotificationListener listener = (INotificationListener) info.service;
5729             try {
5730                 listener.onListenerHintsChanged(hints);
5731             } catch (RemoteException ex) {
5732                 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
5733             }
5734         }
5735
5736         private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
5737                 int interruptionFilter) {
5738             final INotificationListener listener = (INotificationListener) info.service;
5739             try {
5740                 listener.onInterruptionFilterChanged(interruptionFilter);
5741             } catch (RemoteException ex) {
5742                 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
5743             }
5744         }
5745
5746         void notifyNotificationChannelChanged(ManagedServiceInfo info,
5747                 final String pkg, final UserHandle user, final NotificationChannel channel,
5748                 final int modificationType) {
5749             final INotificationListener listener = (INotificationListener) info.service;
5750             try {
5751                 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
5752             } catch (RemoteException ex) {
5753                 Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
5754             }
5755         }
5756
5757         private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
5758                 final String pkg, final UserHandle user, final NotificationChannelGroup group,
5759                 final int modificationType) {
5760             final INotificationListener listener = (INotificationListener) info.service;
5761             try {
5762                 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
5763             } catch (RemoteException ex) {
5764                 Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
5765             }
5766         }
5767
5768         public boolean isListenerPackage(String packageName) {
5769             if (packageName == null) {
5770                 return false;
5771             }
5772             // TODO: clean up locking object later
5773             synchronized (mNotificationLock) {
5774                 for (final ManagedServiceInfo serviceInfo : getServices()) {
5775                     if (packageName.equals(serviceInfo.component.getPackageName())) {
5776                         return true;
5777                     }
5778                 }
5779             }
5780             return false;
5781         }
5782     }
5783
5784     public static final class DumpFilter {
5785         public boolean filtered = false;
5786         public String pkgFilter;
5787         public boolean zen;
5788         public long since;
5789         public boolean stats;
5790         public boolean redact = true;
5791         public boolean proto = false;
5792
5793         public static DumpFilter parseFromArguments(String[] args) {
5794             final DumpFilter filter = new DumpFilter();
5795             for (int ai = 0; ai < args.length; ai++) {
5796                 final String a = args[ai];
5797                 if ("--proto".equals(args[0])) {
5798                     filter.proto = true;
5799                 }
5800                 if ("--noredact".equals(a) || "--reveal".equals(a)) {
5801                     filter.redact = false;
5802                 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
5803                     if (ai < args.length-1) {
5804                         ai++;
5805                         filter.pkgFilter = args[ai].trim().toLowerCase();
5806                         if (filter.pkgFilter.isEmpty()) {
5807                             filter.pkgFilter = null;
5808                         } else {
5809                             filter.filtered = true;
5810                         }
5811                     }
5812                 } else if ("--zen".equals(a) || "zen".equals(a)) {
5813                     filter.filtered = true;
5814                     filter.zen = true;
5815                 } else if ("--stats".equals(a)) {
5816                     filter.stats = true;
5817                     if (ai < args.length-1) {
5818                         ai++;
5819                         filter.since = Long.parseLong(args[ai]);
5820                     } else {
5821                         filter.since = 0;
5822                     }
5823                 }
5824             }
5825             return filter;
5826         }
5827
5828         public boolean matches(StatusBarNotification sbn) {
5829             if (!filtered) return true;
5830             return zen ? true : sbn != null
5831                     && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
5832         }
5833
5834         public boolean matches(ComponentName component) {
5835             if (!filtered) return true;
5836             return zen ? true : component != null && matches(component.getPackageName());
5837         }
5838
5839         public boolean matches(String pkg) {
5840             if (!filtered) return true;
5841             return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
5842         }
5843
5844         @Override
5845         public String toString() {
5846             return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
5847         }
5848     }
5849
5850     /**
5851      * Wrapper for a StatusBarNotification object that allows transfer across a oneway
5852      * binder without sending large amounts of data over a oneway transaction.
5853      */
5854     private static final class StatusBarNotificationHolder
5855             extends IStatusBarNotificationHolder.Stub {
5856         private StatusBarNotification mValue;
5857
5858         public StatusBarNotificationHolder(StatusBarNotification value) {
5859             mValue = value;
5860         }
5861
5862         /** Get the held value and clear it. This function should only be called once per holder */
5863         @Override
5864         public StatusBarNotification get() {
5865             StatusBarNotification value = mValue;
5866             mValue = null;
5867             return value;
5868         }
5869     }
5870
5871     private class ShellCmd extends ShellCommand {
5872         public static final String USAGE = "help\n"
5873                 + "allow_listener COMPONENT [user_id]\n"
5874                 + "disallow_listener COMPONENT [user_id]\n"
5875                 + "set_assistant COMPONENT\n"
5876                 + "remove_assistant COMPONENT\n"
5877                 + "allow_dnd PACKAGE\n"
5878                 + "disallow_dnd PACKAGE";
5879
5880         @Override
5881         public int onCommand(String cmd) {
5882             if (cmd == null) {
5883                 return handleDefaultCommands(cmd);
5884             }
5885             final PrintWriter pw = getOutPrintWriter();
5886             try {
5887                 switch (cmd) {
5888                     case "allow_dnd": {
5889                         getBinderService().setNotificationPolicyAccessGranted(
5890                                 getNextArgRequired(), true);
5891                     }
5892                     break;
5893
5894                     case "disallow_dnd": {
5895                         getBinderService().setNotificationPolicyAccessGranted(
5896                                 getNextArgRequired(), false);
5897                     }
5898                     break;
5899                     case "allow_listener": {
5900                         ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
5901                         if (cn == null) {
5902                             pw.println("Invalid listener - must be a ComponentName");
5903                             return -1;
5904                         }
5905                         String userId = getNextArg();
5906                         if (userId == null) {
5907                             getBinderService().setNotificationListenerAccessGranted(cn, true);
5908                         } else {
5909                             getBinderService().setNotificationListenerAccessGrantedForUser(
5910                                     cn, Integer.parseInt(userId), true);
5911                         }
5912                     }
5913                     break;
5914                     case "disallow_listener": {
5915                         ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
5916                         if (cn == null) {
5917                             pw.println("Invalid listener - must be a ComponentName");
5918                             return -1;
5919                         }
5920                         String userId = getNextArg();
5921                         if (userId == null) {
5922                             getBinderService().setNotificationListenerAccessGranted(cn, false);
5923                         } else {
5924                             getBinderService().setNotificationListenerAccessGrantedForUser(
5925                                     cn, Integer.parseInt(userId), false);
5926                         }
5927                     }
5928                     break;
5929                     case "allow_assistant": {
5930                         ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
5931                         if (cn == null) {
5932                             pw.println("Invalid assistant - must be a ComponentName");
5933                             return -1;
5934                         }
5935                         getBinderService().setNotificationAssistantAccessGranted(cn, true);
5936                     }
5937                     break;
5938                     case "disallow_assistant": {
5939                         ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
5940                         if (cn == null) {
5941                             pw.println("Invalid assistant - must be a ComponentName");
5942                             return -1;
5943                         }
5944                         getBinderService().setNotificationAssistantAccessGranted(cn, false);
5945                     }
5946                     break;
5947
5948                     default:
5949                         return handleDefaultCommands(cmd);
5950                 }
5951             } catch (Exception e) {
5952                 pw.println("Error occurred. Check logcat for details. " + e.getMessage());
5953                 Slog.e(TAG, "Error running shell command", e);
5954             }
5955             return 0;
5956         }
5957
5958         @Override
5959         public void onHelp() {
5960             getOutPrintWriter().println(USAGE);
5961         }
5962     }
5963 }