OSDN Git Service

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