OSDN Git Service

Merge cherrypicks of [3156476, 3155698, 3156194, 3156639, 3156018, 3156477, 3156098...
[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
1771             return mRankingHelper.getImportance(pkg, uid) != IMPORTANCE_NONE;
1772         }
1773
1774         @Override
1775         public int getPackageImportance(String pkg) {
1776             checkCallerIsSystemOrSameApp(pkg);
1777             return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
1778         }
1779
1780         @Override
1781         public boolean canShowBadge(String pkg, int uid) {
1782             checkCallerIsSystem();
1783             return mRankingHelper.canShowBadge(pkg, uid);
1784         }
1785
1786         @Override
1787         public void setShowBadge(String pkg, int uid, boolean showBadge) {
1788             checkCallerIsSystem();
1789             mRankingHelper.setShowBadge(pkg, uid, showBadge);
1790             savePolicyFile();
1791         }
1792
1793         @Override
1794         public void createNotificationChannelGroups(String pkg,
1795                 ParceledListSlice channelGroupList) throws RemoteException {
1796             checkCallerIsSystemOrSameApp(pkg);
1797             List<NotificationChannelGroup> groups = channelGroupList.getList();
1798             final int groupSize = groups.size();
1799             for (int i = 0; i < groupSize; i++) {
1800                 final NotificationChannelGroup group = groups.get(i);
1801                 Preconditions.checkNotNull(group, "group in list is null");
1802                 mRankingHelper.createNotificationChannelGroup(pkg, Binder.getCallingUid(), group,
1803                         true /* fromTargetApp */);
1804                 mListeners.notifyNotificationChannelGroupChanged(pkg,
1805                         UserHandle.of(UserHandle.getCallingUserId()), group,
1806                         NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1807             }
1808             savePolicyFile();
1809         }
1810
1811         private void createNotificationChannelsImpl(String pkg, int uid,
1812                 ParceledListSlice channelsList) {
1813             List<NotificationChannel> channels = channelsList.getList();
1814             final int channelsSize = channels.size();
1815             for (int i = 0; i < channelsSize; i++) {
1816                 final NotificationChannel channel = channels.get(i);
1817                 Preconditions.checkNotNull(channel, "channel in list is null");
1818                 mRankingHelper.createNotificationChannel(pkg, uid, channel,
1819                         true /* fromTargetApp */);
1820                 mListeners.notifyNotificationChannelChanged(pkg,
1821                         UserHandle.getUserHandleForUid(uid),
1822                         mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false),
1823                         NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1824             }
1825             savePolicyFile();
1826         }
1827
1828         @Override
1829         public void createNotificationChannels(String pkg,
1830                 ParceledListSlice channelsList) throws RemoteException {
1831             checkCallerIsSystemOrSameApp(pkg);
1832             createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList);
1833         }
1834
1835         @Override
1836         public void createNotificationChannelsForPackage(String pkg, int uid,
1837                 ParceledListSlice channelsList) throws RemoteException {
1838             checkCallerIsSystem();
1839             createNotificationChannelsImpl(pkg, uid, channelsList);
1840         }
1841
1842         @Override
1843         public NotificationChannel getNotificationChannel(String pkg, String channelId) {
1844             checkCallerIsSystemOrSameApp(pkg);
1845             return mRankingHelper.getNotificationChannel(
1846                     pkg, Binder.getCallingUid(), channelId, false /* includeDeleted */);
1847         }
1848
1849         @Override
1850         public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
1851                 String channelId, boolean includeDeleted) {
1852             checkCallerIsSystem();
1853             return mRankingHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted);
1854         }
1855
1856         @Override
1857         public void deleteNotificationChannel(String pkg, String channelId) {
1858             checkCallerIsSystemOrSameApp(pkg);
1859             final int callingUid = Binder.getCallingUid();
1860             if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
1861                 throw new IllegalArgumentException("Cannot delete default channel");
1862             }
1863             cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
1864                     UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
1865             mRankingHelper.deleteNotificationChannel(pkg, callingUid, channelId);
1866             mListeners.notifyNotificationChannelChanged(pkg,
1867                     UserHandle.getUserHandleForUid(callingUid),
1868                     mRankingHelper.getNotificationChannel(pkg, callingUid, channelId, true),
1869                     NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1870             savePolicyFile();
1871         }
1872
1873         @Override
1874         public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
1875                 String pkg) {
1876             checkCallerIsSystemOrSameApp(pkg);
1877             return new ParceledListSlice<>(new ArrayList(
1878                     mRankingHelper.getNotificationChannelGroups(pkg, Binder.getCallingUid())));
1879         }
1880
1881         @Override
1882         public void deleteNotificationChannelGroup(String pkg, String groupId) {
1883             checkCallerIsSystemOrSameApp(pkg);
1884
1885             final int callingUid = Binder.getCallingUid();
1886             NotificationChannelGroup groupToDelete =
1887                     mRankingHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
1888             if (groupToDelete != null) {
1889                 List<NotificationChannel> deletedChannels =
1890                         mRankingHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
1891                 for (int i = 0; i < deletedChannels.size(); i++) {
1892                     final NotificationChannel deletedChannel = deletedChannels.get(i);
1893                     cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
1894                             true,
1895                             UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
1896                             null);
1897                     mListeners.notifyNotificationChannelChanged(pkg,
1898                             UserHandle.getUserHandleForUid(callingUid),
1899                             deletedChannel,
1900                             NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1901                 }
1902                 mListeners.notifyNotificationChannelGroupChanged(
1903                         pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete,
1904                         NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1905                 savePolicyFile();
1906             }
1907         }
1908
1909         @Override
1910         public void updateNotificationChannelForPackage(String pkg, int uid,
1911                 NotificationChannel channel) {
1912             enforceSystemOrSystemUI("Caller not system or systemui");
1913             Preconditions.checkNotNull(channel);
1914             updateNotificationChannelInt(pkg, uid, channel, false);
1915         }
1916
1917         @Override
1918         public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
1919                 int uid, boolean includeDeleted) {
1920             enforceSystemOrSystemUI("getNotificationChannelsForPackage");
1921             return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted);
1922         }
1923
1924         @Override
1925         public int getNumNotificationChannelsForPackage(String pkg, int uid,
1926                 boolean includeDeleted) {
1927             enforceSystemOrSystemUI("getNumNotificationChannelsForPackage");
1928             return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted)
1929                     .getList().size();
1930         }
1931
1932         @Override
1933         public boolean onlyHasDefaultChannel(String pkg, int uid) {
1934             enforceSystemOrSystemUI("onlyHasDefaultChannel");
1935             return mRankingHelper.onlyHasDefaultChannel(pkg, uid);
1936         }
1937
1938         @Override
1939         public int getDeletedChannelCount(String pkg, int uid) {
1940             enforceSystemOrSystemUI("getDeletedChannelCount");
1941             return mRankingHelper.getDeletedChannelCount(pkg, uid);
1942         }
1943
1944         @Override
1945         public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
1946                 String pkg, int uid, boolean includeDeleted) {
1947             checkCallerIsSystem();
1948             return mRankingHelper.getNotificationChannelGroups(pkg, uid, includeDeleted);
1949         }
1950
1951         @Override
1952         public NotificationChannelGroup getNotificationChannelGroupForPackage(
1953                 String groupId, String pkg, int uid) {
1954             enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
1955             return mRankingHelper.getNotificationChannelGroup(groupId, pkg, uid);
1956         }
1957
1958         @Override
1959         public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
1960             checkCallerIsSystemOrSameApp(pkg);
1961             return mRankingHelper.getNotificationChannels(
1962                     pkg, Binder.getCallingUid(), false /* includeDeleted */);
1963         }
1964
1965         @Override
1966         public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
1967             checkCallerIsSystem();
1968
1969             // Cancel posted notifications
1970             cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true,
1971                     UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
1972
1973             final String[] packages = new String[] {packageName};
1974             final int[] uids = new int[] {uid};
1975
1976             // Listener & assistant
1977             mListeners.onPackagesChanged(true, packages, uids);
1978             mAssistants.onPackagesChanged(true, packages, uids);
1979
1980             // Zen
1981             mConditionProviders.onPackagesChanged(true, packages, uids);
1982
1983             // Reset notification preferences
1984             if (!fromApp) {
1985                 mRankingHelper.onPackagesChanged(
1986                         true, UserHandle.getCallingUserId(), packages, uids);
1987             }
1988
1989             savePolicyFile();
1990         }
1991
1992
1993         /**
1994          * System-only API for getting a list of current (i.e. not cleared) notifications.
1995          *
1996          * Requires ACCESS_NOTIFICATIONS which is signature|system.
1997          * @returns A list of all the notifications, in natural order.
1998          */
1999         @Override
2000         public StatusBarNotification[] getActiveNotifications(String callingPkg) {
2001             // enforce() will ensure the calling uid has the correct permission
2002             getContext().enforceCallingOrSelfPermission(
2003                     android.Manifest.permission.ACCESS_NOTIFICATIONS,
2004                     "NotificationManagerService.getActiveNotifications");
2005
2006             StatusBarNotification[] tmp = null;
2007             int uid = Binder.getCallingUid();
2008
2009             // noteOp will check to make sure the callingPkg matches the uid
2010             if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2011                     == AppOpsManager.MODE_ALLOWED) {
2012                 synchronized (mNotificationLock) {
2013                     tmp = new StatusBarNotification[mNotificationList.size()];
2014                     final int N = mNotificationList.size();
2015                     for (int i=0; i<N; i++) {
2016                         tmp[i] = mNotificationList.get(i).sbn;
2017                     }
2018                 }
2019             }
2020             return tmp;
2021         }
2022
2023         /**
2024          * Public API for getting a list of current notifications for the calling package/uid.
2025          *
2026          * Note that since notification posting is done asynchronously, this will not return
2027          * notifications that are in the process of being posted.
2028          *
2029          * @returns A list of all the package's notifications, in natural order.
2030          */
2031         @Override
2032         public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
2033                 int incomingUserId) {
2034             checkCallerIsSystemOrSameApp(pkg);
2035             int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2036                     Binder.getCallingUid(), incomingUserId, true, false,
2037                     "getAppActiveNotifications", pkg);
2038             synchronized (mNotificationLock) {
2039                 final ArrayMap<String, StatusBarNotification> map
2040                         = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
2041                 final int N = mNotificationList.size();
2042                 for (int i = 0; i < N; i++) {
2043                     StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2044                             mNotificationList.get(i).sbn);
2045                     if (sbn != null) {
2046                         map.put(sbn.getKey(), sbn);
2047                     }
2048                 }
2049                 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
2050                     StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn);
2051                     if (sbn != null) {
2052                         map.put(sbn.getKey(), sbn);
2053                     }
2054                 }
2055                 final int M = mEnqueuedNotifications.size();
2056                 for (int i = 0; i < M; i++) {
2057                     StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2058                             mEnqueuedNotifications.get(i).sbn);
2059                     if (sbn != null) {
2060                         map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
2061                     }
2062                 }
2063                 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
2064                 list.addAll(map.values());
2065                 return new ParceledListSlice<StatusBarNotification>(list);
2066             }
2067         }
2068
2069         private StatusBarNotification sanitizeSbn(String pkg, int userId,
2070                 StatusBarNotification sbn) {
2071             if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId) {
2072                 // We could pass back a cloneLight() but clients might get confused and
2073                 // try to send this thing back to notify() again, which would not work
2074                 // very well.
2075                 return new StatusBarNotification(
2076                         sbn.getPackageName(),
2077                         sbn.getOpPkg(),
2078                         sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
2079                         sbn.getNotification().clone(),
2080                         sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
2081             }
2082             return null;
2083         }
2084
2085         /**
2086          * System-only API for getting a list of recent (cleared, no longer shown) notifications.
2087          *
2088          * Requires ACCESS_NOTIFICATIONS which is signature|system.
2089          */
2090         @Override
2091         public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
2092             // enforce() will ensure the calling uid has the correct permission
2093             getContext().enforceCallingOrSelfPermission(
2094                     android.Manifest.permission.ACCESS_NOTIFICATIONS,
2095                     "NotificationManagerService.getHistoricalNotifications");
2096
2097             StatusBarNotification[] tmp = null;
2098             int uid = Binder.getCallingUid();
2099
2100             // noteOp will check to make sure the callingPkg matches the uid
2101             if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2102                     == AppOpsManager.MODE_ALLOWED) {
2103                 synchronized (mArchive) {
2104                     tmp = mArchive.getArray(count);
2105                 }
2106             }
2107             return tmp;
2108         }
2109
2110         /**
2111          * Register a listener binder directly with the notification manager.
2112          *
2113          * Only works with system callers. Apps should extend
2114          * {@link android.service.notification.NotificationListenerService}.
2115          */
2116         @Override
2117         public void registerListener(final INotificationListener listener,
2118                 final ComponentName component, final int userid) {
2119             enforceSystemOrSystemUI("INotificationManager.registerListener");
2120             mListeners.registerService(listener, component, userid);
2121         }
2122
2123         /**
2124          * Remove a listener binder directly
2125          */
2126         @Override
2127         public void unregisterListener(INotificationListener token, int userid) {
2128             mListeners.unregisterService(token, userid);
2129         }
2130
2131         /**
2132          * Allow an INotificationListener to simulate a "clear all" operation.
2133          *
2134          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
2135          *
2136          * @param token The binder for the listener, to check that the caller is allowed
2137          */
2138         @Override
2139         public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
2140             final int callingUid = Binder.getCallingUid();
2141             final int callingPid = Binder.getCallingPid();
2142             long identity = Binder.clearCallingIdentity();
2143             try {
2144                 synchronized (mNotificationLock) {
2145                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2146                     if (keys != null) {
2147                         final int N = keys.length;
2148                         for (int i = 0; i < N; i++) {
2149                             NotificationRecord r = mNotificationsByKey.get(keys[i]);
2150                             if (r == null) continue;
2151                             final int userId = r.sbn.getUserId();
2152                             if (userId != info.userid && userId != UserHandle.USER_ALL &&
2153                                     !mUserProfiles.isCurrentProfile(userId)) {
2154                                 throw new SecurityException("Disallowed call from listener: "
2155                                         + info.service);
2156                             }
2157                             cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2158                                     r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
2159                                     userId);
2160                         }
2161                     } else {
2162                         cancelAllLocked(callingUid, callingPid, info.userid,
2163                                 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
2164                     }
2165                 }
2166             } finally {
2167                 Binder.restoreCallingIdentity(identity);
2168             }
2169         }
2170
2171         /**
2172          * Handle request from an approved listener to re-enable itself.
2173          *
2174          * @param component The componenet to be re-enabled, caller must match package.
2175          */
2176         @Override
2177         public void requestBindListener(ComponentName component) {
2178             checkCallerIsSystemOrSameApp(component.getPackageName());
2179             long identity = Binder.clearCallingIdentity();
2180             try {
2181                 ManagedServices manager =
2182                         mAssistants.isComponentEnabledForCurrentProfiles(component)
2183                         ? mAssistants
2184                         : mListeners;
2185                 manager.setComponentState(component, true);
2186             } finally {
2187                 Binder.restoreCallingIdentity(identity);
2188             }
2189         }
2190
2191         @Override
2192         public void requestUnbindListener(INotificationListener token) {
2193             long identity = Binder.clearCallingIdentity();
2194             try {
2195                 // allow bound services to disable themselves
2196                 synchronized (mNotificationLock) {
2197                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2198                     info.getOwner().setComponentState(info.component, false);
2199                 }
2200             } finally {
2201                 Binder.restoreCallingIdentity(identity);
2202             }
2203         }
2204
2205         @Override
2206         public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
2207             long identity = Binder.clearCallingIdentity();
2208             try {
2209                 synchronized (mNotificationLock) {
2210                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2211                     if (keys != null) {
2212                         final int N = keys.length;
2213                         for (int i = 0; i < N; i++) {
2214                             NotificationRecord r = mNotificationsByKey.get(keys[i]);
2215                             if (r == null) continue;
2216                             final int userId = r.sbn.getUserId();
2217                             if (userId != info.userid && userId != UserHandle.USER_ALL &&
2218                                     !mUserProfiles.isCurrentProfile(userId)) {
2219                                 throw new SecurityException("Disallowed call from listener: "
2220                                         + info.service);
2221                             }
2222                             if (!r.isSeen()) {
2223                                 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
2224                                 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
2225                                         userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM
2226                                                 : userId,
2227                                         UsageEvents.Event.USER_INTERACTION);
2228                                 r.setSeen();
2229                             }
2230                         }
2231                     }
2232                 }
2233             } finally {
2234                 Binder.restoreCallingIdentity(identity);
2235             }
2236         }
2237
2238         /**
2239          * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2240          *
2241          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2242          *
2243          * @param info The binder for the listener, to check that the caller is allowed
2244          */
2245         @GuardedBy("mNotificationLock")
2246         private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
2247                 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
2248             cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
2249                     Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
2250                     true,
2251                     userId, REASON_LISTENER_CANCEL, info);
2252         }
2253
2254         /**
2255          * Allow an INotificationListener to snooze a single notification until a context.
2256          *
2257          * @param token The binder for the listener, to check that the caller is allowed
2258          */
2259         @Override
2260         public void snoozeNotificationUntilContextFromListener(INotificationListener token,
2261                 String key, String snoozeCriterionId) {
2262             long identity = Binder.clearCallingIdentity();
2263             try {
2264                 synchronized (mNotificationLock) {
2265                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2266                     snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info);
2267                 }
2268             } finally {
2269                 Binder.restoreCallingIdentity(identity);
2270             }
2271         }
2272
2273         /**
2274          * Allow an INotificationListener to snooze a single notification until a time.
2275          *
2276          * @param token The binder for the listener, to check that the caller is allowed
2277          */
2278         @Override
2279         public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
2280                 long duration) {
2281             long identity = Binder.clearCallingIdentity();
2282             try {
2283                 synchronized (mNotificationLock) {
2284                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2285                     snoozeNotificationInt(key, duration, null, info);
2286                 }
2287             } finally {
2288                 Binder.restoreCallingIdentity(identity);
2289             }
2290         }
2291
2292         /**
2293          * Allows the notification assistant to un-snooze a single notification.
2294          *
2295          * @param token The binder for the assistant, to check that the caller is allowed
2296          */
2297         @Override
2298         public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
2299             long identity = Binder.clearCallingIdentity();
2300             try {
2301                 synchronized (mNotificationLock) {
2302                     final ManagedServiceInfo info =
2303                             mAssistants.checkServiceTokenLocked(token);
2304                     unsnoozeNotificationInt(key, info);
2305                 }
2306             } finally {
2307                 Binder.restoreCallingIdentity(identity);
2308             }
2309         }
2310
2311         /**
2312          * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2313          *
2314          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2315          *
2316          * @param token The binder for the listener, to check that the caller is allowed
2317          */
2318         @Override
2319         public void cancelNotificationFromListener(INotificationListener token, String pkg,
2320                 String tag, int id) {
2321             final int callingUid = Binder.getCallingUid();
2322             final int callingPid = Binder.getCallingPid();
2323             long identity = Binder.clearCallingIdentity();
2324             try {
2325                 synchronized (mNotificationLock) {
2326                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2327                     if (info.supportsProfiles()) {
2328                         Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
2329                                 + "from " + info.component
2330                                 + " use cancelNotification(key) instead.");
2331                     } else {
2332                         cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2333                                 pkg, tag, id, info.userid);
2334                     }
2335                 }
2336             } finally {
2337                 Binder.restoreCallingIdentity(identity);
2338             }
2339         }
2340
2341         /**
2342          * Allow an INotificationListener to request the list of outstanding notifications seen by
2343          * the current user. Useful when starting up, after which point the listener callbacks
2344          * should be used.
2345          *
2346          * @param token The binder for the listener, to check that the caller is allowed
2347          * @param keys An array of notification keys to fetch, or null to fetch everything
2348          * @returns The return value will contain the notifications specified in keys, in that
2349          *      order, or if keys is null, all the notifications, in natural order.
2350          */
2351         @Override
2352         public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
2353                 INotificationListener token, String[] keys, int trim) {
2354             synchronized (mNotificationLock) {
2355                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2356                 final boolean getKeys = keys != null;
2357                 final int N = getKeys ? keys.length : mNotificationList.size();
2358                 final ArrayList<StatusBarNotification> list
2359                         = new ArrayList<StatusBarNotification>(N);
2360                 for (int i=0; i<N; i++) {
2361                     final NotificationRecord r = getKeys
2362                             ? mNotificationsByKey.get(keys[i])
2363                             : mNotificationList.get(i);
2364                     if (r == null) continue;
2365                     StatusBarNotification sbn = r.sbn;
2366                     if (!isVisibleToListener(sbn, info)) continue;
2367                     StatusBarNotification sbnToSend =
2368                             (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2369                     list.add(sbnToSend);
2370                 }
2371                 return new ParceledListSlice<StatusBarNotification>(list);
2372             }
2373         }
2374
2375         /**
2376          * Allow an INotificationListener to request the list of outstanding snoozed notifications
2377          * seen by the current user. Useful when starting up, after which point the listener
2378          * callbacks should be used.
2379          *
2380          * @param token The binder for the listener, to check that the caller is allowed
2381          * @returns The return value will contain the notifications specified in keys, in that
2382          *      order, or if keys is null, all the notifications, in natural order.
2383          */
2384         @Override
2385         public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
2386                 INotificationListener token, int trim) {
2387             synchronized (mNotificationLock) {
2388                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2389                 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
2390                 final int N = snoozedRecords.size();
2391                 final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
2392                 for (int i=0; i < N; i++) {
2393                     final NotificationRecord r = snoozedRecords.get(i);
2394                     if (r == null) continue;
2395                     StatusBarNotification sbn = r.sbn;
2396                     if (!isVisibleToListener(sbn, info)) continue;
2397                     StatusBarNotification sbnToSend =
2398                             (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2399                     list.add(sbnToSend);
2400                 }
2401                 return new ParceledListSlice<>(list);
2402             }
2403         }
2404
2405         @Override
2406         public void requestHintsFromListener(INotificationListener token, int hints) {
2407             final long identity = Binder.clearCallingIdentity();
2408             try {
2409                 synchronized (mNotificationLock) {
2410                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2411                     final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
2412                             | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
2413                             | HINT_HOST_DISABLE_CALL_EFFECTS;
2414                     final boolean disableEffects = (hints & disableEffectsMask) != 0;
2415                     if (disableEffects) {
2416                         addDisabledHints(info, hints);
2417                     } else {
2418                         removeDisabledHints(info, hints);
2419                     }
2420                     updateListenerHintsLocked();
2421                     updateEffectsSuppressorLocked();
2422                 }
2423             } finally {
2424                 Binder.restoreCallingIdentity(identity);
2425             }
2426         }
2427
2428         @Override
2429         public int getHintsFromListener(INotificationListener token) {
2430             synchronized (mNotificationLock) {
2431                 return mListenerHints;
2432             }
2433         }
2434
2435         @Override
2436         public void requestInterruptionFilterFromListener(INotificationListener token,
2437                 int interruptionFilter) throws RemoteException {
2438             final long identity = Binder.clearCallingIdentity();
2439             try {
2440                 synchronized (mNotificationLock) {
2441                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2442                     mZenModeHelper.requestFromListener(info.component, interruptionFilter);
2443                     updateInterruptionFilterLocked();
2444                 }
2445             } finally {
2446                 Binder.restoreCallingIdentity(identity);
2447             }
2448         }
2449
2450         @Override
2451         public int getInterruptionFilterFromListener(INotificationListener token)
2452                 throws RemoteException {
2453             synchronized (mNotificationLight) {
2454                 return mInterruptionFilter;
2455             }
2456         }
2457
2458         @Override
2459         public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
2460                 throws RemoteException {
2461             synchronized (mNotificationLock) {
2462                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2463                 if (info == null) return;
2464                 mListeners.setOnNotificationPostedTrimLocked(info, trim);
2465             }
2466         }
2467
2468         @Override
2469         public int getZenMode() {
2470             return mZenModeHelper.getZenMode();
2471         }
2472
2473         @Override
2474         public ZenModeConfig getZenModeConfig() {
2475             enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
2476             return mZenModeHelper.getConfig();
2477         }
2478
2479         @Override
2480         public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
2481             enforceSystemOrSystemUI("INotificationManager.setZenMode");
2482             final long identity = Binder.clearCallingIdentity();
2483             try {
2484                 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
2485             } finally {
2486                 Binder.restoreCallingIdentity(identity);
2487             }
2488         }
2489
2490         @Override
2491         public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
2492             enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
2493             return mZenModeHelper.getZenRules();
2494         }
2495
2496         @Override
2497         public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
2498             Preconditions.checkNotNull(id, "Id is null");
2499             enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
2500             return mZenModeHelper.getAutomaticZenRule(id);
2501         }
2502
2503         @Override
2504         public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
2505                 throws RemoteException {
2506             Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2507             Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2508             Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2509             Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2510             enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
2511
2512             return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
2513                     "addAutomaticZenRule");
2514         }
2515
2516         @Override
2517         public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
2518                 throws RemoteException {
2519             Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2520             Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2521             Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2522             Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2523             enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
2524
2525             return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
2526                     "updateAutomaticZenRule");
2527         }
2528
2529         @Override
2530         public boolean removeAutomaticZenRule(String id) throws RemoteException {
2531             Preconditions.checkNotNull(id, "Id is null");
2532             // Verify that they can modify zen rules.
2533             enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
2534
2535             return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
2536         }
2537
2538         @Override
2539         public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
2540             Preconditions.checkNotNull(packageName, "Package name is null");
2541             enforceSystemOrSystemUI("removeAutomaticZenRules");
2542
2543             return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
2544         }
2545
2546         @Override
2547         public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
2548             Preconditions.checkNotNull(owner, "Owner is null");
2549             enforceSystemOrSystemUI("getRuleInstanceCount");
2550
2551             return mZenModeHelper.getCurrentInstanceCount(owner);
2552         }
2553
2554         @Override
2555         public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
2556             enforcePolicyAccess(pkg, "setInterruptionFilter");
2557             final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
2558             if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
2559             final long identity = Binder.clearCallingIdentity();
2560             try {
2561                 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
2562             } finally {
2563                 Binder.restoreCallingIdentity(identity);
2564             }
2565         }
2566
2567         @Override
2568         public void notifyConditions(final String pkg, IConditionProvider provider,
2569                 final Condition[] conditions) {
2570             final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2571             checkCallerIsSystemOrSameApp(pkg);
2572             mHandler.post(new Runnable() {
2573                 @Override
2574                 public void run() {
2575                     mConditionProviders.notifyConditions(pkg, info, conditions);
2576                 }
2577             });
2578         }
2579
2580         @Override
2581         public void requestUnbindProvider(IConditionProvider provider) {
2582             long identity = Binder.clearCallingIdentity();
2583             try {
2584                 // allow bound services to disable themselves
2585                 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2586                 info.getOwner().setComponentState(info.component, false);
2587             } finally {
2588                 Binder.restoreCallingIdentity(identity);
2589             }
2590         }
2591
2592         @Override
2593         public void requestBindProvider(ComponentName component) {
2594             checkCallerIsSystemOrSameApp(component.getPackageName());
2595             long identity = Binder.clearCallingIdentity();
2596             try {
2597                 mConditionProviders.setComponentState(component, true);
2598             } finally {
2599                 Binder.restoreCallingIdentity(identity);
2600             }
2601         }
2602
2603         private void enforceSystemOrSystemUI(String message) {
2604             if (isCallerSystemOrPhone()) return;
2605             getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
2606                     message);
2607         }
2608
2609         private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
2610             try {
2611                 checkCallerIsSystemOrSameApp(pkg);
2612             } catch (SecurityException e) {
2613                 getContext().enforceCallingPermission(
2614                         android.Manifest.permission.STATUS_BAR_SERVICE,
2615                         message);
2616             }
2617         }
2618
2619         private void enforcePolicyAccess(int uid, String method) {
2620             if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2621                     android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2622                 return;
2623             }
2624             boolean accessAllowed = false;
2625             String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
2626             final int packageCount = packages.length;
2627             for (int i = 0; i < packageCount; i++) {
2628                 if (mConditionProviders.isPackageOrComponentAllowed(
2629                         packages[i], UserHandle.getUserId(uid))) {
2630                     accessAllowed = true;
2631                 }
2632             }
2633             if (!accessAllowed) {
2634                 Slog.w(TAG, "Notification policy access denied calling " + method);
2635                 throw new SecurityException("Notification policy access denied");
2636             }
2637         }
2638
2639         private void enforcePolicyAccess(String pkg, String method) {
2640             if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2641                     android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2642                 return;
2643             }
2644             checkCallerIsSameApp(pkg);
2645             if (!checkPolicyAccess(pkg)) {
2646                 Slog.w(TAG, "Notification policy access denied calling " + method);
2647                 throw new SecurityException("Notification policy access denied");
2648             }
2649         }
2650
2651         private boolean checkPackagePolicyAccess(String pkg) {
2652             return mConditionProviders.isPackageOrComponentAllowed(
2653                     pkg, getCallingUserHandle().getIdentifier());
2654         }
2655
2656         private boolean checkPolicyAccess(String pkg) {
2657             try {
2658                 int uid = getContext().getPackageManager().getPackageUidAsUser(
2659                         pkg, UserHandle.getCallingUserId());
2660                 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
2661                         android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
2662                         -1, true)) {
2663                     return true;
2664                 }
2665             } catch (NameNotFoundException e) {
2666                 return false;
2667             }
2668             return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
2669         }
2670
2671         @Override
2672         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2673             if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
2674             final DumpFilter filter = DumpFilter.parseFromArguments(args);
2675             if (filter != null && filter.stats) {
2676                 dumpJson(pw, filter);
2677             } else if (filter != null && filter.proto) {
2678                 dumpProto(fd, filter);
2679             } else {
2680                 dumpImpl(pw, filter);
2681             }
2682         }
2683
2684         @Override
2685         public ComponentName getEffectsSuppressor() {
2686             return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
2687         }
2688
2689         @Override
2690         public boolean matchesCallFilter(Bundle extras) {
2691             enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
2692             return mZenModeHelper.matchesCallFilter(
2693                     Binder.getCallingUserHandle(),
2694                     extras,
2695                     mRankingHelper.findExtractor(ValidateNotificationPeople.class),
2696                     MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
2697                     MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
2698         }
2699
2700         @Override
2701         public boolean isSystemConditionProviderEnabled(String path) {
2702             enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
2703             return mConditionProviders.isSystemProviderEnabled(path);
2704         }
2705
2706         // Backup/restore interface
2707         @Override
2708         public byte[] getBackupPayload(int user) {
2709             if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
2710             //TODO: http://b/22388012
2711             if (user != UserHandle.USER_SYSTEM) {
2712                 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
2713                 return null;
2714             }
2715             synchronized(mPolicyFile) {
2716                 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
2717                 try {
2718                     writePolicyXml(baos, true /*forBackup*/);
2719                     return baos.toByteArray();
2720                 } catch (IOException e) {
2721                     Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
2722                 }
2723             }
2724             return null;
2725         }
2726
2727         @Override
2728         public void applyRestore(byte[] payload, int user) {
2729             if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
2730                     + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
2731             if (payload == null) {
2732                 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
2733                 return;
2734             }
2735             //TODO: http://b/22388012
2736             if (user != UserHandle.USER_SYSTEM) {
2737                 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
2738                 return;
2739             }
2740             synchronized(mPolicyFile) {
2741                 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
2742                 try {
2743                     readPolicyXml(bais, true /*forRestore*/);
2744                     savePolicyFile();
2745                 } catch (NumberFormatException | XmlPullParserException | IOException e) {
2746                     Slog.w(TAG, "applyRestore: error reading payload", e);
2747                 }
2748             }
2749         }
2750
2751         @Override
2752         public boolean isNotificationPolicyAccessGranted(String pkg) {
2753             return checkPolicyAccess(pkg);
2754         }
2755
2756         @Override
2757         public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
2758             enforceSystemOrSystemUIOrSamePackage(pkg,
2759                     "request policy access status for another package");
2760             return checkPolicyAccess(pkg);
2761         }
2762
2763         @Override
2764         public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
2765                 throws RemoteException {
2766             setNotificationPolicyAccessGrantedForUser(
2767                     pkg, getCallingUserHandle().getIdentifier(), granted);
2768         }
2769
2770         @Override
2771         public void setNotificationPolicyAccessGrantedForUser(
2772                 String pkg, int userId, boolean granted) {
2773             checkCallerIsSystemOrShell();
2774             final long identity = Binder.clearCallingIdentity();
2775             try {
2776                 if (!mActivityManager.isLowRamDevice()) {
2777                     mConditionProviders.setPackageOrComponentEnabled(
2778                             pkg, userId, true, granted);
2779
2780                     getContext().sendBroadcastAsUser(new Intent(
2781                             NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
2782                                     .setPackage(pkg)
2783                                     .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
2784                             UserHandle.of(userId), null);
2785                     savePolicyFile();
2786                 }
2787             } finally {
2788                 Binder.restoreCallingIdentity(identity);
2789             }
2790         }
2791
2792         @Override
2793         public Policy getNotificationPolicy(String pkg) {
2794             enforcePolicyAccess(pkg, "getNotificationPolicy");
2795             final long identity = Binder.clearCallingIdentity();
2796             try {
2797                 return mZenModeHelper.getNotificationPolicy();
2798             } finally {
2799                 Binder.restoreCallingIdentity(identity);
2800             }
2801         }
2802
2803         @Override
2804         public void setNotificationPolicy(String pkg, Policy policy) {
2805             enforcePolicyAccess(pkg, "setNotificationPolicy");
2806             final long identity = Binder.clearCallingIdentity();
2807             try {
2808                 mZenModeHelper.setNotificationPolicy(policy);
2809             } finally {
2810                 Binder.restoreCallingIdentity(identity);
2811             }
2812         }
2813
2814         @Override
2815         public List<String> getEnabledNotificationListenerPackages() {
2816             checkCallerIsSystem();
2817             return mListeners.getAllowedPackages(getCallingUserHandle().getIdentifier());
2818         }
2819
2820         @Override
2821         public List<ComponentName> getEnabledNotificationListeners(int userId) {
2822             checkCallerIsSystem();
2823             return mListeners.getAllowedComponents(userId);
2824         }
2825
2826         @Override
2827         public boolean isNotificationListenerAccessGranted(ComponentName listener) {
2828             Preconditions.checkNotNull(listener);
2829             checkCallerIsSystemOrSameApp(listener.getPackageName());
2830             return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
2831                     getCallingUserHandle().getIdentifier());
2832         }
2833
2834         @Override
2835         public boolean isNotificationListenerAccessGrantedForUser(ComponentName listener,
2836                 int userId) {
2837             Preconditions.checkNotNull(listener);
2838             checkCallerIsSystem();
2839             return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
2840                     userId);
2841         }
2842
2843         @Override
2844         public boolean isNotificationAssistantAccessGranted(ComponentName assistant) {
2845             Preconditions.checkNotNull(assistant);
2846             checkCallerIsSystemOrSameApp(assistant.getPackageName());
2847             return mAssistants.isPackageOrComponentAllowed(assistant.flattenToString(),
2848                     getCallingUserHandle().getIdentifier());
2849         }
2850
2851         @Override
2852         public void setNotificationListenerAccessGranted(ComponentName listener,
2853                 boolean granted) throws RemoteException {
2854             setNotificationListenerAccessGrantedForUser(
2855                     listener, getCallingUserHandle().getIdentifier(), granted);
2856         }
2857
2858         @Override
2859         public void setNotificationAssistantAccessGranted(ComponentName assistant,
2860                 boolean granted) throws RemoteException {
2861             setNotificationAssistantAccessGrantedForUser(
2862                     assistant, getCallingUserHandle().getIdentifier(), granted);
2863         }
2864
2865         @Override
2866         public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
2867                 boolean granted) throws RemoteException {
2868             Preconditions.checkNotNull(listener);
2869             checkCallerIsSystemOrShell();
2870             final long identity = Binder.clearCallingIdentity();
2871             try {
2872                 if (!mActivityManager.isLowRamDevice()) {
2873                     mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
2874                             userId, false, granted);
2875                     mListeners.setPackageOrComponentEnabled(listener.flattenToString(),
2876                             userId, true, granted);
2877
2878                     getContext().sendBroadcastAsUser(new Intent(
2879                             NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
2880                                     .setPackage(listener.getPackageName())
2881                                     .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
2882                             UserHandle.of(userId), null);
2883
2884                     savePolicyFile();
2885                 }
2886             } finally {
2887                 Binder.restoreCallingIdentity(identity);
2888             }
2889         }
2890
2891         @Override
2892         public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
2893                 int userId, boolean granted) throws RemoteException {
2894             Preconditions.checkNotNull(assistant);
2895             checkCallerIsSystemOrShell();
2896             final long identity = Binder.clearCallingIdentity();
2897             try {
2898                 if (!mActivityManager.isLowRamDevice()) {
2899                     mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
2900                             userId, false, granted);
2901                     mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
2902                             userId, true, granted);
2903
2904                     getContext().sendBroadcastAsUser(new Intent(
2905                             NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
2906                                     .setPackage(assistant.getPackageName())
2907                                     .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
2908                             UserHandle.of(userId), null);
2909
2910                     savePolicyFile();
2911                 }
2912             } finally {
2913                 Binder.restoreCallingIdentity(identity);
2914             }
2915         }
2916
2917         @Override
2918         public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
2919                 Adjustment adjustment) throws RemoteException {
2920             final long identity = Binder.clearCallingIdentity();
2921             try {
2922                 synchronized (mNotificationLock) {
2923                     mAssistants.checkServiceTokenLocked(token);
2924                     int N = mEnqueuedNotifications.size();
2925                     for (int i = 0; i < N; i++) {
2926                         final NotificationRecord n = mEnqueuedNotifications.get(i);
2927                         if (Objects.equals(adjustment.getKey(), n.getKey())
2928                                 && Objects.equals(adjustment.getUser(), n.getUserId())) {
2929                             applyAdjustment(n, adjustment);
2930                             break;
2931                         }
2932                     }
2933                 }
2934             } finally {
2935                 Binder.restoreCallingIdentity(identity);
2936             }
2937         }
2938
2939         @Override
2940         public void applyAdjustmentFromAssistant(INotificationListener token,
2941                 Adjustment adjustment) throws RemoteException {
2942             final long identity = Binder.clearCallingIdentity();
2943             try {
2944                 synchronized (mNotificationLock) {
2945                     mAssistants.checkServiceTokenLocked(token);
2946                     NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2947                     applyAdjustment(n, adjustment);
2948                 }
2949                 mRankingHandler.requestSort();
2950             } finally {
2951                 Binder.restoreCallingIdentity(identity);
2952             }
2953         }
2954
2955         @Override
2956         public void applyAdjustmentsFromAssistant(INotificationListener token,
2957                 List<Adjustment> adjustments) throws RemoteException {
2958
2959             final long identity = Binder.clearCallingIdentity();
2960             try {
2961                 synchronized (mNotificationLock) {
2962                     mAssistants.checkServiceTokenLocked(token);
2963                     for (Adjustment adjustment : adjustments) {
2964                         NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2965                         applyAdjustment(n, adjustment);
2966                     }
2967                 }
2968                 mRankingHandler.requestSort();
2969             } finally {
2970                 Binder.restoreCallingIdentity(identity);
2971             }
2972         }
2973
2974         @Override
2975         public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
2976                 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
2977             Preconditions.checkNotNull(channel);
2978             Preconditions.checkNotNull(pkg);
2979             Preconditions.checkNotNull(user);
2980
2981             verifyPrivilegedListener(token, user);
2982             updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
2983         }
2984
2985         @Override
2986         public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
2987                 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
2988             Preconditions.checkNotNull(pkg);
2989             Preconditions.checkNotNull(user);
2990             verifyPrivilegedListener(token, user);
2991
2992             return mRankingHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user),
2993                     false /* includeDeleted */);
2994         }
2995
2996         @Override
2997         public ParceledListSlice<NotificationChannelGroup>
2998                 getNotificationChannelGroupsFromPrivilegedListener(
2999                 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
3000             Preconditions.checkNotNull(pkg);
3001             Preconditions.checkNotNull(user);
3002             verifyPrivilegedListener(token, user);
3003
3004             List<NotificationChannelGroup> groups = new ArrayList<>();
3005             groups.addAll(mRankingHelper.getNotificationChannelGroups(
3006                     pkg, getUidForPackageAndUser(pkg, user)));
3007             return new ParceledListSlice<>(groups);
3008         }
3009
3010         private void verifyPrivilegedListener(INotificationListener token, UserHandle user) {
3011             ManagedServiceInfo info;
3012             synchronized (mNotificationLock) {
3013                 info = mListeners.checkServiceTokenLocked(token);
3014             }
3015             if (!hasCompanionDevice(info)) {
3016                 throw new SecurityException(info + " does not have access");
3017             }
3018             if (!info.enabledAndUserMatches(user.getIdentifier())) {
3019                 throw new SecurityException(info + " does not have access");
3020             }
3021         }
3022
3023         private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
3024             int uid = 0;
3025             long identity = Binder.clearCallingIdentity();
3026             try {
3027                 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
3028             } finally {
3029                 Binder.restoreCallingIdentity(identity);
3030             }
3031             return uid;
3032         }
3033
3034         @Override
3035         public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
3036                 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
3037                 throws RemoteException {
3038             new ShellCmd().exec(this, in, out, err, args, callback, resultReceiver);
3039         }
3040     };
3041
3042     private void applyAdjustment(NotificationRecord r, Adjustment adjustment) {
3043         if (r == null) {
3044             return;
3045         }
3046         if (adjustment.getSignals() != null) {
3047             Bundle.setDefusable(adjustment.getSignals(), true);
3048             r.addAdjustment(adjustment);
3049         }
3050     }
3051
3052     @GuardedBy("mNotificationLock")
3053     void addAutogroupKeyLocked(String key) {
3054         NotificationRecord r = mNotificationsByKey.get(key);
3055         if (r == null) {
3056             return;
3057         }
3058         if (r.sbn.getOverrideGroupKey() == null) {
3059             addAutoGroupAdjustment(r, GroupHelper.AUTOGROUP_KEY);
3060             EventLogTags.writeNotificationAutogrouped(key);
3061             mRankingHandler.requestSort();
3062         }
3063     }
3064
3065     @GuardedBy("mNotificationLock")
3066     void removeAutogroupKeyLocked(String key) {
3067         NotificationRecord r = mNotificationsByKey.get(key);
3068         if (r == null) {
3069             return;
3070         }
3071         if (r.sbn.getOverrideGroupKey() != null) {
3072             addAutoGroupAdjustment(r, null);
3073             EventLogTags.writeNotificationUnautogrouped(key);
3074             mRankingHandler.requestSort();
3075         }
3076     }
3077
3078     private void addAutoGroupAdjustment(NotificationRecord r, String overrideGroupKey) {
3079         Bundle signals = new Bundle();
3080         signals.putString(Adjustment.KEY_GROUP_KEY, overrideGroupKey);
3081         Adjustment adjustment =
3082                 new Adjustment(r.sbn.getPackageName(), r.getKey(), signals, "", r.sbn.getUserId());
3083         r.addAdjustment(adjustment);
3084     }
3085
3086     // Clears the 'fake' auto-group summary.
3087     @GuardedBy("mNotificationLock")
3088     private void clearAutogroupSummaryLocked(int userId, String pkg) {
3089         ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3090         if (summaries != null && summaries.containsKey(pkg)) {
3091             // Clear summary.
3092             final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
3093             if (removed != null) {
3094                 boolean wasPosted = removeFromNotificationListsLocked(removed);
3095                 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED, wasPosted, null);
3096             }
3097         }
3098     }
3099
3100     @GuardedBy("mNotificationLock")
3101     private boolean hasAutoGroupSummaryLocked(StatusBarNotification sbn) {
3102         ArrayMap<String, String> summaries = mAutobundledSummaries.get(sbn.getUserId());
3103         return summaries != null && summaries.containsKey(sbn.getPackageName());
3104     }
3105
3106     // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
3107     private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
3108         NotificationRecord summaryRecord = null;
3109         synchronized (mNotificationLock) {
3110             NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
3111             if (notificationRecord == null) {
3112                 // The notification could have been cancelled again already. A successive
3113                 // adjustment will post a summary if needed.
3114                 return;
3115             }
3116             final StatusBarNotification adjustedSbn = notificationRecord.sbn;
3117             userId = adjustedSbn.getUser().getIdentifier();
3118             ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3119             if (summaries == null) {
3120                 summaries = new ArrayMap<>();
3121             }
3122             mAutobundledSummaries.put(userId, summaries);
3123             if (!summaries.containsKey(pkg)) {
3124                 // Add summary
3125                 final ApplicationInfo appInfo =
3126                        adjustedSbn.getNotification().extras.getParcelable(
3127                                Notification.EXTRA_BUILDER_APPLICATION_INFO);
3128                 final Bundle extras = new Bundle();
3129                 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
3130                 final String channelId = notificationRecord.getChannel().getId();
3131                 final Notification summaryNotification =
3132                         new Notification.Builder(getContext(), channelId)
3133                                 .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
3134                                 .setGroupSummary(true)
3135                                 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN)
3136                                 .setGroup(GroupHelper.AUTOGROUP_KEY)
3137                                 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
3138                                 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
3139                                 .setColor(adjustedSbn.getNotification().color)
3140                                 .setLocalOnly(true)
3141                                 .build();
3142                 summaryNotification.extras.putAll(extras);
3143                 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
3144                 if (appIntent != null) {
3145                     summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
3146                             getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
3147                 }
3148                 final StatusBarNotification summarySbn =
3149                         new StatusBarNotification(adjustedSbn.getPackageName(),
3150                                 adjustedSbn.getOpPkg(),
3151                                 Integer.MAX_VALUE,
3152                                 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
3153                                 adjustedSbn.getInitialPid(), summaryNotification,
3154                                 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
3155                                 System.currentTimeMillis());
3156                 summaryRecord = new NotificationRecord(getContext(), summarySbn,
3157                         notificationRecord.getChannel());
3158                 summaries.put(pkg, summarySbn.getKey());
3159             }
3160         }
3161         if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
3162                 summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord, true)) {
3163             mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
3164         }
3165     }
3166
3167     private String disableNotificationEffects(NotificationRecord record) {
3168         if (mDisableNotificationEffects) {
3169             return "booleanState";
3170         }
3171         if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
3172             return "listenerHints";
3173         }
3174         if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
3175             return "callState";
3176         }
3177         return null;
3178     };
3179
3180     private void dumpJson(PrintWriter pw, DumpFilter filter) {
3181         JSONObject dump = new JSONObject();
3182         try {
3183             dump.put("service", "Notification Manager");
3184             dump.put("bans", mRankingHelper.dumpBansJson(filter));
3185             dump.put("ranking", mRankingHelper.dumpJson(filter));
3186             dump.put("stats", mUsageStats.dumpJson(filter));
3187             dump.put("channels", mRankingHelper.dumpChannelsJson(filter));
3188         } catch (JSONException e) {
3189             e.printStackTrace();
3190         }
3191         pw.println(dump);
3192     }
3193
3194     private void dumpProto(FileDescriptor fd, DumpFilter filter) {
3195         final ProtoOutputStream proto = new ProtoOutputStream(fd);
3196         synchronized (mNotificationLock) {
3197             long records = proto.start(NotificationServiceDumpProto.RECORDS);
3198             int N = mNotificationList.size();
3199             if (N > 0) {
3200                 for (int i = 0; i < N; i++) {
3201                     final NotificationRecord nr = mNotificationList.get(i);
3202                     if (filter.filtered && !filter.matches(nr.sbn)) continue;
3203                     nr.dump(proto, filter.redact);
3204                     proto.write(NotificationRecordProto.STATE, NotificationServiceProto.POSTED);
3205                 }
3206             }
3207             N = mEnqueuedNotifications.size();
3208             if (N > 0) {
3209                 for (int i = 0; i < N; i++) {
3210                     final NotificationRecord nr = mEnqueuedNotifications.get(i);
3211                     if (filter.filtered && !filter.matches(nr.sbn)) continue;
3212                     nr.dump(proto, filter.redact);
3213                     proto.write(NotificationRecordProto.STATE, NotificationServiceProto.ENQUEUED);
3214                 }
3215             }
3216             List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
3217             N = snoozed.size();
3218             if (N > 0) {
3219                 for (int i = 0; i < N; i++) {
3220                     final NotificationRecord nr = snoozed.get(i);
3221                     if (filter.filtered && !filter.matches(nr.sbn)) continue;
3222                     nr.dump(proto, filter.redact);
3223                     proto.write(NotificationRecordProto.STATE, NotificationServiceProto.SNOOZED);
3224                 }
3225             }
3226             proto.end(records);
3227         }
3228
3229         long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
3230         mZenModeHelper.dump(proto);
3231         for (ComponentName suppressor : mEffectsSuppressors) {
3232             proto.write(ZenModeProto.SUPPRESSORS, suppressor.toString());
3233         }
3234         proto.end(zenLog);
3235
3236         proto.flush();
3237     }
3238
3239     void dumpImpl(PrintWriter pw, DumpFilter filter) {
3240         pw.print("Current Notification Manager state");
3241         if (filter.filtered) {
3242             pw.print(" (filtered to "); pw.print(filter); pw.print(")");
3243         }
3244         pw.println(':');
3245         int N;
3246         final boolean zenOnly = filter.filtered && filter.zen;
3247
3248         if (!zenOnly) {
3249             synchronized (mToastQueue) {
3250                 N = mToastQueue.size();
3251                 if (N > 0) {
3252                     pw.println("  Toast Queue:");
3253                     for (int i=0; i<N; i++) {
3254                         mToastQueue.get(i).dump(pw, "    ", filter);
3255                     }
3256                     pw.println("  ");
3257                 }
3258             }
3259         }
3260
3261         synchronized (mNotificationLock) {
3262             if (!zenOnly) {
3263                 N = mNotificationList.size();
3264                 if (N > 0) {
3265                     pw.println("  Notification List:");
3266                     for (int i=0; i<N; i++) {
3267                         final NotificationRecord nr = mNotificationList.get(i);
3268                         if (filter.filtered && !filter.matches(nr.sbn)) continue;
3269                         nr.dump(pw, "    ", getContext(), filter.redact);
3270                     }
3271                     pw.println("  ");
3272                 }
3273
3274                 if (!filter.filtered) {
3275                     N = mLights.size();
3276                     if (N > 0) {
3277                         pw.println("  Lights List:");
3278                         for (int i=0; i<N; i++) {
3279                             if (i == N - 1) {
3280                                 pw.print("  > ");
3281                             } else {
3282                                 pw.print("    ");
3283                             }
3284                             pw.println(mLights.get(i));
3285                         }
3286                         pw.println("  ");
3287                     }
3288                     pw.println("  mUseAttentionLight=" + mUseAttentionLight);
3289                     pw.println("  mNotificationPulseEnabled=" + mNotificationPulseEnabled);
3290                     pw.println("  mSoundNotificationKey=" + mSoundNotificationKey);
3291                     pw.println("  mVibrateNotificationKey=" + mVibrateNotificationKey);
3292                     pw.println("  mDisableNotificationEffects=" + mDisableNotificationEffects);
3293                     pw.println("  mCallState=" + callStateToString(mCallState));
3294                     pw.println("  mSystemReady=" + mSystemReady);
3295                     pw.println("  mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
3296                 }
3297                 pw.println("  mArchive=" + mArchive.toString());
3298                 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
3299                 int j=0;
3300                 while (iter.hasNext()) {
3301                     final StatusBarNotification sbn = iter.next();
3302                     if (filter != null && !filter.matches(sbn)) continue;
3303                     pw.println("    " + sbn);
3304                     if (++j >= 5) {
3305                         if (iter.hasNext()) pw.println("    ...");
3306                         break;
3307                     }
3308                 }
3309
3310                 if (!zenOnly) {
3311                     N = mEnqueuedNotifications.size();
3312                     if (N > 0) {
3313                         pw.println("  Enqueued Notification List:");
3314                         for (int i = 0; i < N; i++) {
3315                             final NotificationRecord nr = mEnqueuedNotifications.get(i);
3316                             if (filter.filtered && !filter.matches(nr.sbn)) continue;
3317                             nr.dump(pw, "    ", getContext(), filter.redact);
3318                         }
3319                         pw.println("  ");
3320                     }
3321
3322                     mSnoozeHelper.dump(pw, filter);
3323                 }
3324             }
3325
3326             if (!zenOnly) {
3327                 pw.println("\n  Ranking Config:");
3328                 mRankingHelper.dump(pw, "    ", filter);
3329
3330                 pw.println("\n  Notification listeners:");
3331                 mListeners.dump(pw, filter);
3332                 pw.print("    mListenerHints: "); pw.println(mListenerHints);
3333                 pw.print("    mListenersDisablingEffects: (");
3334                 N = mListenersDisablingEffects.size();
3335                 for (int i = 0; i < N; i++) {
3336                     final int hint = mListenersDisablingEffects.keyAt(i);
3337                     if (i > 0) pw.print(';');
3338                     pw.print("hint[" + hint + "]:");
3339
3340                     final ArraySet<ManagedServiceInfo> listeners =
3341                             mListenersDisablingEffects.valueAt(i);
3342                     final int listenerSize = listeners.size();
3343
3344                     for (int j = 0; j < listenerSize; j++) {
3345                         if (i > 0) pw.print(',');
3346                         final ManagedServiceInfo listener = listeners.valueAt(i);
3347                         pw.print(listener.component);
3348                     }
3349                 }
3350                 pw.println(')');
3351                 pw.println("\n  Notification assistant services:");
3352                 mAssistants.dump(pw, filter);
3353             }
3354
3355             if (!filter.filtered || zenOnly) {
3356                 pw.println("\n  Zen Mode:");
3357                 pw.print("    mInterruptionFilter="); pw.println(mInterruptionFilter);
3358                 mZenModeHelper.dump(pw, "    ");
3359
3360                 pw.println("\n  Zen Log:");
3361                 ZenLog.dump(pw, "    ");
3362             }
3363
3364             pw.println("\n  Condition providers:");
3365             mConditionProviders.dump(pw, filter);
3366
3367             pw.println("\n  Group summaries:");
3368             for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
3369                 NotificationRecord r = entry.getValue();
3370                 pw.println("    " + entry.getKey() + " -> " + r.getKey());
3371                 if (mNotificationsByKey.get(r.getKey()) != r) {
3372                     pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
3373                     r.dump(pw, "      ", getContext(), filter.redact);
3374                 }
3375             }
3376
3377             if (!zenOnly) {
3378                 pw.println("\n  Usage Stats:");
3379                 mUsageStats.dump(pw, "    ", filter);
3380             }
3381         }
3382     }
3383
3384     /**
3385      * The private API only accessible to the system process.
3386      */
3387     private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
3388         @Override
3389         public NotificationChannel getNotificationChannel(String pkg, int uid, String
3390                 channelId) {
3391             return mRankingHelper.getNotificationChannel(pkg, uid, channelId, false);
3392         }
3393
3394         @Override
3395         public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
3396                 String tag, int id, Notification notification, int userId) {
3397             enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
3398                     userId);
3399         }
3400
3401         @Override
3402         public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
3403                 int userId) {
3404             checkCallerIsSystem();
3405             mHandler.post(new Runnable() {
3406                 @Override
3407                 public void run() {
3408                     synchronized (mNotificationLock) {
3409                         removeForegroundServiceFlagByListLocked(
3410                                 mEnqueuedNotifications, pkg, notificationId, userId);
3411                         removeForegroundServiceFlagByListLocked(
3412                                 mNotificationList, pkg, notificationId, userId);
3413                     }
3414                 }
3415             });
3416         }
3417
3418         @GuardedBy("mNotificationLock")
3419         private void removeForegroundServiceFlagByListLocked(
3420                 ArrayList<NotificationRecord> notificationList, String pkg, int notificationId,
3421                 int userId) {
3422             NotificationRecord r = findNotificationByListLocked(
3423                     notificationList, pkg, null, notificationId, userId);
3424             if (r == null) {
3425                 return;
3426             }
3427             StatusBarNotification sbn = r.sbn;
3428             // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
3429             // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
3430             // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
3431             // initially *and* force remove FLAG_FOREGROUND_SERVICE.
3432             sbn.getNotification().flags =
3433                     (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
3434             mRankingHelper.sort(mNotificationList);
3435             mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
3436         }
3437     };
3438
3439     void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
3440             final int callingPid, final String tag, final int id, final Notification notification,
3441             int incomingUserId) {
3442         if (DBG) {
3443             Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
3444                     + " notification=" + notification);
3445         }
3446         checkCallerIsSystemOrSameApp(pkg);
3447
3448         final int userId = ActivityManager.handleIncomingUser(callingPid,
3449                 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
3450         final UserHandle user = new UserHandle(userId);
3451
3452         if (pkg == null || notification == null) {
3453             throw new IllegalArgumentException("null not allowed: pkg=" + pkg
3454                     + " id=" + id + " notification=" + notification);
3455         }
3456
3457         // The system can post notifications for any package, let us resolve that.
3458         final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);
3459
3460         // Fix the notification as best we can.
3461         try {
3462             final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
3463                     pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
3464                     (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
3465             Notification.addFieldsFromContext(ai, notification);
3466
3467             int canColorize = mPackageManagerClient.checkPermission(
3468                     android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, pkg);
3469             if (canColorize == PERMISSION_GRANTED) {
3470                 notification.flags |= Notification.FLAG_CAN_COLORIZE;
3471             } else {
3472                 notification.flags &= ~Notification.FLAG_CAN_COLORIZE;
3473             }
3474
3475         } catch (NameNotFoundException e) {
3476             Slog.e(TAG, "Cannot create a context for sending app", e);
3477             return;
3478         }
3479
3480         mUsageStats.registerEnqueuedByApp(pkg);
3481
3482         // setup local book-keeping
3483         String channelId = notification.getChannelId();
3484         if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
3485             channelId = (new Notification.TvExtender(notification)).getChannelId();
3486         }
3487         final NotificationChannel channel = mRankingHelper.getNotificationChannel(pkg,
3488                 notificationUid, channelId, false /* includeDeleted */);
3489         if (channel == null) {
3490             final String noChannelStr = "No Channel found for "
3491                     + "pkg=" + pkg
3492                     + ", channelId=" + channelId
3493                     + ", id=" + id
3494                     + ", tag=" + tag
3495                     + ", opPkg=" + opPkg
3496                     + ", callingUid=" + callingUid
3497                     + ", userId=" + userId
3498                     + ", incomingUserId=" + incomingUserId
3499                     + ", notificationUid=" + notificationUid
3500                     + ", notification=" + notification;
3501             Log.e(TAG, noChannelStr);
3502             doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
3503                     "Failed to post notification on channel \"" + channelId + "\"\n" +
3504                     "See log for more details");
3505             return;
3506         }
3507
3508         final StatusBarNotification n = new StatusBarNotification(
3509                 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
3510                 user, null, System.currentTimeMillis());
3511         final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
3512
3513         if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0
3514                 && (channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
3515                 && (r.getImportance() == IMPORTANCE_MIN || r.getImportance() == IMPORTANCE_NONE)) {
3516             // Increase the importance of foreground service notifications unless the user had an
3517             // opinion otherwise
3518             if (TextUtils.isEmpty(channelId)
3519                     || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
3520                 r.setImportance(IMPORTANCE_LOW, "Bumped for foreground service");
3521             } else {
3522                 channel.setImportance(IMPORTANCE_LOW);
3523                 mRankingHelper.updateNotificationChannel(pkg, notificationUid, channel, false);
3524                 r.updateNotificationChannel(channel);
3525             }
3526         }
3527
3528         if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
3529                 r.sbn.getOverrideGroupKey() != null)) {
3530             return;
3531         }
3532
3533         // Whitelist pending intents.
3534         if (notification.allPendingIntents != null) {
3535             final int intentCount = notification.allPendingIntents.size();
3536             if (intentCount > 0) {
3537                 final ActivityManagerInternal am = LocalServices
3538                         .getService(ActivityManagerInternal.class);
3539                 final long duration = LocalServices.getService(
3540                         DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
3541                 for (int i = 0; i < intentCount; i++) {
3542                     PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
3543                     if (pendingIntent != null) {
3544                         am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
3545                                 WHITELIST_TOKEN, duration);
3546                     }
3547                 }
3548             }
3549         }
3550
3551         mHandler.post(new EnqueueNotificationRunnable(userId, r));
3552     }
3553
3554     private void doChannelWarningToast(CharSequence toastText) {
3555         final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
3556         final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
3557                 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
3558         if (warningEnabled) {
3559             Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
3560                     Toast.LENGTH_SHORT);
3561             toast.show();
3562         }
3563     }
3564
3565     private int resolveNotificationUid(String opPackageName, int callingUid, int userId) {
3566         // The system can post notifications on behalf of any package it wants
3567         if (isCallerSystemOrPhone() && opPackageName != null && !"android".equals(opPackageName)) {
3568             try {
3569                 return getContext().getPackageManager()
3570                         .getPackageUidAsUser(opPackageName, userId);
3571             } catch (NameNotFoundException e) {
3572                 /* ignore */
3573             }
3574         }
3575         return callingUid;
3576     }
3577
3578     /**
3579      * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
3580      *
3581      * Has side effects.
3582      */
3583     private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag,
3584             NotificationRecord r, boolean isAutogroup) {
3585         final String pkg = r.sbn.getPackageName();
3586         final String dialerPackage =
3587                 getContext().getSystemService(TelecomManager.class).getSystemDialerPackage();
3588         final boolean isSystemNotification =
3589                 isUidSystemOrPhone(callingUid) || ("android".equals(pkg))
3590                 || TextUtils.equals(pkg, dialerPackage);
3591         final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
3592
3593         // Limit the number of notifications that any given package except the android
3594         // package or a registered listener can enqueue.  Prevents DOS attacks and deals with leaks.
3595         if (!isSystemNotification && !isNotificationFromListener) {
3596             synchronized (mNotificationLock) {
3597                 if (mNotificationsByKey.get(r.sbn.getKey()) == null && isCallerInstantApp(pkg)) {
3598                     // Ephemeral apps have some special constraints for notifications.
3599                     // They are not allowed to create new notifications however they are allowed to
3600                     // update notifications created by the system (e.g. a foreground service
3601                     // notification).
3602                     throw new SecurityException("Instant app " + pkg
3603                             + " cannot create notifications");
3604                 }
3605
3606                 // rate limit updates that aren't completed progress notifications
3607                 if (mNotificationsByKey.get(r.sbn.getKey()) != null
3608                         && !r.getNotification().hasCompletedProgress()
3609                         && !isAutogroup) {
3610
3611                     final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
3612                     if (appEnqueueRate > mMaxPackageEnqueueRate) {
3613                         mUsageStats.registerOverRateQuota(pkg);
3614                         final long now = SystemClock.elapsedRealtime();
3615                         if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
3616                             Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
3617                                     + ". Shedding " + r.sbn.getKey() + ". package=" + pkg);
3618                             mLastOverRateLogTime = now;
3619                         }
3620                         return false;
3621                     }
3622                 }
3623
3624                 // limit the number of outstanding notificationrecords an app can have
3625                 int count = getNotificationCountLocked(pkg, userId, id, tag);
3626                 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
3627                     mUsageStats.registerOverCountQuota(pkg);
3628                     Slog.e(TAG, "Package has already posted or enqueued " + count
3629                             + " notifications.  Not showing more.  package=" + pkg);
3630                     return false;
3631                 }
3632             }
3633         }
3634
3635         // snoozed apps
3636         if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
3637             MetricsLogger.action(r.getLogMaker()
3638                     .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
3639                     .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
3640             if (DBG) {
3641                 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
3642             }
3643             mSnoozeHelper.update(userId, r);
3644             savePolicyFile();
3645             return false;
3646         }
3647
3648
3649         // blocked apps
3650         if (isBlocked(r, mUsageStats)) {
3651             return false;
3652         }
3653
3654         return true;
3655     }
3656
3657     protected int getNotificationCountLocked(String pkg, int userId, int excludedId,
3658             String excludedTag) {
3659         int count = 0;
3660         final int N = mNotificationList.size();
3661         for (int i = 0; i < N; i++) {
3662             final NotificationRecord existing = mNotificationList.get(i);
3663             if (existing.sbn.getPackageName().equals(pkg)
3664                     && existing.sbn.getUserId() == userId) {
3665                 if (existing.sbn.getId() == excludedId
3666                         && TextUtils.equals(existing.sbn.getTag(), excludedTag)) {
3667                     continue;
3668                 }
3669                 count++;
3670             }
3671         }
3672         final int M = mEnqueuedNotifications.size();
3673         for (int i = 0; i < M; i++) {
3674             final NotificationRecord existing = mEnqueuedNotifications.get(i);
3675             if (existing.sbn.getPackageName().equals(pkg)
3676                     && existing.sbn.getUserId() == userId) {
3677                 count++;
3678             }
3679         }
3680         return count;
3681     }
3682
3683     protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
3684         final String pkg = r.sbn.getPackageName();
3685         final int callingUid = r.sbn.getUid();
3686
3687         final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
3688         if (isPackageSuspended) {
3689             Slog.e(TAG, "Suppressing notification from package due to package "
3690                     + "suspended by administrator.");
3691             usageStats.registerSuspendedByAdmin(r);
3692             return isPackageSuspended;
3693         }
3694
3695         final boolean isBlocked =
3696                 mRankingHelper.getImportance(pkg, callingUid) == NotificationManager.IMPORTANCE_NONE
3697                 || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE;
3698         if (isBlocked) {
3699             Slog.e(TAG, "Suppressing notification from package by user request.");
3700             usageStats.registerBlocked(r);
3701         }
3702         return isBlocked;
3703     }
3704
3705     protected class SnoozeNotificationRunnable implements Runnable {
3706         private final String mKey;
3707         private final long mDuration;
3708         private final String mSnoozeCriterionId;
3709
3710         SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) {
3711             mKey = key;
3712             mDuration = duration;
3713             mSnoozeCriterionId = snoozeCriterionId;
3714         }
3715
3716         @Override
3717         public void run() {
3718             synchronized (mNotificationLock) {
3719                 final NotificationRecord r = findNotificationByKeyLocked(mKey);
3720                 if (r != null) {
3721                     snoozeLocked(r);
3722                 }
3723             }
3724         }
3725
3726         @GuardedBy("mNotificationLock")
3727         void snoozeLocked(NotificationRecord r) {
3728             if (r.sbn.isGroup()) {
3729                 final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked(
3730                         r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId());
3731                 if (r.getNotification().isGroupSummary()) {
3732                     // snooze summary and all children
3733                     for (int i = 0; i < groupNotifications.size(); i++) {
3734                         snoozeNotificationLocked(groupNotifications.get(i));
3735                     }
3736                 } else {
3737                     // if there is a valid summary for this group, and we are snoozing the only
3738                     // child, also snooze the summary
3739                     if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) {
3740                         if (groupNotifications.size() != 2) {
3741                             snoozeNotificationLocked(r);
3742                         } else {
3743                             // snooze summary and the one child
3744                             for (int i = 0; i < groupNotifications.size(); i++) {
3745                                 snoozeNotificationLocked(groupNotifications.get(i));
3746                             }
3747                         }
3748                     } else {
3749                         snoozeNotificationLocked(r);
3750                     }
3751                 }
3752             } else {
3753                 // just snooze the one notification
3754                 snoozeNotificationLocked(r);
3755             }
3756         }
3757
3758         @GuardedBy("mNotificationLock")
3759         void snoozeNotificationLocked(NotificationRecord r) {
3760             MetricsLogger.action(r.getLogMaker()
3761                     .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
3762                     .setType(MetricsEvent.TYPE_CLOSE)
3763                     .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS,
3764                             mDuration)
3765                     .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
3766                             mSnoozeCriterionId == null ? 0 : 1));
3767             boolean wasPosted = removeFromNotificationListsLocked(r);
3768             cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null);
3769             updateLightsLocked();
3770             if (mSnoozeCriterionId != null) {
3771                 mAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
3772                 mSnoozeHelper.snooze(r);
3773             } else {
3774                 mSnoozeHelper.snooze(r, mDuration);
3775             }
3776             savePolicyFile();
3777         }
3778     }
3779
3780     protected class EnqueueNotificationRunnable implements Runnable {
3781         private final NotificationRecord r;
3782         private final int userId;
3783
3784         EnqueueNotificationRunnable(int userId, NotificationRecord r) {
3785             this.userId = userId;
3786             this.r = r;
3787         };
3788
3789         @Override
3790         public void run() {
3791             synchronized (mNotificationLock) {
3792                 mEnqueuedNotifications.add(r);
3793                 scheduleTimeoutLocked(r);
3794
3795                 final StatusBarNotification n = r.sbn;
3796                 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
3797                 NotificationRecord old = mNotificationsByKey.get(n.getKey());
3798                 if (old != null) {
3799                     // Retain ranking information from previous record
3800                     r.copyRankingInformation(old);
3801                 }
3802
3803                 final int callingUid = n.getUid();
3804                 final int callingPid = n.getInitialPid();
3805                 final Notification notification = n.getNotification();
3806                 final String pkg = n.getPackageName();
3807                 final int id = n.getId();
3808                 final String tag = n.getTag();
3809
3810                 // Handle grouped notifications and bail out early if we
3811                 // can to avoid extracting signals.
3812                 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
3813
3814                 // if this is a group child, unsnooze parent summary
3815                 if (n.isGroup() && notification.isGroupChild()) {
3816                     mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
3817                 }
3818
3819                 // This conditional is a dirty hack to limit the logging done on
3820                 //     behalf of the download manager without affecting other apps.
3821                 if (!pkg.equals("com.android.providers.downloads")
3822                         || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
3823                     int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
3824                     if (old != null) {
3825                         enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
3826                     }
3827                     EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
3828                             pkg, id, tag, userId, notification.toString(),
3829                             enqueueStatus);
3830                 }
3831
3832                 mRankingHelper.extractSignals(r);
3833
3834                 // tell the assistant service about the notification
3835                 if (mAssistants.isEnabled()) {
3836                     mAssistants.onNotificationEnqueued(r);
3837                     mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
3838                             DELAY_FOR_ASSISTANT_TIME);
3839                 } else {
3840                     mHandler.post(new PostNotificationRunnable(r.getKey()));
3841                 }
3842             }
3843         }
3844     }
3845
3846     protected class PostNotificationRunnable implements Runnable {
3847         private final String key;
3848
3849         PostNotificationRunnable(String key) {
3850             this.key = key;
3851         }
3852
3853         @Override
3854         public void run() {
3855             synchronized (mNotificationLock) {
3856                 try {
3857                     NotificationRecord r = null;
3858                     int N = mEnqueuedNotifications.size();
3859                     for (int i = 0; i < N; i++) {
3860                         final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
3861                         if (Objects.equals(key, enqueued.getKey())) {
3862                             r = enqueued;
3863                             break;
3864                         }
3865                     }
3866                     if (r == null) {
3867                         Slog.i(TAG, "Cannot find enqueued record for key: " + key);
3868                         return;
3869                     }
3870                     NotificationRecord old = mNotificationsByKey.get(key);
3871                     final StatusBarNotification n = r.sbn;
3872                     final Notification notification = n.getNotification();
3873                     int index = indexOfNotificationLocked(n.getKey());
3874                     if (index < 0) {
3875                         mNotificationList.add(r);
3876                         mUsageStats.registerPostedByApp(r);
3877                     } else {
3878                         old = mNotificationList.get(index);
3879                         mNotificationList.set(index, r);
3880                         mUsageStats.registerUpdatedByApp(r, old);
3881                         // Make sure we don't lose the foreground service state.
3882                         notification.flags |=
3883                                 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
3884                         r.isUpdate = true;
3885                     }
3886
3887                     mNotificationsByKey.put(n.getKey(), r);
3888
3889                     // Ensure if this is a foreground service that the proper additional
3890                     // flags are set.
3891                     if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
3892                         notification.flags |= Notification.FLAG_ONGOING_EVENT
3893                                 | Notification.FLAG_NO_CLEAR;
3894                     }
3895
3896                     applyZenModeLocked(r);
3897                     mRankingHelper.sort(mNotificationList);
3898
3899                     if (notification.getSmallIcon() != null) {
3900                         StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
3901                         mListeners.notifyPostedLocked(n, oldSbn);
3902                         if (oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())) {
3903                             mHandler.post(new Runnable() {
3904                                 @Override
3905                                 public void run() {
3906                                     mGroupHelper.onNotificationPosted(
3907                                             n, hasAutoGroupSummaryLocked(n));
3908                                 }
3909                             });
3910                         }
3911                     } else {
3912                         Slog.e(TAG, "Not posting notification without small icon: " + notification);
3913                         if (old != null && !old.isCanceled) {
3914                             mListeners.notifyRemovedLocked(n,
3915                                     NotificationListenerService.REASON_ERROR);
3916                             mHandler.post(new Runnable() {
3917                                 @Override
3918                                 public void run() {
3919                                     mGroupHelper.onNotificationRemoved(n);
3920                                 }
3921                             });
3922                         }
3923                         // ATTENTION: in a future release we will bail out here
3924                         // so that we do not play sounds, show lights, etc. for invalid
3925                         // notifications
3926                         Slog.e(TAG, "WARNING: In a future release this will crash the app: "
3927                                 + n.getPackageName());
3928                     }
3929
3930                     buzzBeepBlinkLocked(r);
3931                 } finally {
3932                     int N = mEnqueuedNotifications.size();
3933                     for (int i = 0; i < N; i++) {
3934                         final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
3935                         if (Objects.equals(key, enqueued.getKey())) {
3936                             mEnqueuedNotifications.remove(i);
3937                             break;
3938                         }
3939                     }
3940                 }
3941             }
3942         }
3943     }
3944
3945     /**
3946      * Ensures that grouped notification receive their special treatment.
3947      *
3948      * <p>Cancels group children if the new notification causes a group to lose
3949      * its summary.</p>
3950      *
3951      * <p>Updates mSummaryByGroupKey.</p>
3952      */
3953     @GuardedBy("mNotificationLock")
3954     private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
3955             int callingUid, int callingPid) {
3956         StatusBarNotification sbn = r.sbn;
3957         Notification n = sbn.getNotification();
3958         if (n.isGroupSummary() && !sbn.isAppGroup())  {
3959             // notifications without a group shouldn't be a summary, otherwise autobundling can
3960             // lead to bugs
3961             n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
3962         }
3963
3964         String group = sbn.getGroupKey();
3965         boolean isSummary = n.isGroupSummary();
3966
3967         Notification oldN = old != null ? old.sbn.getNotification() : null;
3968         String oldGroup = old != null ? old.sbn.getGroupKey() : null;
3969         boolean oldIsSummary = old != null && oldN.isGroupSummary();
3970
3971         if (oldIsSummary) {
3972             NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
3973             if (removedSummary != old) {
3974                 String removedKey =
3975                         removedSummary != null ? removedSummary.getKey() : "<null>";
3976                 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
3977                         ", removed=" + removedKey);
3978             }
3979         }
3980         if (isSummary) {
3981             mSummaryByGroupKey.put(group, r);
3982         }
3983
3984         // Clear out group children of the old notification if the update
3985         // causes the group summary to go away. This happens when the old
3986         // notification was a summary and the new one isn't, or when the old
3987         // notification was a summary and its group key changed.
3988         if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
3989             cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */,
3990                     null);
3991         }
3992     }
3993
3994     @VisibleForTesting
3995     @GuardedBy("mNotificationLock")
3996     void scheduleTimeoutLocked(NotificationRecord record) {
3997         if (record.getNotification().getTimeoutAfter() > 0) {
3998             final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
3999                     REQUEST_CODE_TIMEOUT,
4000                     new Intent(ACTION_NOTIFICATION_TIMEOUT)
4001                             .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
4002                                     .appendPath(record.getKey()).build())
4003                             .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
4004                             .putExtra(EXTRA_KEY, record.getKey()),
4005                     PendingIntent.FLAG_UPDATE_CURRENT);
4006             mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
4007                     SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
4008         }
4009     }
4010
4011     @VisibleForTesting
4012     @GuardedBy("mNotificationLock")
4013     void buzzBeepBlinkLocked(NotificationRecord record) {
4014         boolean buzz = false;
4015         boolean beep = false;
4016         boolean blink = false;
4017
4018         final Notification notification = record.sbn.getNotification();
4019         final String key = record.getKey();
4020
4021         // Should this notification make noise, vibe, or use the LED?
4022         final boolean aboveThreshold =
4023                 record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
4024
4025         // Remember if this notification already owns the notification channels.
4026         boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
4027         boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
4028         // These are set inside the conditional if the notification is allowed to make noise.
4029         boolean hasValidVibrate = false;
4030         boolean hasValidSound = false;
4031         boolean sentAccessibilityEvent = false;
4032         // If the notification will appear in the status bar, it should send an accessibility
4033         // event
4034         if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) {
4035             sendAccessibilityEvent(notification, record.sbn.getPackageName());
4036             sentAccessibilityEvent = true;
4037         }
4038
4039         if (aboveThreshold && isNotificationForCurrentUser(record)) {
4040
4041             if (mSystemReady && mAudioManager != null) {
4042                 Uri soundUri = record.getSound();
4043                 hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
4044                 long[] vibration = record.getVibration();
4045                 // Demote sound to vibration if vibration missing & phone in vibration mode.
4046                 if (vibration == null
4047                         && hasValidSound
4048                         && (mAudioManager.getRingerModeInternal()
4049                         == AudioManager.RINGER_MODE_VIBRATE)
4050                         && mAudioManager.getStreamVolume(
4051                         AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) == 0) {
4052                     vibration = mFallbackVibrationPattern;
4053                 }
4054                 hasValidVibrate = vibration != null;
4055
4056                 boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
4057                 if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
4058                     if (!sentAccessibilityEvent) {
4059                         sendAccessibilityEvent(notification, record.sbn.getPackageName());
4060                         sentAccessibilityEvent = true;
4061                     }
4062                     if (DBG) Slog.v(TAG, "Interrupting!");
4063                     if (hasValidSound) {
4064                         mSoundNotificationKey = key;
4065                         if (mInCall) {
4066                             playInCallNotification();
4067                             beep = true;
4068                         } else {
4069                             beep = playSound(record, soundUri);
4070                         }
4071                     }
4072
4073                     final boolean ringerModeSilent =
4074                             mAudioManager.getRingerModeInternal()
4075                                     == AudioManager.RINGER_MODE_SILENT;
4076                     if (!mInCall && hasValidVibrate && !ringerModeSilent) {
4077                         mVibrateNotificationKey = key;
4078
4079                         buzz = playVibration(record, vibration, hasValidSound);
4080                     }
4081                 }
4082             }
4083         }
4084         // If a notification is updated to remove the actively playing sound or vibrate,
4085         // cancel that feedback now
4086         if (wasBeep && !hasValidSound) {
4087             clearSoundLocked();
4088         }
4089         if (wasBuzz && !hasValidVibrate) {
4090             clearVibrateLocked();
4091         }
4092
4093         // light
4094         // release the light
4095         boolean wasShowLights = mLights.remove(key);
4096         if (record.getLight() != null && aboveThreshold
4097                 && ((record.getSuppressedVisualEffects()
4098                 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
4099             mLights.add(key);
4100             updateLightsLocked();
4101             if (mUseAttentionLight) {
4102                 mAttentionLight.pulse();
4103             }
4104             blink = true;
4105         } else if (wasShowLights) {
4106             updateLightsLocked();
4107         }
4108         if (buzz || beep || blink) {
4109             MetricsLogger.action(record.getLogMaker()
4110                     .setCategory(MetricsEvent.NOTIFICATION_ALERT)
4111                     .setType(MetricsEvent.TYPE_OPEN)
4112                     .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
4113             EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
4114         }
4115     }
4116
4117     @GuardedBy("mNotificationLock")
4118     boolean shouldMuteNotificationLocked(final NotificationRecord record) {
4119         // Suppressed because it's a silent update
4120         final Notification notification = record.getNotification();
4121         if(record.isUpdate
4122                 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
4123             return true;
4124         }
4125
4126         // muted by listener
4127         final String disableEffects = disableNotificationEffects(record);
4128         if (disableEffects != null) {
4129             ZenLog.traceDisableEffects(record, disableEffects);
4130             return true;
4131         }
4132
4133         // suppressed due to DND
4134         if (record.isIntercepted()) {
4135             return true;
4136         }
4137
4138         // Suppressed because another notification in its group handles alerting
4139         if (record.sbn.isGroup()) {
4140             return notification.suppressAlertingDueToGrouping();
4141         }
4142
4143         // Suppressed for being too recently noisy
4144         final String pkg = record.sbn.getPackageName();
4145         if (mUsageStats.isAlertRateLimited(pkg)) {
4146             Slog.e(TAG, "Muting recently noisy " + record.getKey());
4147             return true;
4148         }
4149
4150         return false;
4151     }
4152
4153     private boolean playSound(final NotificationRecord record, Uri soundUri) {
4154         boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
4155         // do not play notifications if there is a user of exclusive audio focus
4156         // or the device is in vibrate mode
4157         if (!mAudioManager.isAudioFocusExclusive() && (mAudioManager.getRingerModeInternal()
4158                 != AudioManager.RINGER_MODE_VIBRATE || mAudioManager.getStreamVolume(
4159                 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) {
4160             final long identity = Binder.clearCallingIdentity();
4161             try {
4162                 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4163                 if (player != null) {
4164                     if (DBG) Slog.v(TAG, "Playing sound " + soundUri
4165                             + " with attributes " + record.getAudioAttributes());
4166                     player.playAsync(soundUri, record.sbn.getUser(), looping,
4167                             record.getAudioAttributes());
4168                     return true;
4169                 }
4170             } catch (RemoteException e) {
4171             } finally {
4172                 Binder.restoreCallingIdentity(identity);
4173             }
4174         }
4175         return false;
4176     }
4177
4178     private boolean playVibration(final NotificationRecord record, long[] vibration,
4179             boolean delayVibForSound) {
4180         // Escalate privileges so we can use the vibrator even if the
4181         // notifying app does not have the VIBRATE permission.
4182         long identity = Binder.clearCallingIdentity();
4183         try {
4184             final VibrationEffect effect;
4185             try {
4186                 final boolean insistent =
4187                         (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
4188                 effect = VibrationEffect.createWaveform(
4189                         vibration, insistent ? 0 : -1 /*repeatIndex*/);
4190             } catch (IllegalArgumentException e) {
4191                 Slog.e(TAG, "Error creating vibration waveform with pattern: " +
4192                         Arrays.toString(vibration));
4193                 return false;
4194             }
4195             if (delayVibForSound) {
4196                 new Thread(() -> {
4197                     // delay the vibration by the same amount as the notification sound
4198                     final int waitMs = mAudioManager.getFocusRampTimeMs(
4199                             AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
4200                             record.getAudioAttributes());
4201                     if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms");
4202                     try {
4203                         Thread.sleep(waitMs);
4204                     } catch (InterruptedException e) { }
4205                     mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
4206                             effect, record.getAudioAttributes());
4207                 }).start();
4208             } else {
4209                 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
4210                         effect, record.getAudioAttributes());
4211             }
4212             return true;
4213         } finally{
4214             Binder.restoreCallingIdentity(identity);
4215         }
4216     }
4217
4218     private boolean isNotificationForCurrentUser(NotificationRecord record) {
4219         final int currentUser;
4220         final long token = Binder.clearCallingIdentity();
4221         try {
4222             currentUser = ActivityManager.getCurrentUser();
4223         } finally {
4224             Binder.restoreCallingIdentity(token);
4225         }
4226         return (record.getUserId() == UserHandle.USER_ALL ||
4227                 record.getUserId() == currentUser ||
4228                 mUserProfiles.isCurrentProfile(record.getUserId()));
4229     }
4230
4231     protected void playInCallNotification() {
4232         new Thread() {
4233             @Override
4234             public void run() {
4235                 final long identity = Binder.clearCallingIdentity();
4236                 try {
4237                     final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4238                     if (player != null) {
4239                         player.play(new Binder(), mInCallNotificationUri,
4240                                 mInCallNotificationAudioAttributes,
4241                                 mInCallNotificationVolume, false);
4242                     }
4243                 } catch (RemoteException e) {
4244                 } finally {
4245                     Binder.restoreCallingIdentity(identity);
4246                 }
4247             }
4248         }.start();
4249     }
4250
4251     @GuardedBy("mToastQueue")
4252     void showNextToastLocked() {
4253         ToastRecord record = mToastQueue.get(0);
4254         while (record != null) {
4255             if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
4256             try {
4257                 record.callback.show(record.token);
4258                 scheduleTimeoutLocked(record);
4259                 return;
4260             } catch (RemoteException e) {
4261                 Slog.w(TAG, "Object died trying to show notification " + record.callback
4262                         + " in package " + record.pkg);
4263                 // remove it from the list and let the process die
4264                 int index = mToastQueue.indexOf(record);
4265                 if (index >= 0) {
4266                     mToastQueue.remove(index);
4267                 }
4268                 keepProcessAliveIfNeededLocked(record.pid);
4269                 if (mToastQueue.size() > 0) {
4270                     record = mToastQueue.get(0);
4271                 } else {
4272                     record = null;
4273                 }
4274             }
4275         }
4276     }
4277
4278     @GuardedBy("mToastQueue")
4279     void cancelToastLocked(int index) {
4280         ToastRecord record = mToastQueue.get(index);
4281         try {
4282             record.callback.hide();
4283         } catch (RemoteException e) {
4284             Slog.w(TAG, "Object died trying to hide notification " + record.callback
4285                     + " in package " + record.pkg);
4286             // don't worry about this, we're about to remove it from
4287             // the list anyway
4288         }
4289
4290         ToastRecord lastToast = mToastQueue.remove(index);
4291         mWindowManagerInternal.removeWindowToken(lastToast.token, true, DEFAULT_DISPLAY);
4292
4293         keepProcessAliveIfNeededLocked(record.pid);
4294         if (mToastQueue.size() > 0) {
4295             // Show the next one. If the callback fails, this will remove
4296             // it from the list, so don't assume that the list hasn't changed
4297             // after this point.
4298             showNextToastLocked();
4299         }
4300     }
4301
4302     @GuardedBy("mToastQueue")
4303     private void scheduleTimeoutLocked(ToastRecord r)
4304     {
4305         mHandler.removeCallbacksAndMessages(r);
4306         Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
4307         long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
4308         mHandler.sendMessageDelayed(m, delay);
4309     }
4310
4311     private void handleTimeout(ToastRecord record)
4312     {
4313         if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
4314         synchronized (mToastQueue) {
4315             int index = indexOfToastLocked(record.pkg, record.callback);
4316             if (index >= 0) {
4317                 cancelToastLocked(index);
4318             }
4319         }
4320     }
4321
4322     @GuardedBy("mToastQueue")
4323     int indexOfToastLocked(String pkg, ITransientNotification callback)
4324     {
4325         IBinder cbak = callback.asBinder();
4326         ArrayList<ToastRecord> list = mToastQueue;
4327         int len = list.size();
4328         for (int i=0; i<len; i++) {
4329             ToastRecord r = list.get(i);
4330             if (r.pkg.equals(pkg) && r.callback.asBinder().equals(cbak)) {
4331                 return i;
4332             }
4333         }
4334         return -1;
4335     }
4336
4337     @GuardedBy("mToastQueue")
4338     int indexOfToastPackageLocked(String pkg)
4339     {
4340         ArrayList<ToastRecord> list = mToastQueue;
4341         int len = list.size();
4342         for (int i=0; i<len; i++) {
4343             ToastRecord r = list.get(i);
4344             if (r.pkg.equals(pkg)) {
4345                 return i;
4346             }
4347         }
4348         return -1;
4349     }
4350
4351     @GuardedBy("mToastQueue")
4352     void keepProcessAliveIfNeededLocked(int pid)
4353     {
4354         int toastCount = 0; // toasts from this pid
4355         ArrayList<ToastRecord> list = mToastQueue;
4356         int N = list.size();
4357         for (int i=0; i<N; i++) {
4358             ToastRecord r = list.get(i);
4359             if (r.pid == pid) {
4360                 toastCount++;
4361             }
4362         }
4363         try {
4364             mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
4365         } catch (RemoteException e) {
4366             // Shouldn't happen.
4367         }
4368     }
4369
4370     private void handleRankingReconsideration(Message message) {
4371         if (!(message.obj instanceof RankingReconsideration)) return;
4372         RankingReconsideration recon = (RankingReconsideration) message.obj;
4373         recon.run();
4374         boolean changed;
4375         synchronized (mNotificationLock) {
4376             final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
4377             if (record == null) {
4378                 return;
4379             }
4380             int indexBefore = findNotificationRecordIndexLocked(record);
4381             boolean interceptBefore = record.isIntercepted();
4382             float contactAffinityBefore = record.getContactAffinity();
4383             int visibilityBefore = record.getPackageVisibilityOverride();
4384             recon.applyChangesLocked(record);
4385             applyZenModeLocked(record);
4386             mRankingHelper.sort(mNotificationList);
4387             int indexAfter = findNotificationRecordIndexLocked(record);
4388             boolean interceptAfter = record.isIntercepted();
4389             float contactAffinityAfter = record.getContactAffinity();
4390             int visibilityAfter = record.getPackageVisibilityOverride();
4391             changed = indexBefore != indexAfter || interceptBefore != interceptAfter
4392                     || visibilityBefore != visibilityAfter;
4393             if (interceptBefore && !interceptAfter
4394                     && Float.compare(contactAffinityBefore, contactAffinityAfter) != 0) {
4395                 buzzBeepBlinkLocked(record);
4396             }
4397         }
4398         if (changed) {
4399             mHandler.scheduleSendRankingUpdate();
4400         }
4401     }
4402
4403     void handleRankingSort() {
4404         if (mRankingHelper == null) return;
4405         synchronized (mNotificationLock) {
4406             final int N = mNotificationList.size();
4407             // Any field that can change via one of the extractors needs to be added here.
4408             ArrayList<String> orderBefore = new ArrayList<>(N);
4409             int[] visibilities = new int[N];
4410             boolean[] showBadges = new boolean[N];
4411             ArrayList<NotificationChannel> channelBefore = new ArrayList<>(N);
4412             ArrayList<String> groupKeyBefore = new ArrayList<>(N);
4413             ArrayList<ArrayList<String>> overridePeopleBefore = new ArrayList<>(N);
4414             ArrayList<ArrayList<SnoozeCriterion>> snoozeCriteriaBefore = new ArrayList<>(N);
4415             for (int i = 0; i < N; i++) {
4416                 final NotificationRecord r = mNotificationList.get(i);
4417                 orderBefore.add(r.getKey());
4418                 visibilities[i] = r.getPackageVisibilityOverride();
4419                 showBadges[i] = r.canShowBadge();
4420                 channelBefore.add(r.getChannel());
4421                 groupKeyBefore.add(r.getGroupKey());
4422                 overridePeopleBefore.add(r.getPeopleOverride());
4423                 snoozeCriteriaBefore.add(r.getSnoozeCriteria());
4424                 mRankingHelper.extractSignals(r);
4425             }
4426             mRankingHelper.sort(mNotificationList);
4427             for (int i = 0; i < N; i++) {
4428                 final NotificationRecord r = mNotificationList.get(i);
4429                 if (!orderBefore.get(i).equals(r.getKey())
4430                         || visibilities[i] != r.getPackageVisibilityOverride()
4431                         || showBadges[i] != r.canShowBadge()
4432                         || !Objects.equals(channelBefore.get(i), r.getChannel())
4433                         || !Objects.equals(groupKeyBefore.get(i), r.getGroupKey())
4434                         || !Objects.equals(overridePeopleBefore.get(i), r.getPeopleOverride())
4435                         || !Objects.equals(snoozeCriteriaBefore.get(i), r.getSnoozeCriteria())) {
4436                     mHandler.scheduleSendRankingUpdate();
4437                     return;
4438                 }
4439             }
4440         }
4441     }
4442
4443     @GuardedBy("mNotificationLock")
4444     private void recordCallerLocked(NotificationRecord record) {
4445         if (mZenModeHelper.isCall(record)) {
4446             mZenModeHelper.recordCaller(record);
4447         }
4448     }
4449
4450     // let zen mode evaluate this record
4451     @GuardedBy("mNotificationLock")
4452     private void applyZenModeLocked(NotificationRecord record) {
4453         record.setIntercepted(mZenModeHelper.shouldIntercept(record));
4454         if (record.isIntercepted()) {
4455             int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
4456                     ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
4457                     | (mZenModeHelper.shouldSuppressWhenScreenOn()
4458                     ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
4459             record.setSuppressedVisualEffects(suppressed);
4460         } else {
4461             record.setSuppressedVisualEffects(0);
4462         }
4463     }
4464
4465     @GuardedBy("mNotificationLock")
4466     private int findNotificationRecordIndexLocked(NotificationRecord target) {
4467         return mRankingHelper.indexOf(mNotificationList, target);
4468     }
4469
4470     private void handleSendRankingUpdate() {
4471         synchronized (mNotificationLock) {
4472             mListeners.notifyRankingUpdateLocked();
4473         }
4474     }
4475
4476     private void scheduleListenerHintsChanged(int state) {
4477         mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
4478         mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
4479     }
4480
4481     private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
4482         mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
4483         mHandler.obtainMessage(
4484                 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
4485                 listenerInterruptionFilter,
4486                 0).sendToTarget();
4487     }
4488
4489     private void handleListenerHintsChanged(int hints) {
4490         synchronized (mNotificationLock) {
4491             mListeners.notifyListenerHintsChangedLocked(hints);
4492         }
4493     }
4494
4495     private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
4496         synchronized (mNotificationLock) {
4497             mListeners.notifyInterruptionFilterChanged(interruptionFilter);
4498         }
4499     }
4500
4501     protected class WorkerHandler extends Handler
4502     {
4503         public WorkerHandler(Looper looper) {
4504             super(looper);
4505         }
4506
4507         @Override
4508         public void handleMessage(Message msg)
4509         {
4510             switch (msg.what)
4511             {
4512                 case MESSAGE_TIMEOUT:
4513                     handleTimeout((ToastRecord)msg.obj);
4514                     break;
4515                 case MESSAGE_SAVE_POLICY_FILE:
4516                     handleSavePolicyFile();
4517                     break;
4518                 case MESSAGE_SEND_RANKING_UPDATE:
4519                     handleSendRankingUpdate();
4520                     break;
4521                 case MESSAGE_LISTENER_HINTS_CHANGED:
4522                     handleListenerHintsChanged(msg.arg1);
4523                     break;
4524                 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
4525                     handleListenerInterruptionFilterChanged(msg.arg1);
4526                     break;
4527             }
4528         }
4529
4530         protected void scheduleSendRankingUpdate() {
4531             if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
4532                 Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE);
4533                 sendMessage(m);
4534             }
4535         }
4536
4537     }
4538
4539     private final class RankingHandlerWorker extends Handler implements RankingHandler
4540     {
4541         public RankingHandlerWorker(Looper looper) {
4542             super(looper);
4543         }
4544
4545         @Override
4546         public void handleMessage(Message msg) {
4547             switch (msg.what) {
4548                 case MESSAGE_RECONSIDER_RANKING:
4549                     handleRankingReconsideration(msg);
4550                     break;
4551                 case MESSAGE_RANKING_SORT:
4552                     handleRankingSort();
4553                     break;
4554             }
4555         }
4556
4557         public void requestSort() {
4558             removeMessages(MESSAGE_RANKING_SORT);
4559             Message msg = Message.obtain();
4560             msg.what = MESSAGE_RANKING_SORT;
4561             sendMessage(msg);
4562         }
4563
4564         public void requestReconsideration(RankingReconsideration recon) {
4565             Message m = Message.obtain(this,
4566                     NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
4567             long delay = recon.getDelay(TimeUnit.MILLISECONDS);
4568             sendMessageDelayed(m, delay);
4569         }
4570     }
4571
4572     // Notifications
4573     // ============================================================================
4574     static int clamp(int x, int low, int high) {
4575         return (x < low) ? low : ((x > high) ? high : x);
4576     }
4577
4578     void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
4579         if (!mAccessibilityManager.isEnabled()) {
4580             return;
4581         }
4582
4583         AccessibilityEvent event =
4584             AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
4585         event.setPackageName(packageName);
4586         event.setClassName(Notification.class.getName());
4587         event.setParcelableData(notification);
4588         CharSequence tickerText = notification.tickerText;
4589         if (!TextUtils.isEmpty(tickerText)) {
4590             event.getText().add(tickerText);
4591         }
4592
4593         mAccessibilityManager.sendAccessibilityEvent(event);
4594     }
4595
4596     /**
4597      * Removes all NotificationsRecords with the same key as the given notification record
4598      * from both lists. Do not call this method while iterating over either list.
4599      */
4600     @GuardedBy("mNotificationLock")
4601     private boolean removeFromNotificationListsLocked(NotificationRecord r) {
4602         // Remove from both lists, either list could have a separate Record for what is
4603         // effectively the same notification.
4604         boolean wasPosted = false;
4605         NotificationRecord recordInList = null;
4606         if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))
4607                 != null) {
4608             mNotificationList.remove(recordInList);
4609             mNotificationsByKey.remove(recordInList.sbn.getKey());
4610             wasPosted = true;
4611         }
4612         while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
4613                 != null) {
4614             mEnqueuedNotifications.remove(recordInList);
4615         }
4616         return wasPosted;
4617     }
4618
4619     @GuardedBy("mNotificationLock")
4620     private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
4621             boolean wasPosted, String listenerName) {
4622         final String canceledKey = r.getKey();
4623
4624         // Record caller.
4625         recordCallerLocked(r);
4626
4627         // tell the app
4628         if (sendDelete) {
4629             if (r.getNotification().deleteIntent != null) {
4630                 try {
4631                     r.getNotification().deleteIntent.send();
4632                 } catch (PendingIntent.CanceledException ex) {
4633                     // do nothing - there's no relevant way to recover, and
4634                     //     no reason to let this propagate
4635                     Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
4636                 }
4637             }
4638         }
4639
4640         // Only cancel these if this notification actually got to be posted.
4641         if (wasPosted) {
4642             // status bar
4643             if (r.getNotification().getSmallIcon() != null) {
4644                 if (reason != REASON_SNOOZED) {
4645                     r.isCanceled = true;
4646                 }
4647                 mListeners.notifyRemovedLocked(r.sbn, reason);
4648                 mHandler.post(new Runnable() {
4649                     @Override
4650                     public void run() {
4651                         mGroupHelper.onNotificationRemoved(r.sbn);
4652                     }
4653                 });
4654             }
4655
4656             // sound
4657             if (canceledKey.equals(mSoundNotificationKey)) {
4658                 mSoundNotificationKey = null;
4659                 final long identity = Binder.clearCallingIdentity();
4660                 try {
4661                     final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4662                     if (player != null) {
4663                         player.stopAsync();
4664                     }
4665                 } catch (RemoteException e) {
4666                 } finally {
4667                     Binder.restoreCallingIdentity(identity);
4668                 }
4669             }
4670
4671             // vibrate
4672             if (canceledKey.equals(mVibrateNotificationKey)) {
4673                 mVibrateNotificationKey = null;
4674                 long identity = Binder.clearCallingIdentity();
4675                 try {
4676                     mVibrator.cancel();
4677                 }
4678                 finally {
4679                     Binder.restoreCallingIdentity(identity);
4680                 }
4681             }
4682
4683             // light
4684             mLights.remove(canceledKey);
4685         }
4686
4687         // Record usage stats
4688         // TODO: add unbundling stats?
4689         switch (reason) {
4690             case REASON_CANCEL:
4691             case REASON_CANCEL_ALL:
4692             case REASON_LISTENER_CANCEL:
4693             case REASON_LISTENER_CANCEL_ALL:
4694                 mUsageStats.registerDismissedByUser(r);
4695                 break;
4696             case REASON_APP_CANCEL:
4697             case REASON_APP_CANCEL_ALL:
4698                 mUsageStats.registerRemovedByApp(r);
4699                 break;
4700         }
4701
4702         String groupKey = r.getGroupKey();
4703         NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
4704         if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
4705             mSummaryByGroupKey.remove(groupKey);
4706         }
4707         final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
4708         if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
4709             summaries.remove(r.sbn.getPackageName());
4710         }
4711
4712         // Save it for users of getHistoricalNotifications()
4713         mArchive.record(r.sbn);
4714
4715         final long now = System.currentTimeMillis();
4716         MetricsLogger.action(r.getLogMaker(now)
4717                 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
4718                 .setType(MetricsEvent.TYPE_DISMISS)
4719                 .setSubtype(reason));
4720         EventLogTags.writeNotificationCanceled(canceledKey, reason,
4721                 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), listenerName);
4722     }
4723
4724     /**
4725      * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
4726      * and none of the {@code mustNotHaveFlags}.
4727      */
4728     void cancelNotification(final int callingUid, final int callingPid,
4729             final String pkg, final String tag, final int id,
4730             final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
4731             final int userId, final int reason, final ManagedServiceInfo listener) {
4732         // In enqueueNotificationInternal notifications are added by scheduling the
4733         // work on the worker handler. Hence, we also schedule the cancel on this
4734         // handler to avoid a scenario where an add notification call followed by a
4735         // remove notification call ends up in not removing the notification.
4736         mHandler.post(new Runnable() {
4737             @Override
4738             public void run() {
4739                 String listenerName = listener == null ? null : listener.component.toShortString();
4740                 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
4741                         userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
4742
4743                 synchronized (mNotificationLock) {
4744                     // Look for the notification, searching both the posted and enqueued lists.
4745                     NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
4746                     if (r != null) {
4747                         // The notification was found, check if it should be removed.
4748
4749                         // Ideally we'd do this in the caller of this method. However, that would
4750                         // require the caller to also find the notification.
4751                         if (reason == REASON_CLICK) {
4752                             mUsageStats.registerClickedByUser(r);
4753                         }
4754
4755                         if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
4756                             return;
4757                         }
4758                         if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
4759                             return;
4760                         }
4761
4762                         // Cancel the notification.
4763                         boolean wasPosted = removeFromNotificationListsLocked(r);
4764                         cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
4765                         cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
4766                                 sendDelete, null);
4767                         updateLightsLocked();
4768                     } else {
4769                         // No notification was found, assume that it is snoozed and cancel it.
4770                         if (reason != REASON_SNOOZED) {
4771                             final boolean wasSnoozed = mSnoozeHelper.cancel(userId, pkg, tag, id);
4772                             if (wasSnoozed) {
4773                                 savePolicyFile();
4774                             }
4775                         }
4776                     }
4777                 }
4778             }
4779         });
4780     }
4781
4782     /**
4783      * Determine whether the userId applies to the notification in question, either because
4784      * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
4785      */
4786     private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
4787         return
4788                 // looking for USER_ALL notifications? match everything
4789                    userId == UserHandle.USER_ALL
4790                 // a notification sent to USER_ALL matches any query
4791                 || r.getUserId() == UserHandle.USER_ALL
4792                 // an exact user match
4793                 || r.getUserId() == userId;
4794     }
4795
4796     /**
4797      * Determine whether the userId applies to the notification in question, either because
4798      * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
4799      * because it matches one of the users profiles.
4800      */
4801     private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
4802         return notificationMatchesUserId(r, userId)
4803                 || mUserProfiles.isCurrentProfile(r.getUserId());
4804     }
4805
4806     /**
4807      * Cancels all notifications from a given package that have all of the
4808      * {@code mustHaveFlags}.
4809      */
4810     void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
4811             int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
4812             ManagedServiceInfo listener) {
4813         mHandler.post(new Runnable() {
4814             @Override
4815             public void run() {
4816                 String listenerName = listener == null ? null : listener.component.toShortString();
4817                 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
4818                         pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
4819                         listenerName);
4820
4821                 // Why does this parameter exist? Do we actually want to execute the above if doit
4822                 // is false?
4823                 if (!doit) {
4824                     return;
4825                 }
4826
4827                 synchronized (mNotificationLock) {
4828                     FlagChecker flagChecker = (int flags) -> {
4829                         if ((flags & mustHaveFlags) != mustHaveFlags) {
4830                             return false;
4831                         }
4832                         if ((flags & mustNotHaveFlags) != 0) {
4833                             return false;
4834                         }
4835                         return true;
4836                     };
4837                     cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
4838                             pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
4839                             false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
4840                             listenerName, true /* wasPosted */);
4841                     cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
4842                             callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
4843                             flagChecker, false /*includeCurrentProfiles*/, userId,
4844                             false /*sendDelete*/, reason, listenerName, false /* wasPosted */);
4845                     mSnoozeHelper.cancel(userId, pkg);
4846                 }
4847             }
4848         });
4849     }
4850
4851     private interface FlagChecker {
4852         // Returns false if these flags do not pass the defined flag test.
4853         public boolean apply(int flags);
4854     }
4855
4856     @GuardedBy("mNotificationLock")
4857     private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
4858             int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
4859             String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
4860             boolean sendDelete, int reason, String listenerName, boolean wasPosted) {
4861         ArrayList<NotificationRecord> canceledNotifications = null;
4862         for (int i = notificationList.size() - 1; i >= 0; --i) {
4863             NotificationRecord r = notificationList.get(i);
4864             if (includeCurrentProfiles) {
4865                 if (!notificationMatchesCurrentProfiles(r, userId)) {
4866                     continue;
4867                 }
4868             } else if (!notificationMatchesUserId(r, userId)) {
4869                 continue;
4870             }
4871             // Don't remove notifications to all, if there's no package name specified
4872             if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
4873                 continue;
4874             }
4875             if (!flagChecker.apply(r.getFlags())) {
4876                 continue;
4877             }
4878             if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
4879                 continue;
4880             }
4881             if (channelId != null && !channelId.equals(r.getChannel().getId())) {
4882                 continue;
4883             }
4884             if (canceledNotifications == null) {
4885                 canceledNotifications = new ArrayList<>();
4886             }
4887             notificationList.remove(i);
4888             mNotificationsByKey.remove(r.getKey());
4889             canceledNotifications.add(r);
4890             cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
4891         }
4892         if (canceledNotifications != null) {
4893             final int M = canceledNotifications.size();
4894             for (int i = 0; i < M; i++) {
4895                 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
4896                         listenerName, false /* sendDelete */, flagChecker);
4897             }
4898             updateLightsLocked();
4899         }
4900     }
4901
4902     void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
4903             ManagedServiceInfo listener) {
4904         String listenerName = listener == null ? null : listener.component.toShortString();
4905         if (duration <= 0 && snoozeCriterionId == null || key == null) {
4906             return;
4907         }
4908
4909         if (DBG) {
4910             Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
4911                     snoozeCriterionId, listenerName));
4912         }
4913         // Needs to post so that it can cancel notifications not yet enqueued.
4914         mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
4915     }
4916
4917     void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
4918         String listenerName = listener == null ? null : listener.component.toShortString();
4919         if (DBG) {
4920             Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
4921         }
4922         mSnoozeHelper.repost(key);
4923         savePolicyFile();
4924     }
4925
4926     @GuardedBy("mNotificationLock")
4927     void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
4928             ManagedServiceInfo listener, boolean includeCurrentProfiles) {
4929         mHandler.post(new Runnable() {
4930             @Override
4931             public void run() {
4932                 synchronized (mNotificationLock) {
4933                     String listenerName =
4934                             listener == null ? null : listener.component.toShortString();
4935                     EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
4936                             null, userId, 0, 0, reason, listenerName);
4937
4938                     FlagChecker flagChecker = (int flags) -> {
4939                         if ((flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR))
4940                                 != 0) {
4941                             return false;
4942                         }
4943                         return true;
4944                     };
4945
4946                     cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
4947                             null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
4948                             includeCurrentProfiles, userId, true /*sendDelete*/, reason,
4949                             listenerName, true);
4950                     cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
4951                             callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
4952                             flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
4953                             reason, listenerName, false);
4954                     mSnoozeHelper.cancel(userId, includeCurrentProfiles);
4955                 }
4956             }
4957         });
4958     }
4959
4960     // Warning: The caller is responsible for invoking updateLightsLocked().
4961     @GuardedBy("mNotificationLock")
4962     private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
4963             String listenerName, boolean sendDelete, FlagChecker flagChecker) {
4964         Notification n = r.getNotification();
4965         if (!n.isGroupSummary()) {
4966             return;
4967         }
4968
4969         String pkg = r.sbn.getPackageName();
4970
4971         if (pkg == null) {
4972             if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
4973             return;
4974         }
4975
4976         cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
4977                 sendDelete, true, flagChecker);
4978         cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
4979                 listenerName, sendDelete, false, flagChecker);
4980     }
4981
4982     @GuardedBy("mNotificationLock")
4983     private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
4984             NotificationRecord parentNotification, int callingUid, int callingPid,
4985             String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker) {
4986         final String pkg = parentNotification.sbn.getPackageName();
4987         final int userId = parentNotification.getUserId();
4988         final int reason = REASON_GROUP_SUMMARY_CANCELED;
4989         for (int i = notificationList.size() - 1; i >= 0; i--) {
4990             final NotificationRecord childR = notificationList.get(i);
4991             final StatusBarNotification childSbn = childR.sbn;
4992             if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
4993                     childR.getGroupKey().equals(parentNotification.getGroupKey())
4994                     && (childR.getFlags() & Notification.FLAG_FOREGROUND_SERVICE) == 0
4995                     && (flagChecker == null || flagChecker.apply(childR.getFlags()))) {
4996                 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
4997                         childSbn.getTag(), userId, 0, 0, reason, listenerName);
4998                 notificationList.remove(i);
4999                 mNotificationsByKey.remove(childR.getKey());
5000                 cancelNotificationLocked(childR, sendDelete, reason, wasPosted, listenerName);
5001             }
5002         }
5003     }
5004
5005     @GuardedBy("mNotificationLock")
5006     void updateLightsLocked()
5007     {
5008         // handle notification lights
5009         NotificationRecord ledNotification = null;
5010         while (ledNotification == null && !mLights.isEmpty()) {
5011             final String owner = mLights.get(mLights.size() - 1);
5012             ledNotification = mNotificationsByKey.get(owner);
5013             if (ledNotification == null) {
5014                 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
5015                 mLights.remove(owner);
5016             }
5017         }
5018
5019         // Don't flash while we are in a call or screen is on
5020         if (ledNotification == null || mInCall || mScreenOn) {
5021             mNotificationLight.turnOff();
5022         } else {
5023             NotificationRecord.Light light = ledNotification.getLight();
5024             if (light != null && mNotificationPulseEnabled) {
5025                 // pulse repeatedly
5026                 mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
5027                         light.onMs, light.offMs);
5028             }
5029         }
5030     }
5031
5032     @GuardedBy("mNotificationLock")
5033     @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
5034             String groupKey, int userId) {
5035         List<NotificationRecord> records = new ArrayList<>();
5036         records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
5037         records.addAll(
5038                 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
5039         return records;
5040     }
5041
5042
5043     @GuardedBy("mNotificationLock")
5044     private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
5045             ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
5046         List<NotificationRecord> records = new ArrayList<>();
5047         final int len = list.size();
5048         for (int i = 0; i < len; i++) {
5049             NotificationRecord r = list.get(i);
5050             if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey)
5051                     && r.sbn.getPackageName().equals(pkg)) {
5052                 records.add(r);
5053             }
5054         }
5055         return records;
5056     }
5057
5058     // Searches both enqueued and posted notifications by key.
5059     // TODO: need to combine a bunch of these getters with slightly different behavior.
5060     // TODO: Should enqueuing just add to mNotificationsByKey instead?
5061     @GuardedBy("mNotificationLock")
5062     private NotificationRecord findNotificationByKeyLocked(String key) {
5063         NotificationRecord r;
5064         if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
5065             return r;
5066         }
5067         if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
5068             return r;
5069         }
5070         return null;
5071     }
5072
5073     @GuardedBy("mNotificationLock")
5074     NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
5075         NotificationRecord r;
5076         if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
5077             return r;
5078         }
5079         if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
5080                 != null) {
5081             return r;
5082         }
5083         return null;
5084     }
5085
5086     @GuardedBy("mNotificationLock")
5087     private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
5088             String pkg, String tag, int id, int userId) {
5089         final int len = list.size();
5090         for (int i = 0; i < len; i++) {
5091             NotificationRecord r = list.get(i);
5092             if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
5093                     TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
5094                 return r;
5095             }
5096         }
5097         return null;
5098     }
5099
5100     @GuardedBy("mNotificationLock")
5101     private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
5102             String key) {
5103         final int N = list.size();
5104         for (int i = 0; i < N; i++) {
5105             if (key.equals(list.get(i).getKey())) {
5106                 return list.get(i);
5107             }
5108         }
5109         return null;
5110     }
5111
5112     @GuardedBy("mNotificationLock")
5113     int indexOfNotificationLocked(String key) {
5114         final int N = mNotificationList.size();
5115         for (int i = 0; i < N; i++) {
5116             if (key.equals(mNotificationList.get(i).getKey())) {
5117                 return i;
5118             }
5119         }
5120         return -1;
5121     }
5122
5123     private void updateNotificationPulse() {
5124         synchronized (mNotificationLock) {
5125             updateLightsLocked();
5126         }
5127     }
5128
5129     protected boolean isCallingUidSystem() {
5130         final int uid = Binder.getCallingUid();
5131         return uid == Process.SYSTEM_UID;
5132     }
5133
5134     protected boolean isUidSystemOrPhone(int uid) {
5135         final int appid = UserHandle.getAppId(uid);
5136         return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
5137     }
5138
5139     // TODO: Most calls should probably move to isCallerSystem.
5140     protected boolean isCallerSystemOrPhone() {
5141         return isUidSystemOrPhone(Binder.getCallingUid());
5142     }
5143
5144     private void checkCallerIsSystemOrShell() {
5145         if (Binder.getCallingUid() == Process.SHELL_UID) {
5146             return;
5147         }
5148         checkCallerIsSystem();
5149     }
5150
5151     private void checkCallerIsSystem() {
5152         if (isCallerSystemOrPhone()) {
5153             return;
5154         }
5155         throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
5156     }
5157
5158     private void checkCallerIsSystemOrSameApp(String pkg) {
5159         if (isCallerSystemOrPhone()) {
5160             return;
5161         }
5162         checkCallerIsSameApp(pkg);
5163     }
5164
5165     private boolean isCallerInstantApp(String pkg) {
5166         // System is always allowed to act for ephemeral apps.
5167         if (isCallerSystemOrPhone()) {
5168             return false;
5169         }
5170
5171         mAppOps.checkPackage(Binder.getCallingUid(), pkg);
5172
5173         try {
5174             ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0,
5175                     UserHandle.getCallingUserId());
5176             if (ai == null) {
5177                 throw new SecurityException("Unknown package " + pkg);
5178             }
5179             return ai.isInstantApp();
5180         } catch (RemoteException re) {
5181             throw new SecurityException("Unknown package " + pkg, re);
5182         }
5183
5184     }
5185
5186     private void checkCallerIsSameApp(String pkg) {
5187         final int uid = Binder.getCallingUid();
5188         try {
5189             ApplicationInfo ai = mPackageManager.getApplicationInfo(
5190                     pkg, 0, UserHandle.getCallingUserId());
5191             if (ai == null) {
5192                 throw new SecurityException("Unknown package " + pkg);
5193             }
5194             if (!UserHandle.isSameApp(ai.uid, uid)) {
5195                 throw new SecurityException("Calling uid " + uid + " gave package "
5196                         + pkg + " which is owned by uid " + ai.uid);
5197             }
5198         } catch (RemoteException re) {
5199             throw new SecurityException("Unknown package " + pkg + "\n" + re);
5200         }
5201     }
5202
5203     private static String callStateToString(int state) {
5204         switch (state) {
5205             case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
5206             case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
5207             case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
5208             default: return "CALL_STATE_UNKNOWN_" + state;
5209         }
5210     }
5211
5212     private void listenForCallState() {
5213         TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
5214             @Override
5215             public void onCallStateChanged(int state, String incomingNumber) {
5216                 if (mCallState == state) return;
5217                 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
5218                 mCallState = state;
5219             }
5220         }, PhoneStateListener.LISTEN_CALL_STATE);
5221     }
5222
5223     /**
5224      * Generates a NotificationRankingUpdate from 'sbns', considering only
5225      * notifications visible to the given listener.
5226      */
5227     @GuardedBy("mNotificationLock")
5228     private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
5229         final int N = mNotificationList.size();
5230         ArrayList<String> keys = new ArrayList<String>(N);
5231         ArrayList<String> interceptedKeys = new ArrayList<String>(N);
5232         ArrayList<Integer> importance = new ArrayList<>(N);
5233         Bundle overrideGroupKeys = new Bundle();
5234         Bundle visibilityOverrides = new Bundle();
5235         Bundle suppressedVisualEffects = new Bundle();
5236         Bundle explanation = new Bundle();
5237         Bundle channels = new Bundle();
5238         Bundle overridePeople = new Bundle();
5239         Bundle snoozeCriteria = new Bundle();
5240         Bundle showBadge = new Bundle();
5241         for (int i = 0; i < N; i++) {
5242             NotificationRecord record = mNotificationList.get(i);
5243             if (!isVisibleToListener(record.sbn, info)) {
5244                 continue;
5245             }
5246             final String key = record.sbn.getKey();
5247             keys.add(key);
5248             importance.add(record.getImportance());
5249             if (record.getImportanceExplanation() != null) {
5250                 explanation.putCharSequence(key, record.getImportanceExplanation());
5251             }
5252             if (record.isIntercepted()) {
5253                 interceptedKeys.add(key);
5254
5255             }
5256             suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
5257             if (record.getPackageVisibilityOverride()
5258                     != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
5259                 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
5260             }
5261             overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
5262             channels.putParcelable(key, record.getChannel());
5263             overridePeople.putStringArrayList(key, record.getPeopleOverride());
5264             snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria());
5265             showBadge.putBoolean(key, record.canShowBadge());
5266         }
5267         final int M = keys.size();
5268         String[] keysAr = keys.toArray(new String[M]);
5269         String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
5270         int[] importanceAr = new int[M];
5271         for (int i = 0; i < M; i++) {
5272             importanceAr[i] = importance.get(i);
5273         }
5274         return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
5275                 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
5276                 channels, overridePeople, snoozeCriteria, showBadge);
5277     }
5278
5279     boolean hasCompanionDevice(ManagedServiceInfo info) {
5280         if (mCompanionManager == null) {
5281             mCompanionManager = getCompanionManager();
5282         }
5283         // Companion mgr doesn't exist on all device types
5284         if (mCompanionManager == null) {
5285             return false;
5286         }
5287         long identity = Binder.clearCallingIdentity();
5288         try {
5289             List<String> associations = mCompanionManager.getAssociations(
5290                     info.component.getPackageName(), info.userid);
5291             if (!ArrayUtils.isEmpty(associations)) {
5292                 return true;
5293             }
5294         } catch (SecurityException se) {
5295             // Not a privileged listener
5296         } catch (RemoteException re) {
5297             Slog.e(TAG, "Cannot reach companion device service", re);
5298         } catch (Exception e) {
5299             Slog.e(TAG, "Cannot verify listener " + info, e);
5300         } finally {
5301             Binder.restoreCallingIdentity(identity);
5302         }
5303         return false;
5304     }
5305
5306     protected ICompanionDeviceManager getCompanionManager() {
5307         return ICompanionDeviceManager.Stub.asInterface(
5308                 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
5309     }
5310
5311     private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
5312         if (!listener.enabledAndUserMatches(sbn.getUserId())) {
5313             return false;
5314         }
5315         // TODO: remove this for older listeners.
5316         return true;
5317     }
5318
5319     private boolean isPackageSuspendedForUser(String pkg, int uid) {
5320         int userId = UserHandle.getUserId(uid);
5321         try {
5322             return mPackageManager.isPackageSuspendedForUser(pkg, userId);
5323         } catch (RemoteException re) {
5324             throw new SecurityException("Could not talk to package manager service");
5325         } catch (IllegalArgumentException ex) {
5326             // Package not found.
5327             return false;
5328         }
5329     }
5330
5331     private class TrimCache {
5332         StatusBarNotification heavy;
5333         StatusBarNotification sbnClone;
5334         StatusBarNotification sbnCloneLight;
5335
5336         TrimCache(StatusBarNotification sbn) {
5337             heavy = sbn;
5338         }
5339
5340         StatusBarNotification ForListener(ManagedServiceInfo info) {
5341             if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
5342                 if (sbnCloneLight == null) {
5343                     sbnCloneLight = heavy.cloneLight();
5344                 }
5345                 return sbnCloneLight;
5346             } else {
5347                 if (sbnClone == null) {
5348                     sbnClone = heavy.clone();
5349                 }
5350                 return sbnClone;
5351             }
5352         }
5353     }
5354
5355     public class NotificationAssistants extends ManagedServices {
5356         static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
5357
5358         public NotificationAssistants(IPackageManager pm) {
5359             super(getContext(), mNotificationLock, mUserProfiles, pm);
5360         }
5361
5362         @Override
5363         protected Config getConfig() {
5364             Config c = new Config();
5365             c.caption = "notification assistant service";
5366             c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
5367             c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS;
5368             c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
5369             c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
5370             c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
5371             c.clientLabel = R.string.notification_ranker_binding_label;
5372             return c;
5373         }
5374
5375         @Override
5376         protected IInterface asInterface(IBinder binder) {
5377             return INotificationListener.Stub.asInterface(binder);
5378         }
5379
5380         @Override
5381         protected boolean checkType(IInterface service) {
5382             return service instanceof INotificationListener;
5383         }
5384
5385         @Override
5386         protected void onServiceAdded(ManagedServiceInfo info) {
5387             mListeners.registerGuestService(info);
5388         }
5389
5390         @Override
5391         @GuardedBy("mNotificationLock")
5392         protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
5393             mListeners.unregisterService(removed.service, removed.userid);
5394         }
5395
5396         public void onNotificationEnqueued(final NotificationRecord r) {
5397             final StatusBarNotification sbn = r.sbn;
5398             TrimCache trimCache = new TrimCache(sbn);
5399
5400             // There should be only one, but it's a list, so while we enforce
5401             // singularity elsewhere, we keep it general here, to avoid surprises.
5402             for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
5403                 boolean sbnVisible = isVisibleToListener(sbn, info);
5404                 if (!sbnVisible) {
5405                     continue;
5406                 }
5407
5408                 final int importance = r.getImportance();
5409                 final boolean fromUser = r.isImportanceFromUser();
5410                 final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
5411                 mHandler.post(new Runnable() {
5412                     @Override
5413                     public void run() {
5414                         notifyEnqueued(info, sbnToPost);
5415                     }
5416                 });
5417             }
5418         }
5419
5420         private void notifyEnqueued(final ManagedServiceInfo info,
5421                 final StatusBarNotification sbn) {
5422             final INotificationListener assistant = (INotificationListener) info.service;
5423             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5424             try {
5425                 assistant.onNotificationEnqueued(sbnHolder);
5426             } catch (RemoteException ex) {
5427                 Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
5428             }
5429         }
5430
5431         /**
5432          * asynchronously notify the assistant that a notification has been snoozed until a
5433          * context
5434          */
5435         @GuardedBy("mNotificationLock")
5436         public void notifyAssistantSnoozedLocked(final StatusBarNotification sbn,
5437                 final String snoozeCriterionId) {
5438             TrimCache trimCache = new TrimCache(sbn);
5439             for (final ManagedServiceInfo info : getServices()) {
5440                 final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
5441                 mHandler.post(new Runnable() {
5442                     @Override
5443                     public void run() {
5444                         final INotificationListener assistant =
5445                                 (INotificationListener) info.service;
5446                         StatusBarNotificationHolder sbnHolder
5447                                 = new StatusBarNotificationHolder(sbnToPost);
5448                         try {
5449                             assistant.onNotificationSnoozedUntilContext(
5450                                     sbnHolder, snoozeCriterionId);
5451                         } catch (RemoteException ex) {
5452                             Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
5453                         }
5454                     }
5455                 });
5456             }
5457         }
5458
5459         public boolean isEnabled() {
5460             return !getServices().isEmpty();
5461         }
5462     }
5463
5464     public class NotificationListeners extends ManagedServices {
5465         static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners";
5466
5467         private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
5468
5469         public NotificationListeners(IPackageManager pm) {
5470             super(getContext(), mNotificationLock, mUserProfiles, pm);
5471
5472         }
5473
5474         @Override
5475         protected Config getConfig() {
5476             Config c = new Config();
5477             c.caption = "notification listener";
5478             c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
5479             c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS;
5480             c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
5481             c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
5482             c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
5483             c.clientLabel = R.string.notification_listener_binding_label;
5484             return c;
5485         }
5486
5487         @Override
5488         protected IInterface asInterface(IBinder binder) {
5489             return INotificationListener.Stub.asInterface(binder);
5490         }
5491
5492         @Override
5493         protected boolean checkType(IInterface service) {
5494             return service instanceof INotificationListener;
5495         }
5496
5497         @Override
5498         public void onServiceAdded(ManagedServiceInfo info) {
5499             final INotificationListener listener = (INotificationListener) info.service;
5500             final NotificationRankingUpdate update;
5501             synchronized (mNotificationLock) {
5502                 update = makeRankingUpdateLocked(info);
5503             }
5504             try {
5505                 listener.onListenerConnected(update);
5506             } catch (RemoteException e) {
5507                 // we tried
5508             }
5509         }
5510
5511         @Override
5512         @GuardedBy("mNotificationLock")
5513         protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
5514             if (removeDisabledHints(removed)) {
5515                 updateListenerHintsLocked();
5516                 updateEffectsSuppressorLocked();
5517             }
5518             mLightTrimListeners.remove(removed);
5519         }
5520
5521         @GuardedBy("mNotificationLock")
5522         public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
5523             if (trim == TRIM_LIGHT) {
5524                 mLightTrimListeners.add(info);
5525             } else {
5526                 mLightTrimListeners.remove(info);
5527             }
5528         }
5529
5530         public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
5531             return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
5532         }
5533
5534         /**
5535          * asynchronously notify all listeners about a new notification
5536          *
5537          * <p>
5538          * Also takes care of removing a notification that has been visible to a listener before,
5539          * but isn't anymore.
5540          */
5541         @GuardedBy("mNotificationLock")
5542         public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
5543             // Lazily initialized snapshots of the notification.
5544             TrimCache trimCache = new TrimCache(sbn);
5545
5546             for (final ManagedServiceInfo info : getServices()) {
5547                 boolean sbnVisible = isVisibleToListener(sbn, info);
5548                 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
5549                 // This notification hasn't been and still isn't visible -> ignore.
5550                 if (!oldSbnVisible && !sbnVisible) {
5551                     continue;
5552                 }
5553                 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
5554
5555                 // This notification became invisible -> remove the old one.
5556                 if (oldSbnVisible && !sbnVisible) {
5557                     final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
5558                     mHandler.post(new Runnable() {
5559                         @Override
5560                         public void run() {
5561                             notifyRemoved(info, oldSbnLightClone, update, REASON_USER_STOPPED);
5562                         }
5563                     });
5564                     continue;
5565                 }
5566
5567                 final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
5568                 mHandler.post(new Runnable() {
5569                     @Override
5570                     public void run() {
5571                         notifyPosted(info, sbnToPost, update);
5572                     }
5573                 });
5574             }
5575         }
5576
5577         /**
5578          * asynchronously notify all listeners about a removed notification
5579          */
5580         @GuardedBy("mNotificationLock")
5581         public void notifyRemovedLocked(StatusBarNotification sbn, int reason) {
5582             // make a copy in case changes are made to the underlying Notification object
5583             // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
5584             // notification
5585             final StatusBarNotification sbnLight = sbn.cloneLight();
5586             for (final ManagedServiceInfo info : getServices()) {
5587                 if (!isVisibleToListener(sbn, info)) {
5588                     continue;
5589                 }
5590                 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
5591                 mHandler.post(new Runnable() {
5592                     @Override
5593                     public void run() {
5594                         notifyRemoved(info, sbnLight, update, reason);
5595                     }
5596                 });
5597             }
5598         }
5599
5600         /**
5601          * asynchronously notify all listeners about a reordering of notifications
5602          */
5603         @GuardedBy("mNotificationLock")
5604         public void notifyRankingUpdateLocked() {
5605             for (final ManagedServiceInfo serviceInfo : getServices()) {
5606                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5607                     continue;
5608                 }
5609                 final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
5610                 mHandler.post(new Runnable() {
5611                     @Override
5612                     public void run() {
5613                         notifyRankingUpdate(serviceInfo, update);
5614                     }
5615                 });
5616             }
5617         }
5618
5619         @GuardedBy("mNotificationLock")
5620         public void notifyListenerHintsChangedLocked(final int hints) {
5621             for (final ManagedServiceInfo serviceInfo : getServices()) {
5622                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5623                     continue;
5624                 }
5625                 mHandler.post(new Runnable() {
5626                     @Override
5627                     public void run() {
5628                         notifyListenerHintsChanged(serviceInfo, hints);
5629                     }
5630                 });
5631             }
5632         }
5633
5634         public void notifyInterruptionFilterChanged(final int interruptionFilter) {
5635             for (final ManagedServiceInfo serviceInfo : getServices()) {
5636                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5637                     continue;
5638                 }
5639                 mHandler.post(new Runnable() {
5640                     @Override
5641                     public void run() {
5642                         notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
5643                     }
5644                 });
5645             }
5646         }
5647
5648         protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user,
5649                 final NotificationChannel channel, final int modificationType) {
5650             if (channel == null) {
5651                 return;
5652             }
5653             for (final ManagedServiceInfo serviceInfo : getServices()) {
5654                 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
5655                     continue;
5656                 }
5657
5658                 BackgroundThread.getHandler().post(() -> {
5659                     if (hasCompanionDevice(serviceInfo)) {
5660                         notifyNotificationChannelChanged(
5661                                 serviceInfo, pkg, user, channel, modificationType);
5662                     }
5663                 });
5664             }
5665         }
5666
5667         protected void notifyNotificationChannelGroupChanged(
5668                 final String pkg, final UserHandle user, final NotificationChannelGroup group,
5669                 final int modificationType) {
5670             if (group == null) {
5671                 return;
5672             }
5673             for (final ManagedServiceInfo serviceInfo : getServices()) {
5674                 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
5675                     continue;
5676                 }
5677
5678                 BackgroundThread.getHandler().post(() -> {
5679                     if (hasCompanionDevice(serviceInfo)) {
5680                         notifyNotificationChannelGroupChanged(
5681                                 serviceInfo, pkg, user, group, modificationType);
5682                     }
5683                 });
5684             }
5685         }
5686
5687         private void notifyPosted(final ManagedServiceInfo info,
5688                 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
5689             final INotificationListener listener = (INotificationListener) info.service;
5690             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5691             try {
5692                 listener.onNotificationPosted(sbnHolder, rankingUpdate);
5693             } catch (RemoteException ex) {
5694                 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
5695             }
5696         }
5697
5698         private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
5699                 NotificationRankingUpdate rankingUpdate, int reason) {
5700             if (!info.enabledAndUserMatches(sbn.getUserId())) {
5701                 return;
5702             }
5703             final INotificationListener listener = (INotificationListener) info.service;
5704             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5705             try {
5706                 listener.onNotificationRemoved(sbnHolder, rankingUpdate, reason);
5707             } catch (RemoteException ex) {
5708                 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
5709             }
5710         }
5711
5712         private void notifyRankingUpdate(ManagedServiceInfo info,
5713                                          NotificationRankingUpdate rankingUpdate) {
5714             final INotificationListener listener = (INotificationListener) info.service;
5715             try {
5716                 listener.onNotificationRankingUpdate(rankingUpdate);
5717             } catch (RemoteException ex) {
5718                 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
5719             }
5720         }
5721
5722         private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
5723             final INotificationListener listener = (INotificationListener) info.service;
5724             try {
5725                 listener.onListenerHintsChanged(hints);
5726             } catch (RemoteException ex) {
5727                 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
5728             }
5729         }
5730
5731         private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
5732                 int interruptionFilter) {
5733             final INotificationListener listener = (INotificationListener) info.service;
5734             try {
5735                 listener.onInterruptionFilterChanged(interruptionFilter);
5736             } catch (RemoteException ex) {
5737                 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
5738             }
5739         }
5740
5741         void notifyNotificationChannelChanged(ManagedServiceInfo info,
5742                 final String pkg, final UserHandle user, final NotificationChannel channel,
5743                 final int modificationType) {
5744             final INotificationListener listener = (INotificationListener) info.service;
5745             try {
5746                 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
5747             } catch (RemoteException ex) {
5748                 Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
5749             }
5750         }
5751
5752         private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
5753                 final String pkg, final UserHandle user, final NotificationChannelGroup group,
5754                 final int modificationType) {
5755             final INotificationListener listener = (INotificationListener) info.service;
5756             try {
5757                 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
5758             } catch (RemoteException ex) {
5759                 Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
5760             }
5761         }
5762
5763         public boolean isListenerPackage(String packageName) {
5764             if (packageName == null) {
5765                 return false;
5766             }
5767             // TODO: clean up locking object later
5768             synchronized (mNotificationLock) {
5769                 for (final ManagedServiceInfo serviceInfo : getServices()) {
5770                     if (packageName.equals(serviceInfo.component.getPackageName())) {
5771                         return true;
5772                     }
5773                 }
5774             }
5775             return false;
5776         }
5777     }
5778
5779     public static final class DumpFilter {
5780         public boolean filtered = false;
5781         public String pkgFilter;
5782         public boolean zen;
5783         public long since;
5784         public boolean stats;
5785         public boolean redact = true;
5786         public boolean proto = false;
5787
5788         public static DumpFilter parseFromArguments(String[] args) {
5789             final DumpFilter filter = new DumpFilter();
5790             for (int ai = 0; ai < args.length; ai++) {
5791                 final String a = args[ai];
5792                 if ("--proto".equals(args[0])) {
5793                     filter.proto = true;
5794                 }
5795                 if ("--noredact".equals(a) || "--reveal".equals(a)) {
5796                     filter.redact = false;
5797                 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
5798                     if (ai < args.length-1) {
5799                         ai++;
5800                         filter.pkgFilter = args[ai].trim().toLowerCase();
5801                         if (filter.pkgFilter.isEmpty()) {
5802                             filter.pkgFilter = null;
5803                         } else {
5804                             filter.filtered = true;
5805                         }
5806                     }
5807                 } else if ("--zen".equals(a) || "zen".equals(a)) {
5808                     filter.filtered = true;
5809                     filter.zen = true;
5810                 } else if ("--stats".equals(a)) {
5811                     filter.stats = true;
5812                     if (ai < args.length-1) {
5813                         ai++;
5814                         filter.since = Long.parseLong(args[ai]);
5815                     } else {
5816                         filter.since = 0;
5817                     }
5818                 }
5819             }
5820             return filter;
5821         }
5822
5823         public boolean matches(StatusBarNotification sbn) {
5824             if (!filtered) return true;
5825             return zen ? true : sbn != null
5826                     && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
5827         }
5828
5829         public boolean matches(ComponentName component) {
5830             if (!filtered) return true;
5831             return zen ? true : component != null && matches(component.getPackageName());
5832         }
5833
5834         public boolean matches(String pkg) {
5835             if (!filtered) return true;
5836             return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
5837         }
5838
5839         @Override
5840         public String toString() {
5841             return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
5842         }
5843     }
5844
5845     /**
5846      * Wrapper for a StatusBarNotification object that allows transfer across a oneway
5847      * binder without sending large amounts of data over a oneway transaction.
5848      */
5849     private static final class StatusBarNotificationHolder
5850             extends IStatusBarNotificationHolder.Stub {
5851         private StatusBarNotification mValue;
5852
5853         public StatusBarNotificationHolder(StatusBarNotification value) {
5854             mValue = value;
5855         }
5856
5857         /** Get the held value and clear it. This function should only be called once per holder */
5858         @Override
5859         public StatusBarNotification get() {
5860             StatusBarNotification value = mValue;
5861             mValue = null;
5862             return value;
5863         }
5864     }
5865
5866     private class ShellCmd extends ShellCommand {
5867         public static final String USAGE = "help\n"
5868                 + "allow_listener COMPONENT [user_id]\n"
5869                 + "disallow_listener COMPONENT [user_id]\n"
5870                 + "set_assistant COMPONENT\n"
5871                 + "remove_assistant COMPONENT\n"
5872                 + "allow_dnd PACKAGE\n"
5873                 + "disallow_dnd PACKAGE";
5874
5875         @Override
5876         public int onCommand(String cmd) {
5877             if (cmd == null) {
5878                 return handleDefaultCommands(cmd);
5879             }
5880             final PrintWriter pw = getOutPrintWriter();
5881             try {
5882                 switch (cmd) {
5883                     case "allow_dnd": {
5884                         getBinderService().setNotificationPolicyAccessGranted(
5885                                 getNextArgRequired(), true);
5886                     }
5887                     break;
5888
5889                     case "disallow_dnd": {
5890                         getBinderService().setNotificationPolicyAccessGranted(
5891                                 getNextArgRequired(), false);
5892                     }
5893                     break;
5894                     case "allow_listener": {
5895                         ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
5896                         if (cn == null) {
5897                             pw.println("Invalid listener - must be a ComponentName");
5898                             return -1;
5899                         }
5900                         String userId = getNextArg();
5901                         if (userId == null) {
5902                             getBinderService().setNotificationListenerAccessGranted(cn, true);
5903                         } else {
5904                             getBinderService().setNotificationListenerAccessGrantedForUser(
5905                                     cn, Integer.parseInt(userId), true);
5906                         }
5907                     }
5908                     break;
5909                     case "disallow_listener": {
5910                         ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
5911                         if (cn == null) {
5912                             pw.println("Invalid listener - must be a ComponentName");
5913                             return -1;
5914                         }
5915                         String userId = getNextArg();
5916                         if (userId == null) {
5917                             getBinderService().setNotificationListenerAccessGranted(cn, false);
5918                         } else {
5919                             getBinderService().setNotificationListenerAccessGrantedForUser(
5920                                     cn, Integer.parseInt(userId), false);
5921                         }
5922                     }
5923                     break;
5924                     case "allow_assistant": {
5925                         ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
5926                         if (cn == null) {
5927                             pw.println("Invalid assistant - must be a ComponentName");
5928                             return -1;
5929                         }
5930                         getBinderService().setNotificationAssistantAccessGranted(cn, true);
5931                     }
5932                     break;
5933                     case "disallow_assistant": {
5934                         ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
5935                         if (cn == null) {
5936                             pw.println("Invalid assistant - must be a ComponentName");
5937                             return -1;
5938                         }
5939                         getBinderService().setNotificationAssistantAccessGranted(cn, false);
5940                     }
5941                     break;
5942
5943                     default:
5944                         return handleDefaultCommands(cmd);
5945                 }
5946             } catch (Exception e) {
5947                 pw.println("Error occurred. Check logcat for details. " + e.getMessage());
5948                 Slog.e(TAG, "Error running shell command", e);
5949             }
5950             return 0;
5951         }
5952
5953         @Override
5954         public void onHelp() {
5955             getOutPrintWriter().println(USAGE);
5956         }
5957     }
5958 }