OSDN Git Service

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