OSDN Git Service

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