OSDN Git Service

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