OSDN Git Service

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