2 * Copyright (C) 2007 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.server.notification;
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.service.notification.NotificationListenerService
24 .NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
25 import static android.service.notification.NotificationListenerService
26 .NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
27 import static android.service.notification.NotificationListenerService
28 .NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
29 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
30 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
31 import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
32 import static android.service.notification.NotificationListenerService.REASON_CANCEL;
33 import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
34 import static android.service.notification.NotificationListenerService.REASON_CLICK;
35 import static android.service.notification.NotificationListenerService.REASON_ERROR;
36 import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
37 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL;
38 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL;
39 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED;
40 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED;
41 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED;
42 import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF;
43 import static android.service.notification.NotificationListenerService.REASON_SNOOZED;
44 import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
45 import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
46 import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
47 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
48 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
49 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
50 import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
51 import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
52 import static android.service.notification.NotificationListenerService.TRIM_FULL;
53 import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
55 import static android.view.Display.DEFAULT_DISPLAY;
56 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
57 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
59 import android.Manifest;
60 import android.annotation.NonNull;
61 import android.annotation.Nullable;
62 import android.app.ActivityManager;
63 import android.app.ActivityManagerInternal;
64 import android.app.AlarmManager;
65 import android.app.AppGlobals;
66 import android.app.AppOpsManager;
67 import android.app.AutomaticZenRule;
68 import android.app.NotificationChannelGroup;
69 import android.app.backup.BackupManager;
70 import android.app.IActivityManager;
71 import android.app.INotificationManager;
72 import android.app.ITransientNotification;
73 import android.app.Notification;
74 import android.app.NotificationChannel;
75 import android.app.NotificationManager.Policy;
76 import android.app.NotificationManager;
77 import android.app.PendingIntent;
78 import android.app.StatusBarManager;
79 import android.app.usage.UsageEvents;
80 import android.app.usage.UsageStatsManagerInternal;
81 import android.companion.ICompanionDeviceManager;
82 import android.content.BroadcastReceiver;
83 import android.content.ComponentName;
84 import android.content.ContentResolver;
85 import android.content.Context;
86 import android.content.Intent;
87 import android.content.IntentFilter;
88 import android.content.pm.ApplicationInfo;
89 import android.content.pm.IPackageManager;
90 import android.content.pm.PackageInfo;
91 import android.content.pm.PackageManager;
92 import android.content.pm.PackageManager.NameNotFoundException;
93 import android.content.pm.ParceledListSlice;
94 import android.content.res.Resources;
95 import android.database.ContentObserver;
96 import android.media.AudioManager;
97 import android.media.AudioManagerInternal;
98 import android.media.IRingtonePlayer;
99 import android.media.ToneGenerator;
100 import android.net.Uri;
101 import android.os.Binder;
102 import android.os.Build;
103 import android.os.Bundle;
104 import android.os.Environment;
105 import android.os.Handler;
106 import android.os.HandlerThread;
107 import android.os.IBinder;
108 import android.os.IInterface;
109 import android.os.Looper;
110 import android.os.Message;
111 import android.os.Process;
112 import android.os.RemoteException;
113 import android.os.ServiceManager;
114 import android.os.SystemClock;
115 import android.os.SystemProperties;
116 import android.os.UserHandle;
117 import android.os.Vibrator;
118 import android.os.VibrationEffect;
119 import android.provider.Settings;
120 import android.service.notification.Adjustment;
121 import android.service.notification.Condition;
122 import android.service.notification.IConditionProvider;
123 import android.service.notification.INotificationListener;
124 import android.service.notification.IStatusBarNotificationHolder;
125 import android.service.notification.NotificationAssistantService;
126 import android.service.notification.NotificationListenerService;
127 import android.service.notification.NotificationRankingUpdate;
128 import android.service.notification.NotificationRecordProto;
129 import android.service.notification.NotificationServiceDumpProto;
130 import android.service.notification.NotificationServiceProto;
131 import android.service.notification.SnoozeCriterion;
132 import android.service.notification.StatusBarNotification;
133 import android.service.notification.ZenModeConfig;
134 import android.service.notification.ZenModeProto;
135 import android.telephony.PhoneStateListener;
136 import android.telephony.TelephonyManager;
137 import android.text.TextUtils;
138 import android.util.ArrayMap;
139 import android.util.ArraySet;
140 import android.util.AtomicFile;
141 import android.util.Log;
142 import android.util.Slog;
143 import android.util.SparseArray;
144 import android.util.Xml;
145 import android.util.proto.ProtoOutputStream;
146 import android.view.WindowManagerInternal;
147 import android.view.accessibility.AccessibilityEvent;
148 import android.view.accessibility.AccessibilityManager;
149 import android.widget.Toast;
151 import com.android.internal.R;
152 import com.android.internal.annotations.GuardedBy;
153 import com.android.internal.annotations.VisibleForTesting;
154 import com.android.internal.logging.MetricsLogger;
155 import com.android.internal.logging.nano.MetricsProto;
156 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
157 import com.android.internal.statusbar.NotificationVisibility;
158 import com.android.internal.util.ArrayUtils;
159 import com.android.internal.util.DumpUtils;
160 import com.android.internal.util.FastXmlSerializer;
161 import com.android.internal.util.Preconditions;
162 import com.android.server.DeviceIdleController;
163 import com.android.server.EventLogTags;
164 import com.android.server.LocalServices;
165 import com.android.server.SystemService;
166 import com.android.server.lights.Light;
167 import com.android.server.lights.LightsManager;
168 import com.android.server.notification.ManagedServices.ManagedServiceInfo;
169 import com.android.server.policy.PhoneWindowManager;
170 import com.android.server.statusbar.StatusBarManagerInternal;
171 import com.android.server.notification.ManagedServices.UserProfiles;
173 import libcore.io.IoUtils;
175 import org.json.JSONException;
176 import org.json.JSONObject;
177 import org.xmlpull.v1.XmlPullParser;
178 import org.xmlpull.v1.XmlPullParserException;
179 import org.xmlpull.v1.XmlSerializer;
181 import java.io.ByteArrayInputStream;
182 import java.io.ByteArrayOutputStream;
184 import java.io.FileDescriptor;
185 import java.io.FileInputStream;
186 import java.io.FileNotFoundException;
187 import java.io.FileOutputStream;
188 import java.io.IOException;
189 import java.io.InputStream;
190 import java.io.OutputStream;
191 import java.io.PrintWriter;
192 import java.nio.charset.StandardCharsets;
193 import java.util.ArrayDeque;
194 import java.util.ArrayList;
195 import java.util.Arrays;
196 import java.util.Iterator;
197 import java.util.List;
198 import java.util.Map;
199 import java.util.Map.Entry;
200 import java.util.Objects;
201 import java.util.concurrent.TimeUnit;
204 public class NotificationManagerService extends SystemService {
205 static final String TAG = "NotificationService";
206 static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
207 public static final boolean ENABLE_CHILD_NOTIFICATIONS
208 = SystemProperties.getBoolean("debug.child_notifs", true);
210 static final int MAX_PACKAGE_NOTIFICATIONS = 50;
211 static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 10f;
214 static final int MESSAGE_TIMEOUT = 2;
215 static final int MESSAGE_SAVE_POLICY_FILE = 3;
216 static final int MESSAGE_SEND_RANKING_UPDATE = 4;
217 static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
218 static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
220 // ranking thread messages
221 private static final int MESSAGE_RECONSIDER_RANKING = 1000;
222 private static final int MESSAGE_RANKING_SORT = 1001;
224 static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
225 static final int SHORT_DELAY = 2000; // 2 seconds
227 static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
229 static final long SNOOZE_UNTIL_UNSPECIFIED = -1;
231 static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
233 static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
235 static final boolean ENABLE_BLOCKED_TOASTS = true;
237 // When #matchesCallFilter is called from the ringer, wait at most
238 // 3s to resolve the contacts. This timeout is required since
239 // ContactsProvider might take a long time to start up.
241 // Return STARRED_CONTACT when the timeout is hit in order to avoid
242 // missed calls in ZEN mode "Important".
243 static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
244 static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
245 ValidateNotificationPeople.STARRED_CONTACT;
247 /** notification_enqueue status value for a newly enqueued notification. */
248 private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
250 /** notification_enqueue status value for an existing notification. */
251 private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
253 /** notification_enqueue status value for an ignored notification. */
254 private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
255 private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
257 private static final long DELAY_FOR_ASSISTANT_TIME = 100;
259 private static final String ACTION_NOTIFICATION_TIMEOUT =
260 NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
261 private static final int REQUEST_CODE_TIMEOUT = 1;
262 private static final String SCHEME_TIMEOUT = "timeout";
263 private static final String EXTRA_KEY = "key";
265 private IActivityManager mAm;
266 private IPackageManager mPackageManager;
267 private PackageManager mPackageManagerClient;
268 AudioManager mAudioManager;
269 AudioManagerInternal mAudioManagerInternal;
270 @Nullable StatusBarManagerInternal mStatusBar;
272 private WindowManagerInternal mWindowManagerInternal;
273 private AlarmManager mAlarmManager;
274 private ICompanionDeviceManager mCompanionManager;
276 final IBinder mForegroundToken = new Binder();
277 private Handler mHandler;
278 private final HandlerThread mRankingThread = new HandlerThread("ranker",
279 Process.THREAD_PRIORITY_BACKGROUND);
281 private Light mNotificationLight;
282 Light mAttentionLight;
284 private long[] mFallbackVibrationPattern;
285 private boolean mUseAttentionLight;
286 boolean mSystemReady;
288 private boolean mDisableNotificationEffects;
289 private int mCallState;
290 private String mSoundNotificationKey;
291 private String mVibrateNotificationKey;
293 private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
294 new SparseArray<ArraySet<ManagedServiceInfo>>();
295 private List<ComponentName> mEffectsSuppressors = new ArrayList<ComponentName>();
296 private int mListenerHints; // right now, all hints are global
297 private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
299 // for enabling and disabling notification pulse behavior
300 private boolean mScreenOn = true;
301 private boolean mInCall = false;
302 private boolean mNotificationPulseEnabled;
304 // for generating notification tones in-call
305 private ToneGenerator mInCallToneGenerator;
306 private final Object mInCallToneGeneratorLock = new Object();
308 // used as a mutex for access to all active notifications & listeners
309 final Object mNotificationLock = new Object();
310 @GuardedBy("mNotificationLock")
311 final ArrayList<NotificationRecord> mNotificationList =
312 new ArrayList<NotificationRecord>();
313 @GuardedBy("mNotificationLock")
314 final ArrayMap<String, NotificationRecord> mNotificationsByKey =
315 new ArrayMap<String, NotificationRecord>();
316 @GuardedBy("mNotificationLock")
317 final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();
318 @GuardedBy("mNotificationLock")
319 final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
320 final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();
321 final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
322 final PolicyAccess mPolicyAccess = new PolicyAccess();
324 // The last key in this list owns the hardware.
325 ArrayList<String> mLights = new ArrayList<>();
327 private AppOpsManager mAppOps;
328 private UsageStatsManagerInternal mAppUsageStats;
330 private Archive mArchive;
332 // Persistent storage for notification policy
333 private AtomicFile mPolicyFile;
335 private static final int DB_VERSION = 1;
337 private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
338 private static final String ATTR_VERSION = "version";
340 private RankingHelper mRankingHelper;
342 private final UserProfiles mUserProfiles = new UserProfiles();
343 private NotificationListeners mListeners;
344 private NotificationAssistants mNotificationAssistants;
345 private ConditionProviders mConditionProviders;
346 private NotificationUsageStats mUsageStats;
348 private static final int MY_UID = Process.myUid();
349 private static final int MY_PID = Process.myPid();
350 private static final IBinder WHITELIST_TOKEN = new Binder();
351 private RankingHandler mRankingHandler;
352 private long mLastOverRateLogTime;
353 private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
355 private SnoozeHelper mSnoozeHelper;
356 private GroupHelper mGroupHelper;
357 private boolean mIsTelevision;
359 private static class Archive {
360 final int mBufferSize;
361 final ArrayDeque<StatusBarNotification> mBuffer;
363 public Archive(int size) {
365 mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
368 public String toString() {
369 final StringBuilder sb = new StringBuilder();
370 final int N = mBuffer.size();
371 sb.append("Archive (");
373 sb.append(" notification");
374 sb.append((N==1)?")":"s)");
375 return sb.toString();
378 public void record(StatusBarNotification nr) {
379 if (mBuffer.size() == mBufferSize) {
380 mBuffer.removeFirst();
383 // We don't want to store the heavy bits of the notification in the archive,
384 // but other clients in the system process might be using the object, so we
385 // store a (lightened) copy.
386 mBuffer.addLast(nr.cloneLight());
389 public Iterator<StatusBarNotification> descendingIterator() {
390 return mBuffer.descendingIterator();
393 public StatusBarNotification[] getArray(int count) {
394 if (count == 0) count = mBufferSize;
395 final StatusBarNotification[] a
396 = new StatusBarNotification[Math.min(count, mBuffer.size())];
397 Iterator<StatusBarNotification> iter = descendingIterator();
399 while (iter.hasNext() && i < count) {
400 a[i++] = iter.next();
407 private void readPolicyXml(InputStream stream, boolean forRestore)
408 throws XmlPullParserException, NumberFormatException, IOException {
409 final XmlPullParser parser = Xml.newPullParser();
410 parser.setInput(stream, StandardCharsets.UTF_8.name());
412 while (parser.next() != END_DOCUMENT) {
413 mZenModeHelper.readXml(parser, forRestore);
414 mRankingHelper.readXml(parser, forRestore);
418 private void loadPolicyFile() {
419 if (DBG) Slog.d(TAG, "loadPolicyFile");
420 synchronized (mPolicyFile) {
422 FileInputStream infile = null;
424 infile = mPolicyFile.openRead();
425 readPolicyXml(infile, false /*forRestore*/);
426 } catch (FileNotFoundException e) {
428 } catch (IOException e) {
429 Log.wtf(TAG, "Unable to read notification policy", e);
430 } catch (NumberFormatException e) {
431 Log.wtf(TAG, "Unable to parse notification policy", e);
432 } catch (XmlPullParserException e) {
433 Log.wtf(TAG, "Unable to parse notification policy", e);
435 IoUtils.closeQuietly(infile);
440 public void savePolicyFile() {
441 mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
442 mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
445 private void handleSavePolicyFile() {
446 if (DBG) Slog.d(TAG, "handleSavePolicyFile");
447 synchronized (mPolicyFile) {
448 final FileOutputStream stream;
450 stream = mPolicyFile.startWrite();
451 } catch (IOException e) {
452 Slog.w(TAG, "Failed to save policy file", e);
457 writePolicyXml(stream, false /*forBackup*/);
458 mPolicyFile.finishWrite(stream);
459 } catch (IOException e) {
460 Slog.w(TAG, "Failed to save policy file, restoring backup", e);
461 mPolicyFile.failWrite(stream);
464 BackupManager.dataChanged(getContext().getPackageName());
467 private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
468 final XmlSerializer out = new FastXmlSerializer();
469 out.setOutput(stream, StandardCharsets.UTF_8.name());
470 out.startDocument(null, true);
471 out.startTag(null, TAG_NOTIFICATION_POLICY);
472 out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
473 mZenModeHelper.writeXml(out, forBackup);
474 mRankingHelper.writeXml(out, forBackup);
475 out.endTag(null, TAG_NOTIFICATION_POLICY);
479 /** Use this to check if a package can post a notification or toast. */
480 private boolean checkNotificationOp(String pkg, int uid) {
481 return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
482 == AppOpsManager.MODE_ALLOWED && !isPackageSuspendedForUser(pkg, uid);
485 private static final class ToastRecord
489 final ITransientNotification callback;
493 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
497 this.callback = callback;
498 this.duration = duration;
502 void update(int duration) {
503 this.duration = duration;
506 void dump(PrintWriter pw, String prefix, DumpFilter filter) {
507 if (filter != null && !filter.matches(pkg)) return;
508 pw.println(prefix + this);
512 public final String toString()
514 return "ToastRecord{"
515 + Integer.toHexString(System.identityHashCode(this))
517 + " callback=" + callback
518 + " duration=" + duration;
523 final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
526 public void onSetDisabled(int status) {
527 synchronized (mNotificationLock) {
528 mDisableNotificationEffects =
529 (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
530 if (disableNotificationEffects(null) != null) {
531 // cancel whatever's going on
532 long identity = Binder.clearCallingIdentity();
534 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
535 if (player != null) {
538 } catch (RemoteException e) {
540 Binder.restoreCallingIdentity(identity);
543 identity = Binder.clearCallingIdentity();
547 Binder.restoreCallingIdentity(identity);
554 public void onClearAll(int callingUid, int callingPid, int userId) {
555 synchronized (mNotificationLock) {
556 cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null,
557 /*includeCurrentProfiles*/ true);
562 public void onNotificationClick(int callingUid, int callingPid, String key) {
563 synchronized (mNotificationLock) {
564 NotificationRecord r = mNotificationsByKey.get(key);
566 Log.w(TAG, "No notification with key: " + key);
569 final long now = System.currentTimeMillis();
570 MetricsLogger.action(r.getLogMaker(now)
571 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
572 .setType(MetricsEvent.TYPE_ACTION));
573 EventLogTags.writeNotificationClicked(key,
574 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
576 StatusBarNotification sbn = r.sbn;
577 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
578 sbn.getId(), Notification.FLAG_AUTO_CANCEL,
579 Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
585 public void onNotificationActionClick(int callingUid, int callingPid, String key,
587 synchronized (mNotificationLock) {
588 NotificationRecord r = mNotificationsByKey.get(key);
590 Log.w(TAG, "No notification with key: " + key);
593 final long now = System.currentTimeMillis();
594 MetricsLogger.action(r.getLogMaker(now)
595 .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION)
596 .setType(MetricsEvent.TYPE_ACTION)
597 .setSubtype(actionIndex));
598 EventLogTags.writeNotificationActionClicked(key, actionIndex,
599 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
600 // TODO: Log action click via UsageStats.
605 public void onNotificationClear(int callingUid, int callingPid,
606 String pkg, String tag, int id, int userId) {
607 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
608 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
609 true, userId, REASON_CANCEL, null);
613 public void onPanelRevealed(boolean clearEffects, int items) {
614 MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL);
615 MetricsLogger.histogram(getContext(), "note_load", items);
616 EventLogTags.writeNotificationPanelRevealed(items);
623 public void onPanelHidden() {
624 MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL);
625 EventLogTags.writeNotificationPanelHidden();
629 public void clearEffects() {
630 synchronized (mNotificationLock) {
631 if (DBG) Slog.d(TAG, "clearEffects");
633 clearVibrateLocked();
639 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
640 int uid, int initialPid, String message, int userId) {
641 Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
642 + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
643 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
645 long ident = Binder.clearCallingIdentity();
647 ActivityManager.getService().crashApplication(uid, initialPid, pkg, -1,
648 "Bad notification posted from package " + pkg
650 } catch (RemoteException e) {
652 Binder.restoreCallingIdentity(ident);
656 public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
657 NotificationVisibility[] noLongerVisibleKeys) {
658 synchronized (mNotificationLock) {
659 for (NotificationVisibility nv : newlyVisibleKeys) {
660 NotificationRecord r = mNotificationsByKey.get(nv.key);
661 if (r == null) continue;
662 r.setVisibility(true, nv.rank);
665 // Note that we might receive this event after notifications
666 // have already left the system, e.g. after dismissing from the
667 // shade. Hence not finding notifications in
668 // mNotificationsByKey is not an exceptional condition.
669 for (NotificationVisibility nv : noLongerVisibleKeys) {
670 NotificationRecord r = mNotificationsByKey.get(nv.key);
671 if (r == null) continue;
672 r.setVisibility(false, nv.rank);
679 public void onNotificationExpansionChanged(String key,
680 boolean userAction, boolean expanded) {
681 synchronized (mNotificationLock) {
682 NotificationRecord r = mNotificationsByKey.get(key);
684 r.stats.onExpansionChanged(userAction, expanded);
685 final long now = System.currentTimeMillis();
686 MetricsLogger.action(r.getLogMaker(now)
687 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
688 .setType(MetricsEvent.TYPE_DETAIL));
689 EventLogTags.writeNotificationExpansion(key,
690 userAction ? 1 : 0, expanded ? 1 : 0,
691 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
697 @GuardedBy("mNotificationLock")
698 private void clearSoundLocked() {
699 mSoundNotificationKey = null;
700 long identity = Binder.clearCallingIdentity();
702 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
703 if (player != null) {
706 } catch (RemoteException e) {
708 Binder.restoreCallingIdentity(identity);
712 @GuardedBy("mNotificationLock")
713 private void clearVibrateLocked() {
714 mVibrateNotificationKey = null;
715 long identity = Binder.clearCallingIdentity();
719 Binder.restoreCallingIdentity(identity);
723 @GuardedBy("mNotificationLock")
724 private void clearLightsLocked() {
727 updateLightsLocked();
730 private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() {
732 public void onReceive(Context context, Intent intent) {
733 String action = intent.getAction();
734 if (action == null) {
737 if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) {
738 final NotificationRecord record;
739 synchronized (mNotificationLock) {
740 record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
742 if (record != null) {
743 cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(),
744 record.sbn.getPackageName(), record.sbn.getTag(),
745 record.sbn.getId(), 0,
746 Notification.FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
747 REASON_TIMEOUT, null);
753 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
755 public void onReceive(Context context, Intent intent) {
756 String action = intent.getAction();
757 if (action == null) {
761 boolean queryRestart = false;
762 boolean queryRemove = false;
763 boolean packageChanged = false;
764 boolean cancelNotifications = true;
765 int reason = REASON_PACKAGE_CHANGED;
767 if (action.equals(Intent.ACTION_PACKAGE_ADDED)
768 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
769 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
770 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
771 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
772 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
773 || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
774 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
775 UserHandle.USER_ALL);
776 String pkgList[] = null;
777 int uidList[] = null;
778 boolean removingPackage = queryRemove &&
779 !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
780 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
781 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
782 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
783 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
784 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
785 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
786 reason = REASON_PACKAGE_SUSPENDED;
787 } else if (queryRestart) {
788 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
789 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
791 Uri uri = intent.getData();
795 String pkgName = uri.getSchemeSpecificPart();
796 if (pkgName == null) {
799 if (packageChanged) {
800 // We cancel notifications for packages which have just been disabled
802 final int enabled = mPackageManager.getApplicationEnabledSetting(
804 changeUserId != UserHandle.USER_ALL ? changeUserId :
805 UserHandle.USER_SYSTEM);
806 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
807 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
808 cancelNotifications = false;
810 } catch (IllegalArgumentException e) {
811 // Package doesn't exist; probably racing with uninstall.
812 // cancelNotifications is already true, so nothing to do here.
814 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
816 } catch (RemoteException e) {
817 // Failed to talk to PackageManagerService Should never happen!
820 pkgList = new String[]{pkgName};
821 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
823 if (pkgList != null && (pkgList.length > 0)) {
824 for (String pkgName : pkgList) {
825 if (cancelNotifications) {
826 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0,
827 !queryRestart, changeUserId, reason, null);
831 mListeners.onPackagesChanged(removingPackage, pkgList);
832 mNotificationAssistants.onPackagesChanged(removingPackage, pkgList);
833 mConditionProviders.onPackagesChanged(removingPackage, pkgList);
834 mRankingHelper.onPackagesChanged(removingPackage, changeUserId, pkgList, uidList);
840 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
842 public void onReceive(Context context, Intent intent) {
843 String action = intent.getAction();
845 if (action.equals(Intent.ACTION_SCREEN_ON)) {
846 // Keep track of screen on/off state, but do not turn off the notification light
847 // until user passes through the lock screen or views the notification.
849 updateNotificationPulse();
850 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
852 updateNotificationPulse();
853 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
854 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
855 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
856 updateNotificationPulse();
857 synchronized (mInCallToneGeneratorLock) {
859 if (mInCallToneGenerator == null) {
860 int relativeToneVolume = getContext().getResources().getInteger(
861 R.integer.config_inCallNotificationVolumeRelative);
862 if (relativeToneVolume < ToneGenerator.MIN_VOLUME
863 || relativeToneVolume > ToneGenerator.MAX_VOLUME) {
864 relativeToneVolume = ToneGenerator.MAX_VOLUME;
867 mInCallToneGenerator = new ToneGenerator(
868 AudioManager.STREAM_VOICE_CALL, relativeToneVolume);
869 } catch (RuntimeException e) {
870 Log.e(TAG, "Error creating local tone generator: " + e);
871 mInCallToneGenerator = null;
875 if (mInCallToneGenerator != null) {
876 mInCallToneGenerator.release();
877 mInCallToneGenerator = null;
881 } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
882 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
883 if (userHandle >= 0) {
884 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
885 REASON_USER_STOPPED, null);
887 } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
888 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
889 if (userHandle >= 0) {
890 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
891 REASON_PROFILE_TURNED_OFF, null);
893 } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
894 // turn off LED when user passes through lock screen
895 mNotificationLight.turnOff();
896 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
897 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
898 // reload per-user settings
899 mSettingsObserver.update(null);
900 mUserProfiles.updateCache(context);
901 // Refresh managed services
902 mConditionProviders.onUserSwitched(user);
903 mListeners.onUserSwitched(user);
904 mNotificationAssistants.onUserSwitched(user);
905 mZenModeHelper.onUserSwitched(user);
906 } else if (action.equals(Intent.ACTION_USER_ADDED)) {
907 mUserProfiles.updateCache(context);
908 } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
909 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
910 mZenModeHelper.onUserRemoved(user);
911 mRankingHelper.onUserRemoved(user);
913 } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
914 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
915 mConditionProviders.onUserUnlocked(user);
916 mListeners.onUserUnlocked(user);
917 mNotificationAssistants.onUserUnlocked(user);
918 mZenModeHelper.onUserUnlocked(user);
923 private final class SettingsObserver extends ContentObserver {
924 private final Uri NOTIFICATION_BADGING_URI
925 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING);
926 private final Uri NOTIFICATION_LIGHT_PULSE_URI
927 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
928 private final Uri NOTIFICATION_RATE_LIMIT_URI
929 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
931 SettingsObserver(Handler handler) {
936 ContentResolver resolver = getContext().getContentResolver();
937 resolver.registerContentObserver(NOTIFICATION_BADGING_URI,
938 false, this, UserHandle.USER_ALL);
939 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
940 false, this, UserHandle.USER_ALL);
941 resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
942 false, this, UserHandle.USER_ALL);
946 @Override public void onChange(boolean selfChange, Uri uri) {
950 public void update(Uri uri) {
951 ContentResolver resolver = getContext().getContentResolver();
952 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
953 boolean pulseEnabled = Settings.System.getInt(resolver,
954 Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
955 if (mNotificationPulseEnabled != pulseEnabled) {
956 mNotificationPulseEnabled = pulseEnabled;
957 updateNotificationPulse();
960 if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
961 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
962 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
964 if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) {
965 mRankingHelper.updateBadgingEnabled();
970 private SettingsObserver mSettingsObserver;
971 private ZenModeHelper mZenModeHelper;
973 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
974 int[] ar = r.getIntArray(resid);
978 final int len = ar.length > maxlen ? maxlen : ar.length;
979 long[] out = new long[len];
980 for (int i=0; i<len; i++) {
986 public NotificationManagerService(Context context) {
988 Notification.processWhitelistToken = WHITELIST_TOKEN;
991 // TODO - replace these methods with a single VisibleForTesting constructor
993 void setAudioManager(AudioManager audioMananger) {
994 mAudioManager = audioMananger;
998 void setVibrator(Vibrator vibrator) {
999 mVibrator = vibrator;
1003 void setLights(Light light) {
1004 mNotificationLight = light;
1005 mAttentionLight = light;
1006 mNotificationPulseEnabled = true;
1010 void setScreenOn(boolean on) {
1015 int getNotificationRecordCount() {
1016 synchronized (mNotificationLock) {
1017 int count = mNotificationList.size() + mNotificationsByKey.size()
1018 + mSummaryByGroupKey.size() + mEnqueuedNotifications.size();
1019 // subtract duplicates
1020 for (NotificationRecord posted : mNotificationList) {
1021 if (mNotificationsByKey.containsKey(posted.getKey())) {
1024 if (posted.sbn.isGroup() && posted.getNotification().isGroupSummary()) {
1034 void addNotification(NotificationRecord r) {
1035 mNotificationList.add(r);
1036 mNotificationsByKey.put(r.sbn.getKey(), r);
1037 if (r.sbn.isGroup()) {
1038 mSummaryByGroupKey.put(r.getGroupKey(), r);
1043 void addEnqueuedNotification(NotificationRecord r) {
1044 mEnqueuedNotifications.add(r);
1048 void setSystemReady(boolean systemReady) {
1049 mSystemReady = systemReady;
1053 void setHandler(Handler handler) {
1058 void setFallbackVibrationPattern(long[] vibrationPattern) {
1059 mFallbackVibrationPattern = vibrationPattern;
1063 void setPackageManager(IPackageManager packageManager) {
1064 mPackageManager = packageManager;
1068 void setRankingHelper(RankingHelper rankingHelper) {
1069 mRankingHelper = rankingHelper;
1073 void setIsTelevision(boolean isTelevision) {
1074 mIsTelevision = isTelevision;
1077 // TODO: Tests should call onStart instead once the methods above are removed.
1079 void init(Looper looper, IPackageManager packageManager, PackageManager packageManagerClient,
1080 LightsManager lightsManager, NotificationListeners notificationListeners,
1081 ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
1082 NotificationUsageStats usageStats) {
1083 Resources resources = getContext().getResources();
1084 mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
1085 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
1086 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
1088 mAm = ActivityManager.getService();
1089 mPackageManager = packageManager;
1090 mPackageManagerClient = packageManagerClient;
1091 mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
1092 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
1093 mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
1094 mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
1095 mCompanionManager = companionManager;
1097 mHandler = new WorkerHandler(looper);
1098 mRankingThread.start();
1099 String[] extractorNames;
1101 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
1102 } catch (Resources.NotFoundException e) {
1103 extractorNames = new String[0];
1105 mUsageStats = usageStats;
1106 mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
1107 mRankingHelper = new RankingHelper(getContext(),
1108 getContext().getPackageManager(),
1112 mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles);
1113 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
1114 mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
1116 public void onConfigChanged() {
1121 void onZenModeChanged() {
1122 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
1123 getContext().sendBroadcastAsUser(
1124 new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
1125 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
1126 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
1127 synchronized (mNotificationLock) {
1128 updateInterruptionFilterLocked();
1133 void onPolicyChanged() {
1134 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
1137 mSnoozeHelper = snoozeHelper;
1138 mGroupHelper = new GroupHelper(new GroupHelper.Callback() {
1140 public void addAutoGroup(String key) {
1141 synchronized (mNotificationLock) {
1142 addAutogroupKeyLocked(key);
1144 mRankingHandler.requestSort(false);
1148 public void removeAutoGroup(String key) {
1149 synchronized (mNotificationLock) {
1150 removeAutogroupKeyLocked(key);
1152 mRankingHandler.requestSort(false);
1156 public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) {
1157 createAutoGroupSummary(userId, pkg, triggeringKey);
1161 public void removeAutoGroupSummary(int userId, String pkg) {
1162 synchronized (mNotificationLock) {
1163 clearAutogroupSummaryLocked(userId, pkg);
1168 final File systemDir = new File(Environment.getDataDirectory(), "system");
1169 mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
1173 // This is a ManagedServices object that keeps track of the listeners.
1174 mListeners = notificationListeners;
1176 // This is a MangedServices object that keeps track of the assistant.
1177 mNotificationAssistants = new NotificationAssistants();
1179 mStatusBar = getLocalService(StatusBarManagerInternal.class);
1180 if (mStatusBar != null) {
1181 mStatusBar.setNotificationDelegate(mNotificationDelegate);
1184 mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
1185 mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
1187 mFallbackVibrationPattern = getLongArray(resources,
1188 R.array.config_notificationFallbackVibePattern,
1189 VIBRATE_PATTERN_MAXLEN,
1190 DEFAULT_VIBRATE_PATTERN);
1192 mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
1194 // Don't start allowing notifications until the setup wizard has run once.
1195 // After that, including subsequent boots, init with notifications turned on.
1196 // This works on the first boot because the setup wizard will toggle this
1197 // flag at least once and we'll go back to 0 after that.
1198 if (0 == Settings.Global.getInt(getContext().getContentResolver(),
1199 Settings.Global.DEVICE_PROVISIONED, 0)) {
1200 mDisableNotificationEffects = true;
1202 mZenModeHelper.initZenMode();
1203 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1205 mUserProfiles.updateCache(getContext());
1206 listenForCallState();
1208 // register for various Intents
1209 IntentFilter filter = new IntentFilter();
1210 filter.addAction(Intent.ACTION_SCREEN_ON);
1211 filter.addAction(Intent.ACTION_SCREEN_OFF);
1212 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
1213 filter.addAction(Intent.ACTION_USER_PRESENT);
1214 filter.addAction(Intent.ACTION_USER_STOPPED);
1215 filter.addAction(Intent.ACTION_USER_SWITCHED);
1216 filter.addAction(Intent.ACTION_USER_ADDED);
1217 filter.addAction(Intent.ACTION_USER_REMOVED);
1218 filter.addAction(Intent.ACTION_USER_UNLOCKED);
1219 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
1220 getContext().registerReceiver(mIntentReceiver, filter);
1222 IntentFilter pkgFilter = new IntentFilter();
1223 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
1224 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1225 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
1226 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1227 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1228 pkgFilter.addDataScheme("package");
1229 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1232 IntentFilter suspendedPkgFilter = new IntentFilter();
1233 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
1234 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1235 suspendedPkgFilter, null, null);
1237 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
1238 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1241 IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
1242 timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
1243 getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter);
1245 mSettingsObserver = new SettingsObserver(mHandler);
1247 mArchive = new Archive(resources.getInteger(
1248 R.integer.config_notificationServiceArchiveSize));
1250 mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
1251 || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
1255 public void onStart() {
1256 SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() {
1258 public void repost(int userId, NotificationRecord r) {
1261 Slog.d(TAG, "Reposting " + r.getKey());
1263 enqueueNotificationInternal(r.sbn.getPackageName(), r.sbn.getOpPkg(),
1264 r.sbn.getUid(), r.sbn.getInitialPid(), r.sbn.getTag(), r.sbn.getId(),
1265 r.sbn.getNotification(), userId);
1266 } catch (Exception e) {
1267 Slog.e(TAG, "Cannot un-snooze notification", e);
1272 init(Looper.myLooper(), AppGlobals.getPackageManager(), getContext().getPackageManager(),
1273 getLocalService(LightsManager.class), new NotificationListeners(),
1274 null, snoozeHelper, new NotificationUsageStats(getContext()));
1275 publishBinderService(Context.NOTIFICATION_SERVICE, mService);
1276 publishLocalService(NotificationManagerInternal.class, mInternalService);
1279 private void sendRegisteredOnlyBroadcast(String action) {
1280 getContext().sendBroadcastAsUser(new Intent(action)
1281 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
1285 public void onBootPhase(int phase) {
1286 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1287 // no beeping until we're basically done booting
1288 mSystemReady = true;
1290 // Grab our optional AudioService
1291 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
1292 mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
1293 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
1294 mZenModeHelper.onSystemReady();
1295 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1296 // This observer will force an update when observe is called, causing us to
1297 // bind to listener services.
1298 mSettingsObserver.observe();
1299 mListeners.onBootPhaseAppsCanStart();
1300 mNotificationAssistants.onBootPhaseAppsCanStart();
1301 mConditionProviders.onBootPhaseAppsCanStart();
1305 @GuardedBy("mNotificationLock")
1306 private void updateListenerHintsLocked() {
1307 final int hints = calculateHints();
1308 if (hints == mListenerHints) return;
1309 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
1310 mListenerHints = hints;
1311 scheduleListenerHintsChanged(hints);
1314 @GuardedBy("mNotificationLock")
1315 private void updateEffectsSuppressorLocked() {
1316 final long updatedSuppressedEffects = calculateSuppressedEffects();
1317 if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1318 final List<ComponentName> suppressors = getSuppressors();
1319 ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1320 mEffectsSuppressors = suppressors;
1321 mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
1322 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
1325 private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
1326 boolean fromListener) {
1327 if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
1329 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
1330 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
1333 mRankingHelper.updateNotificationChannel(pkg, uid, channel);
1335 final NotificationChannel modifiedChannel =
1336 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
1338 if (!fromListener) {
1339 mListeners.notifyNotificationChannelChanged(
1340 pkg, UserHandle.getUserHandleForUid(uid),
1341 modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
1344 synchronized (mNotificationLock) {
1345 final int N = mNotificationList.size();
1346 for (int i = N - 1; i >= 0; --i) {
1347 NotificationRecord r = mNotificationList.get(i);
1348 if (r.sbn.getPackageName().equals(pkg)
1349 && r.sbn.getUid() == uid
1350 && channel.getId() != null
1351 && channel.getId().equals(r.getChannel().getId())) {
1352 r.updateNotificationChannel(modifiedChannel);
1356 mRankingHandler.requestSort(true);
1360 private ArrayList<ComponentName> getSuppressors() {
1361 ArrayList<ComponentName> names = new ArrayList<ComponentName>();
1362 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1363 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1365 for (ManagedServiceInfo info : serviceInfoList) {
1366 names.add(info.component);
1373 private boolean removeDisabledHints(ManagedServiceInfo info) {
1374 return removeDisabledHints(info, 0);
1377 private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
1378 boolean removed = false;
1380 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1381 final int hint = mListenersDisablingEffects.keyAt(i);
1382 final ArraySet<ManagedServiceInfo> listeners =
1383 mListenersDisablingEffects.valueAt(i);
1385 if (hints == 0 || (hint & hints) == hint) {
1386 removed = removed || listeners.remove(info);
1393 private void addDisabledHints(ManagedServiceInfo info, int hints) {
1394 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1395 addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
1398 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1399 addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1402 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1403 addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
1407 private void addDisabledHint(ManagedServiceInfo info, int hint) {
1408 if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
1409 mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
1412 ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
1413 hintListeners.add(info);
1416 private int calculateHints() {
1418 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1419 int hint = mListenersDisablingEffects.keyAt(i);
1420 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1422 if (!serviceInfoList.isEmpty()) {
1430 private long calculateSuppressedEffects() {
1431 int hints = calculateHints();
1432 long suppressedEffects = 0;
1434 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1435 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
1438 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1439 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
1442 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1443 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
1446 return suppressedEffects;
1449 @GuardedBy("mNotificationLock")
1450 private void updateInterruptionFilterLocked() {
1451 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1452 if (interruptionFilter == mInterruptionFilter) return;
1453 mInterruptionFilter = interruptionFilter;
1454 scheduleInterruptionFilterChanged(interruptionFilter);
1458 INotificationManager getBinderService() {
1459 return INotificationManager.Stub.asInterface(mService);
1463 NotificationManagerInternal getInternalService() {
1464 return mInternalService;
1467 private final IBinder mService = new INotificationManager.Stub() {
1469 // ============================================================================
1472 public void enqueueToast(String pkg, ITransientNotification callback, int duration)
1475 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1476 + " duration=" + duration);
1479 if (pkg == null || callback == null) {
1480 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1484 final boolean isSystemToast = isCallerSystemOrPhone() || ("android".equals(pkg));
1485 final boolean isPackageSuspended =
1486 isPackageSuspendedForUser(pkg, Binder.getCallingUid());
1488 if (ENABLE_BLOCKED_TOASTS && !isSystemToast &&
1489 (!areNotificationsEnabledForPackage(pkg, Binder.getCallingUid())
1490 || isPackageSuspended)) {
1491 Slog.e(TAG, "Suppressing toast from package " + pkg
1492 + (isPackageSuspended
1493 ? " due to package suspended by administrator."
1494 : " by user request."));
1498 synchronized (mToastQueue) {
1499 int callingPid = Binder.getCallingPid();
1500 long callingId = Binder.clearCallingIdentity();
1503 int index = indexOfToastLocked(pkg, callback);
1504 // If it's already in the queue, we update it in place, we don't
1505 // move it to the end of the queue.
1507 record = mToastQueue.get(index);
1508 record.update(duration);
1510 // Limit the number of toasts that any given package except the android
1511 // package can enqueue. Prevents DOS attacks and deals with leaks.
1512 if (!isSystemToast) {
1514 final int N = mToastQueue.size();
1515 for (int i=0; i<N; i++) {
1516 final ToastRecord r = mToastQueue.get(i);
1517 if (r.pkg.equals(pkg)) {
1519 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
1520 Slog.e(TAG, "Package has already posted " + count
1521 + " toasts. Not showing more. Package=" + pkg);
1528 Binder token = new Binder();
1529 mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, DEFAULT_DISPLAY);
1530 record = new ToastRecord(callingPid, pkg, callback, duration, token);
1531 mToastQueue.add(record);
1532 index = mToastQueue.size() - 1;
1533 keepProcessAliveIfNeededLocked(callingPid);
1535 // If it's at index 0, it's the current toast. It doesn't matter if it's
1536 // new or just been updated. Call back and tell it to show itself.
1537 // If the callback fails, this will remove it from the list, so don't
1538 // assume that it's valid after this.
1540 showNextToastLocked();
1543 Binder.restoreCallingIdentity(callingId);
1549 public void cancelToast(String pkg, ITransientNotification callback) {
1550 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
1552 if (pkg == null || callback == null) {
1553 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
1557 synchronized (mToastQueue) {
1558 long callingId = Binder.clearCallingIdentity();
1560 int index = indexOfToastLocked(pkg, callback);
1562 cancelToastLocked(index);
1564 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
1565 + " callback=" + callback);
1568 Binder.restoreCallingIdentity(callingId);
1574 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
1575 Notification notification, int userId) throws RemoteException {
1576 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
1577 Binder.getCallingPid(), tag, id, notification, userId);
1581 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
1582 checkCallerIsSystemOrSameApp(pkg);
1583 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1584 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
1585 // Don't allow client applications to cancel foreground service notis or autobundled
1587 final int mustNotHaveFlags = isCallingUidSystem() ? 0 :
1588 (Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTOGROUP_SUMMARY);
1589 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
1590 mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null);
1594 public void cancelAllNotifications(String pkg, int userId) {
1595 checkCallerIsSystemOrSameApp(pkg);
1597 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1598 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
1600 // Calling from user space, don't allow the canceling of actively
1601 // running foreground services.
1602 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
1603 pkg, null, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
1604 REASON_APP_CANCEL_ALL, null);
1608 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
1609 checkCallerIsSystem();
1611 mRankingHelper.setEnabled(pkg, uid, enabled);
1612 // Now, cancel any outstanding notifications that are part of a just-disabled app
1614 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
1615 UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
1621 * Use this when you just want to know if notifications are OK for this package.
1624 public boolean areNotificationsEnabled(String pkg) {
1625 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
1629 * Use this when you just want to know if notifications are OK for this package.
1632 public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
1633 checkCallerIsSystemOrSameApp(pkg);
1635 return mRankingHelper.getImportance(pkg, uid) != IMPORTANCE_NONE;
1639 public int getPackageImportance(String pkg) {
1640 checkCallerIsSystemOrSameApp(pkg);
1641 return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
1645 public boolean canShowBadge(String pkg, int uid) {
1646 checkCallerIsSystem();
1647 return mRankingHelper.canShowBadge(pkg, uid);
1651 public void setShowBadge(String pkg, int uid, boolean showBadge) {
1652 checkCallerIsSystem();
1653 mRankingHelper.setShowBadge(pkg, uid, showBadge);
1658 public void createNotificationChannelGroups(String pkg,
1659 ParceledListSlice channelGroupList) throws RemoteException {
1660 checkCallerIsSystemOrSameApp(pkg);
1661 List<NotificationChannelGroup> groups = channelGroupList.getList();
1662 final int groupSize = groups.size();
1663 for (int i = 0; i < groupSize; i++) {
1664 final NotificationChannelGroup group = groups.get(i);
1665 Preconditions.checkNotNull(group, "group in list is null");
1666 mRankingHelper.createNotificationChannelGroup(pkg, Binder.getCallingUid(), group,
1667 true /* fromTargetApp */);
1668 mListeners.notifyNotificationChannelGroupChanged(pkg,
1669 UserHandle.of(UserHandle.getCallingUserId()), group,
1670 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1675 private void createNotificationChannelsImpl(String pkg, int uid,
1676 ParceledListSlice channelsList) {
1677 List<NotificationChannel> channels = channelsList.getList();
1678 final int channelsSize = channels.size();
1679 for (int i = 0; i < channelsSize; i++) {
1680 final NotificationChannel channel = channels.get(i);
1681 Preconditions.checkNotNull(channel, "channel in list is null");
1682 mRankingHelper.createNotificationChannel(pkg, uid, channel,
1683 true /* fromTargetApp */);
1684 mListeners.notifyNotificationChannelChanged(pkg,
1685 UserHandle.getUserHandleForUid(uid),
1686 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false),
1687 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1693 public void createNotificationChannels(String pkg,
1694 ParceledListSlice channelsList) throws RemoteException {
1695 checkCallerIsSystemOrSameApp(pkg);
1696 createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList);
1700 public void createNotificationChannelsForPackage(String pkg, int uid,
1701 ParceledListSlice channelsList) throws RemoteException {
1702 checkCallerIsSystem();
1703 createNotificationChannelsImpl(pkg, uid, channelsList);
1707 public NotificationChannel getNotificationChannel(String pkg, String channelId) {
1708 checkCallerIsSystemOrSameApp(pkg);
1709 return mRankingHelper.getNotificationChannel(
1710 pkg, Binder.getCallingUid(), channelId, false /* includeDeleted */);
1714 public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
1715 String channelId, boolean includeDeleted) {
1716 checkCallerIsSystem();
1717 return mRankingHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted);
1721 public void deleteNotificationChannel(String pkg, String channelId) {
1722 checkCallerIsSystemOrSameApp(pkg);
1723 final int callingUid = Binder.getCallingUid();
1724 if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
1725 throw new IllegalArgumentException("Cannot delete default channel");
1727 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
1728 UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
1729 mRankingHelper.deleteNotificationChannel(pkg, callingUid, channelId);
1730 mListeners.notifyNotificationChannelChanged(pkg,
1731 UserHandle.getUserHandleForUid(callingUid),
1732 mRankingHelper.getNotificationChannel(pkg, callingUid, channelId, true),
1733 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1738 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
1740 checkCallerIsSystemOrSameApp(pkg);
1741 return new ParceledListSlice<>(new ArrayList(
1742 mRankingHelper.getNotificationChannelGroups(pkg, Binder.getCallingUid())));
1746 public void deleteNotificationChannelGroup(String pkg, String groupId) {
1747 checkCallerIsSystemOrSameApp(pkg);
1749 final int callingUid = Binder.getCallingUid();
1750 NotificationChannelGroup groupToDelete =
1751 mRankingHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
1752 if (groupToDelete != null) {
1753 List<NotificationChannel> deletedChannels =
1754 mRankingHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
1755 for (int i = 0; i < deletedChannels.size(); i++) {
1756 final NotificationChannel deletedChannel = deletedChannels.get(i);
1757 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
1759 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
1761 mListeners.notifyNotificationChannelChanged(pkg,
1762 UserHandle.getUserHandleForUid(callingUid),
1764 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1766 mListeners.notifyNotificationChannelGroupChanged(
1767 pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete,
1768 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1774 public void updateNotificationChannelForPackage(String pkg, int uid,
1775 NotificationChannel channel) {
1776 enforceSystemOrSystemUI("Caller not system or systemui");
1777 Preconditions.checkNotNull(channel);
1778 updateNotificationChannelInt(pkg, uid, channel, false);
1782 public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
1783 int uid, boolean includeDeleted) {
1784 enforceSystemOrSystemUI("getNotificationChannelsForPackage");
1785 return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted);
1789 public int getNumNotificationChannelsForPackage(String pkg, int uid,
1790 boolean includeDeleted) {
1791 enforceSystemOrSystemUI("getNumNotificationChannelsForPackage");
1792 return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted)
1797 public boolean onlyHasDefaultChannel(String pkg, int uid) {
1798 enforceSystemOrSystemUI("onlyHasDefaultChannel");
1799 return mRankingHelper.onlyHasDefaultChannel(pkg, uid);
1803 public int getDeletedChannelCount(String pkg, int uid) {
1804 enforceSystemOrSystemUI("getDeletedChannelCount");
1805 return mRankingHelper.getDeletedChannelCount(pkg, uid);
1809 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
1810 String pkg, int uid, boolean includeDeleted) {
1811 checkCallerIsSystem();
1812 return mRankingHelper.getNotificationChannelGroups(pkg, uid, includeDeleted);
1816 public NotificationChannelGroup getNotificationChannelGroupForPackage(
1817 String groupId, String pkg, int uid) {
1818 enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
1819 return mRankingHelper.getNotificationChannelGroup(groupId, pkg, uid);
1823 public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
1824 checkCallerIsSystemOrSameApp(pkg);
1825 return mRankingHelper.getNotificationChannels(
1826 pkg, Binder.getCallingUid(), false /* includeDeleted */);
1830 public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
1831 checkCallerIsSystem();
1833 // Cancel posted notifications
1834 cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true,
1835 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
1837 // Listener & assistant
1838 mListeners.onPackagesChanged(true, new String[] {packageName});
1839 mNotificationAssistants.onPackagesChanged(true, new String[] {packageName});
1842 mConditionProviders.onPackagesChanged(true, new String[] {packageName});
1844 // Reset notification preferences
1846 mRankingHelper.onPackagesChanged(true, UserHandle.getCallingUserId(),
1847 new String[]{packageName}, new int[]{uid});
1855 * System-only API for getting a list of current (i.e. not cleared) notifications.
1857 * Requires ACCESS_NOTIFICATIONS which is signature|system.
1858 * @returns A list of all the notifications, in natural order.
1861 public StatusBarNotification[] getActiveNotifications(String callingPkg) {
1862 // enforce() will ensure the calling uid has the correct permission
1863 getContext().enforceCallingOrSelfPermission(
1864 android.Manifest.permission.ACCESS_NOTIFICATIONS,
1865 "NotificationManagerService.getActiveNotifications");
1867 StatusBarNotification[] tmp = null;
1868 int uid = Binder.getCallingUid();
1870 // noteOp will check to make sure the callingPkg matches the uid
1871 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1872 == AppOpsManager.MODE_ALLOWED) {
1873 synchronized (mNotificationLock) {
1874 tmp = new StatusBarNotification[mNotificationList.size()];
1875 final int N = mNotificationList.size();
1876 for (int i=0; i<N; i++) {
1877 tmp[i] = mNotificationList.get(i).sbn;
1885 * Public API for getting a list of current notifications for the calling package/uid.
1887 * Note that since notification posting is done asynchronously, this will not return
1888 * notifications that are in the process of being posted.
1890 * @returns A list of all the package's notifications, in natural order.
1893 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
1894 int incomingUserId) {
1895 checkCallerIsSystemOrSameApp(pkg);
1896 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1897 Binder.getCallingUid(), incomingUserId, true, false,
1898 "getAppActiveNotifications", pkg);
1899 synchronized (mNotificationLock) {
1900 final ArrayMap<String, StatusBarNotification> map
1901 = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
1902 final int N = mNotificationList.size();
1903 for (int i = 0; i < N; i++) {
1904 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
1905 mNotificationList.get(i).sbn);
1907 map.put(sbn.getKey(), sbn);
1910 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
1911 StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn);
1913 map.put(sbn.getKey(), sbn);
1916 final int M = mEnqueuedNotifications.size();
1917 for (int i = 0; i < M; i++) {
1918 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
1919 mEnqueuedNotifications.get(i).sbn);
1921 map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
1924 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
1925 list.addAll(map.values());
1926 return new ParceledListSlice<StatusBarNotification>(list);
1930 private StatusBarNotification sanitizeSbn(String pkg, int userId,
1931 StatusBarNotification sbn) {
1932 if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId
1933 && (sbn.getNotification().flags
1934 & Notification.FLAG_AUTOGROUP_SUMMARY) == 0) {
1935 // We could pass back a cloneLight() but clients might get confused and
1936 // try to send this thing back to notify() again, which would not work
1938 return new StatusBarNotification(
1939 sbn.getPackageName(),
1941 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
1942 sbn.getNotification().clone(),
1943 sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
1949 * System-only API for getting a list of recent (cleared, no longer shown) notifications.
1951 * Requires ACCESS_NOTIFICATIONS which is signature|system.
1954 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
1955 // enforce() will ensure the calling uid has the correct permission
1956 getContext().enforceCallingOrSelfPermission(
1957 android.Manifest.permission.ACCESS_NOTIFICATIONS,
1958 "NotificationManagerService.getHistoricalNotifications");
1960 StatusBarNotification[] tmp = null;
1961 int uid = Binder.getCallingUid();
1963 // noteOp will check to make sure the callingPkg matches the uid
1964 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1965 == AppOpsManager.MODE_ALLOWED) {
1966 synchronized (mArchive) {
1967 tmp = mArchive.getArray(count);
1974 * Register a listener binder directly with the notification manager.
1976 * Only works with system callers. Apps should extend
1977 * {@link android.service.notification.NotificationListenerService}.
1980 public void registerListener(final INotificationListener listener,
1981 final ComponentName component, final int userid) {
1982 enforceSystemOrSystemUI("INotificationManager.registerListener");
1983 mListeners.registerService(listener, component, userid);
1987 * Remove a listener binder directly
1990 public void unregisterListener(INotificationListener token, int userid) {
1991 mListeners.unregisterService(token, userid);
1995 * Allow an INotificationListener to simulate a "clear all" operation.
1997 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
1999 * @param token The binder for the listener, to check that the caller is allowed
2002 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
2003 final int callingUid = Binder.getCallingUid();
2004 final int callingPid = Binder.getCallingPid();
2005 long identity = Binder.clearCallingIdentity();
2007 synchronized (mNotificationLock) {
2008 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2010 final int N = keys.length;
2011 for (int i = 0; i < N; i++) {
2012 NotificationRecord r = mNotificationsByKey.get(keys[i]);
2013 if (r == null) continue;
2014 final int userId = r.sbn.getUserId();
2015 if (userId != info.userid && userId != UserHandle.USER_ALL &&
2016 !mUserProfiles.isCurrentProfile(userId)) {
2017 throw new SecurityException("Disallowed call from listener: "
2020 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2021 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
2025 cancelAllLocked(callingUid, callingPid, info.userid,
2026 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
2030 Binder.restoreCallingIdentity(identity);
2035 * Handle request from an approved listener to re-enable itself.
2037 * @param component The componenet to be re-enabled, caller must match package.
2040 public void requestBindListener(ComponentName component) {
2041 checkCallerIsSystemOrSameApp(component.getPackageName());
2042 long identity = Binder.clearCallingIdentity();
2044 ManagedServices manager =
2045 mNotificationAssistants.isComponentEnabledForCurrentProfiles(component)
2046 ? mNotificationAssistants
2048 manager.setComponentState(component, true);
2050 Binder.restoreCallingIdentity(identity);
2055 public void requestUnbindListener(INotificationListener token) {
2056 long identity = Binder.clearCallingIdentity();
2058 // allow bound services to disable themselves
2059 synchronized (mNotificationLock) {
2060 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2061 info.getOwner().setComponentState(info.component, false);
2064 Binder.restoreCallingIdentity(identity);
2069 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
2070 long identity = Binder.clearCallingIdentity();
2072 synchronized (mNotificationLock) {
2073 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2075 final int N = keys.length;
2076 for (int i = 0; i < N; i++) {
2077 NotificationRecord r = mNotificationsByKey.get(keys[i]);
2078 if (r == null) continue;
2079 final int userId = r.sbn.getUserId();
2080 if (userId != info.userid && userId != UserHandle.USER_ALL &&
2081 !mUserProfiles.isCurrentProfile(userId)) {
2082 throw new SecurityException("Disallowed call from listener: "
2086 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
2087 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
2088 userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM
2090 UsageEvents.Event.USER_INTERACTION);
2097 Binder.restoreCallingIdentity(identity);
2102 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2104 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2106 * @param info The binder for the listener, to check that the caller is allowed
2108 @GuardedBy("mNotificationLock")
2109 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
2110 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
2111 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
2112 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
2114 userId, REASON_LISTENER_CANCEL, info);
2118 * Allow an INotificationListener to snooze a single notification until a context.
2120 * @param token The binder for the listener, to check that the caller is allowed
2123 public void snoozeNotificationUntilContextFromListener(INotificationListener token,
2124 String key, String snoozeCriterionId) {
2125 long identity = Binder.clearCallingIdentity();
2127 synchronized (mNotificationLock) {
2128 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2129 snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info);
2132 Binder.restoreCallingIdentity(identity);
2137 * Allow an INotificationListener to snooze a single notification until a time.
2139 * @param token The binder for the listener, to check that the caller is allowed
2142 public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
2144 long identity = Binder.clearCallingIdentity();
2146 synchronized (mNotificationLock) {
2147 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2148 snoozeNotificationInt(key, duration, null, info);
2151 Binder.restoreCallingIdentity(identity);
2156 * Allows the notification assistant to un-snooze a single notification.
2158 * @param token The binder for the assistant, to check that the caller is allowed
2161 public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
2162 long identity = Binder.clearCallingIdentity();
2164 synchronized (mNotificationLock) {
2165 final ManagedServiceInfo info =
2166 mNotificationAssistants.checkServiceTokenLocked(token);
2167 unsnoozeNotificationInt(key, info);
2170 Binder.restoreCallingIdentity(identity);
2175 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2177 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2179 * @param token The binder for the listener, to check that the caller is allowed
2182 public void cancelNotificationFromListener(INotificationListener token, String pkg,
2183 String tag, int id) {
2184 final int callingUid = Binder.getCallingUid();
2185 final int callingPid = Binder.getCallingPid();
2186 long identity = Binder.clearCallingIdentity();
2188 synchronized (mNotificationLock) {
2189 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2190 if (info.supportsProfiles()) {
2191 Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
2192 + "from " + info.component
2193 + " use cancelNotification(key) instead.");
2195 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2196 pkg, tag, id, info.userid);
2200 Binder.restoreCallingIdentity(identity);
2205 * Allow an INotificationListener to request the list of outstanding notifications seen by
2206 * the current user. Useful when starting up, after which point the listener callbacks
2209 * @param token The binder for the listener, to check that the caller is allowed
2210 * @param keys An array of notification keys to fetch, or null to fetch everything
2211 * @returns The return value will contain the notifications specified in keys, in that
2212 * order, or if keys is null, all the notifications, in natural order.
2215 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
2216 INotificationListener token, String[] keys, int trim) {
2217 synchronized (mNotificationLock) {
2218 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2219 final boolean getKeys = keys != null;
2220 final int N = getKeys ? keys.length : mNotificationList.size();
2221 final ArrayList<StatusBarNotification> list
2222 = new ArrayList<StatusBarNotification>(N);
2223 for (int i=0; i<N; i++) {
2224 final NotificationRecord r = getKeys
2225 ? mNotificationsByKey.get(keys[i])
2226 : mNotificationList.get(i);
2227 if (r == null) continue;
2228 StatusBarNotification sbn = r.sbn;
2229 if (!isVisibleToListener(sbn, info)) continue;
2230 StatusBarNotification sbnToSend =
2231 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2232 list.add(sbnToSend);
2234 return new ParceledListSlice<StatusBarNotification>(list);
2239 * Allow an INotificationListener to request the list of outstanding snoozed notifications
2240 * seen by the current user. Useful when starting up, after which point the listener
2241 * callbacks should be used.
2243 * @param token The binder for the listener, to check that the caller is allowed
2244 * @returns The return value will contain the notifications specified in keys, in that
2245 * order, or if keys is null, all the notifications, in natural order.
2248 public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
2249 INotificationListener token, int trim) {
2250 synchronized (mNotificationLock) {
2251 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2252 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
2253 final int N = snoozedRecords.size();
2254 final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
2255 for (int i=0; i < N; i++) {
2256 final NotificationRecord r = snoozedRecords.get(i);
2257 if (r == null) continue;
2258 StatusBarNotification sbn = r.sbn;
2259 if (!isVisibleToListener(sbn, info)) continue;
2260 StatusBarNotification sbnToSend =
2261 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2262 list.add(sbnToSend);
2264 return new ParceledListSlice<>(list);
2269 public void requestHintsFromListener(INotificationListener token, int hints) {
2270 final long identity = Binder.clearCallingIdentity();
2272 synchronized (mNotificationLock) {
2273 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2274 final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
2275 | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
2276 | HINT_HOST_DISABLE_CALL_EFFECTS;
2277 final boolean disableEffects = (hints & disableEffectsMask) != 0;
2278 if (disableEffects) {
2279 addDisabledHints(info, hints);
2281 removeDisabledHints(info, hints);
2283 updateListenerHintsLocked();
2284 updateEffectsSuppressorLocked();
2287 Binder.restoreCallingIdentity(identity);
2292 public int getHintsFromListener(INotificationListener token) {
2293 synchronized (mNotificationLock) {
2294 return mListenerHints;
2299 public void requestInterruptionFilterFromListener(INotificationListener token,
2300 int interruptionFilter) throws RemoteException {
2301 final long identity = Binder.clearCallingIdentity();
2303 synchronized (mNotificationLock) {
2304 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2305 mZenModeHelper.requestFromListener(info.component, interruptionFilter);
2306 updateInterruptionFilterLocked();
2309 Binder.restoreCallingIdentity(identity);
2314 public int getInterruptionFilterFromListener(INotificationListener token)
2315 throws RemoteException {
2316 synchronized (mNotificationLight) {
2317 return mInterruptionFilter;
2322 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
2323 throws RemoteException {
2324 synchronized (mNotificationLock) {
2325 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2326 if (info == null) return;
2327 mListeners.setOnNotificationPostedTrimLocked(info, trim);
2332 public int getZenMode() {
2333 return mZenModeHelper.getZenMode();
2337 public ZenModeConfig getZenModeConfig() {
2338 enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
2339 return mZenModeHelper.getConfig();
2343 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
2344 enforceSystemOrSystemUI("INotificationManager.setZenMode");
2345 final long identity = Binder.clearCallingIdentity();
2347 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
2349 Binder.restoreCallingIdentity(identity);
2354 public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
2355 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
2356 return mZenModeHelper.getZenRules();
2360 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
2361 Preconditions.checkNotNull(id, "Id is null");
2362 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
2363 return mZenModeHelper.getAutomaticZenRule(id);
2367 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
2368 throws RemoteException {
2369 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2370 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2371 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2372 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2373 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
2375 return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
2376 "addAutomaticZenRule");
2380 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
2381 throws RemoteException {
2382 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2383 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2384 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2385 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2386 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
2388 return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
2389 "updateAutomaticZenRule");
2393 public boolean removeAutomaticZenRule(String id) throws RemoteException {
2394 Preconditions.checkNotNull(id, "Id is null");
2395 // Verify that they can modify zen rules.
2396 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
2398 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
2402 public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
2403 Preconditions.checkNotNull(packageName, "Package name is null");
2404 enforceSystemOrSystemUI("removeAutomaticZenRules");
2406 return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
2410 public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
2411 Preconditions.checkNotNull(owner, "Owner is null");
2412 enforceSystemOrSystemUI("getRuleInstanceCount");
2414 return mZenModeHelper.getCurrentInstanceCount(owner);
2418 public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
2419 enforcePolicyAccess(pkg, "setInterruptionFilter");
2420 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
2421 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
2422 final long identity = Binder.clearCallingIdentity();
2424 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
2426 Binder.restoreCallingIdentity(identity);
2431 public void notifyConditions(final String pkg, IConditionProvider provider,
2432 final Condition[] conditions) {
2433 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2434 checkCallerIsSystemOrSameApp(pkg);
2435 mHandler.post(new Runnable() {
2438 mConditionProviders.notifyConditions(pkg, info, conditions);
2444 public void requestUnbindProvider(IConditionProvider provider) {
2445 long identity = Binder.clearCallingIdentity();
2447 // allow bound services to disable themselves
2448 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2449 info.getOwner().setComponentState(info.component, false);
2451 Binder.restoreCallingIdentity(identity);
2456 public void requestBindProvider(ComponentName component) {
2457 checkCallerIsSystemOrSameApp(component.getPackageName());
2458 long identity = Binder.clearCallingIdentity();
2460 mConditionProviders.setComponentState(component, true);
2462 Binder.restoreCallingIdentity(identity);
2466 private void enforceSystemOrSystemUI(String message) {
2467 if (isCallerSystemOrPhone()) return;
2468 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
2472 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
2474 checkCallerIsSystemOrSameApp(pkg);
2475 } catch (SecurityException e) {
2476 getContext().enforceCallingPermission(
2477 android.Manifest.permission.STATUS_BAR_SERVICE,
2482 private void enforcePolicyAccess(int uid, String method) {
2483 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2484 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2487 boolean accessAllowed = false;
2488 String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
2489 final int packageCount = packages.length;
2490 for (int i = 0; i < packageCount; i++) {
2491 if (checkPolicyAccess(packages[i])) {
2492 accessAllowed = true;
2495 if (!accessAllowed) {
2496 Slog.w(TAG, "Notification policy access denied calling " + method);
2497 throw new SecurityException("Notification policy access denied");
2501 private void enforcePolicyAccess(String pkg, String method) {
2502 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2503 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2506 checkCallerIsSameApp(pkg);
2507 if (!checkPolicyAccess(pkg)) {
2508 Slog.w(TAG, "Notification policy access denied calling " + method);
2509 throw new SecurityException("Notification policy access denied");
2513 private boolean checkPackagePolicyAccess(String pkg) {
2514 return mPolicyAccess.isPackageGranted(pkg);
2517 private boolean checkPolicyAccess(String pkg) {
2519 int uid = getContext().getPackageManager().getPackageUidAsUser(
2520 pkg, UserHandle.getCallingUserId());
2521 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
2522 android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
2526 } catch (NameNotFoundException e) {
2529 return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
2533 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2534 if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
2535 final DumpFilter filter = DumpFilter.parseFromArguments(args);
2536 if (filter != null && filter.stats) {
2537 dumpJson(pw, filter);
2538 } else if (filter != null && filter.proto) {
2539 dumpProto(fd, filter);
2541 dumpImpl(pw, filter);
2546 public ComponentName getEffectsSuppressor() {
2547 return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
2551 public boolean matchesCallFilter(Bundle extras) {
2552 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
2553 return mZenModeHelper.matchesCallFilter(
2554 Binder.getCallingUserHandle(),
2556 mRankingHelper.findExtractor(ValidateNotificationPeople.class),
2557 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
2558 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
2562 public boolean isSystemConditionProviderEnabled(String path) {
2563 enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
2564 return mConditionProviders.isSystemProviderEnabled(path);
2567 // Backup/restore interface
2569 public byte[] getBackupPayload(int user) {
2570 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
2571 //TODO: http://b/22388012
2572 if (user != UserHandle.USER_SYSTEM) {
2573 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
2576 synchronized(mPolicyFile) {
2577 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
2579 writePolicyXml(baos, true /*forBackup*/);
2580 return baos.toByteArray();
2581 } catch (IOException e) {
2582 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
2589 public void applyRestore(byte[] payload, int user) {
2590 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
2591 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
2592 if (payload == null) {
2593 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
2596 //TODO: http://b/22388012
2597 if (user != UserHandle.USER_SYSTEM) {
2598 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
2601 synchronized(mPolicyFile) {
2602 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
2604 readPolicyXml(bais, true /*forRestore*/);
2606 } catch (NumberFormatException | XmlPullParserException | IOException e) {
2607 Slog.w(TAG, "applyRestore: error reading payload", e);
2613 public boolean isNotificationPolicyAccessGranted(String pkg) {
2614 return checkPolicyAccess(pkg);
2618 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
2619 enforceSystemOrSystemUIOrSamePackage(pkg,
2620 "request policy access status for another package");
2621 return checkPolicyAccess(pkg);
2625 public String[] getPackagesRequestingNotificationPolicyAccess()
2626 throws RemoteException {
2627 enforceSystemOrSystemUI("request policy access packages");
2628 final long identity = Binder.clearCallingIdentity();
2630 return mPolicyAccess.getRequestingPackages();
2632 Binder.restoreCallingIdentity(identity);
2637 public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
2638 throws RemoteException {
2639 enforceSystemOrSystemUI("grant notification policy access");
2640 final long identity = Binder.clearCallingIdentity();
2642 synchronized (mNotificationLock) {
2643 mPolicyAccess.put(pkg, granted);
2646 Binder.restoreCallingIdentity(identity);
2651 public Policy getNotificationPolicy(String pkg) {
2652 enforcePolicyAccess(pkg, "getNotificationPolicy");
2653 final long identity = Binder.clearCallingIdentity();
2655 return mZenModeHelper.getNotificationPolicy();
2657 Binder.restoreCallingIdentity(identity);
2662 public void setNotificationPolicy(String pkg, Policy policy) {
2663 enforcePolicyAccess(pkg, "setNotificationPolicy");
2664 final long identity = Binder.clearCallingIdentity();
2666 mZenModeHelper.setNotificationPolicy(policy);
2668 Binder.restoreCallingIdentity(identity);
2673 public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
2674 Adjustment adjustment) throws RemoteException {
2675 final long identity = Binder.clearCallingIdentity();
2677 synchronized (mNotificationLock) {
2678 mNotificationAssistants.checkServiceTokenLocked(token);
2679 int N = mEnqueuedNotifications.size();
2680 for (int i = 0; i < N; i++) {
2681 final NotificationRecord n = mEnqueuedNotifications.get(i);
2682 if (Objects.equals(adjustment.getKey(), n.getKey())
2683 && Objects.equals(adjustment.getUser(), n.getUserId())) {
2684 applyAdjustment(n, adjustment);
2690 Binder.restoreCallingIdentity(identity);
2695 public void applyAdjustmentFromAssistant(INotificationListener token,
2696 Adjustment adjustment) throws RemoteException {
2697 final long identity = Binder.clearCallingIdentity();
2699 synchronized (mNotificationLock) {
2700 mNotificationAssistants.checkServiceTokenLocked(token);
2701 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2702 applyAdjustment(n, adjustment);
2704 mRankingHandler.requestSort(true);
2706 Binder.restoreCallingIdentity(identity);
2711 public void applyAdjustmentsFromAssistant(INotificationListener token,
2712 List<Adjustment> adjustments) throws RemoteException {
2714 final long identity = Binder.clearCallingIdentity();
2716 synchronized (mNotificationLock) {
2717 mNotificationAssistants.checkServiceTokenLocked(token);
2718 for (Adjustment adjustment : adjustments) {
2719 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2720 applyAdjustment(n, adjustment);
2723 mRankingHandler.requestSort(true);
2725 Binder.restoreCallingIdentity(identity);
2730 public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
2731 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
2732 Preconditions.checkNotNull(channel);
2733 Preconditions.checkNotNull(pkg);
2734 Preconditions.checkNotNull(user);
2736 verifyPrivilegedListener(token, user);
2737 updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
2741 public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
2742 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
2743 Preconditions.checkNotNull(pkg);
2744 Preconditions.checkNotNull(user);
2745 verifyPrivilegedListener(token, user);
2747 return mRankingHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user),
2748 false /* includeDeleted */);
2752 public ParceledListSlice<NotificationChannelGroup>
2753 getNotificationChannelGroupsFromPrivilegedListener(
2754 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
2755 Preconditions.checkNotNull(pkg);
2756 Preconditions.checkNotNull(user);
2757 verifyPrivilegedListener(token, user);
2759 List<NotificationChannelGroup> groups = new ArrayList<>();
2760 groups.addAll(mRankingHelper.getNotificationChannelGroups(
2761 pkg, getUidForPackageAndUser(pkg, user)));
2762 return new ParceledListSlice<>(groups);
2765 private void verifyPrivilegedListener(INotificationListener token, UserHandle user) {
2766 ManagedServiceInfo info;
2767 synchronized (mNotificationLock) {
2768 info = mListeners.checkServiceTokenLocked(token);
2770 if (!hasCompanionDevice(info)) {
2771 throw new SecurityException(info + " does not have access");
2773 if (!info.enabledAndUserMatches(user.getIdentifier())) {
2774 throw new SecurityException(info + " does not have access");
2778 private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
2780 long identity = Binder.clearCallingIdentity();
2782 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
2784 Binder.restoreCallingIdentity(identity);
2790 private void applyAdjustment(NotificationRecord n, Adjustment adjustment) {
2794 if (adjustment.getSignals() != null) {
2795 Bundle.setDefusable(adjustment.getSignals(), true);
2796 final ArrayList<String> people =
2797 adjustment.getSignals().getStringArrayList(Adjustment.KEY_PEOPLE);
2798 final ArrayList<SnoozeCriterion> snoozeCriterionList =
2799 adjustment.getSignals().getParcelableArrayList(Adjustment.KEY_SNOOZE_CRITERIA);
2800 n.setPeopleOverride(people);
2801 n.setSnoozeCriteria(snoozeCriterionList);
2805 @GuardedBy("mNotificationLock")
2806 private void addAutogroupKeyLocked(String key) {
2807 NotificationRecord n = mNotificationsByKey.get(key);
2811 n.setOverrideGroupKey(GroupHelper.AUTOGROUP_KEY);
2812 EventLogTags.writeNotificationAutogrouped(key);
2815 @GuardedBy("mNotificationLock")
2816 private void removeAutogroupKeyLocked(String key) {
2817 NotificationRecord n = mNotificationsByKey.get(key);
2821 n.setOverrideGroupKey(null);
2822 EventLogTags.writeNotificationUnautogrouped(key);
2825 // Clears the 'fake' auto-group summary.
2826 @GuardedBy("mNotificationLock")
2827 private void clearAutogroupSummaryLocked(int userId, String pkg) {
2828 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
2829 if (summaries != null && summaries.containsKey(pkg)) {
2831 final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
2832 if (removed != null) {
2833 boolean wasPosted = removeFromNotificationListsLocked(removed);
2834 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED, wasPosted);
2839 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
2840 private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
2841 NotificationRecord summaryRecord = null;
2842 synchronized (mNotificationLock) {
2843 NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
2844 if (notificationRecord == null) {
2845 // The notification could have been cancelled again already. A successive
2846 // adjustment will post a summary if needed.
2849 final StatusBarNotification adjustedSbn = notificationRecord.sbn;
2850 userId = adjustedSbn.getUser().getIdentifier();
2851 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
2852 if (summaries == null) {
2853 summaries = new ArrayMap<>();
2855 mAutobundledSummaries.put(userId, summaries);
2856 if (!summaries.containsKey(pkg)) {
2858 final ApplicationInfo appInfo =
2859 adjustedSbn.getNotification().extras.getParcelable(
2860 Notification.EXTRA_BUILDER_APPLICATION_INFO);
2861 final Bundle extras = new Bundle();
2862 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
2863 final String channelId = notificationRecord.getChannel().getId();
2864 final Notification summaryNotification =
2865 new Notification.Builder(getContext(), channelId)
2866 .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
2867 .setGroupSummary(true)
2868 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN)
2869 .setGroup(GroupHelper.AUTOGROUP_KEY)
2870 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
2871 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
2872 .setColor(adjustedSbn.getNotification().color)
2875 summaryNotification.extras.putAll(extras);
2876 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
2877 if (appIntent != null) {
2878 summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
2879 getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
2881 final StatusBarNotification summarySbn =
2882 new StatusBarNotification(adjustedSbn.getPackageName(),
2883 adjustedSbn.getOpPkg(),
2885 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
2886 adjustedSbn.getInitialPid(), summaryNotification,
2887 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
2888 System.currentTimeMillis());
2889 summaryRecord = new NotificationRecord(getContext(), summarySbn,
2890 notificationRecord.getChannel());
2891 summaries.put(pkg, summarySbn.getKey());
2894 if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
2895 summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord)) {
2896 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
2900 private String disableNotificationEffects(NotificationRecord record) {
2901 if (mDisableNotificationEffects) {
2902 return "booleanState";
2904 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
2905 return "listenerHints";
2907 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
2913 private void dumpJson(PrintWriter pw, DumpFilter filter) {
2914 JSONObject dump = new JSONObject();
2916 dump.put("service", "Notification Manager");
2917 dump.put("bans", mRankingHelper.dumpBansJson(filter));
2918 dump.put("ranking", mRankingHelper.dumpJson(filter));
2919 dump.put("stats", mUsageStats.dumpJson(filter));
2920 dump.put("channels", mRankingHelper.dumpChannelsJson(filter));
2921 } catch (JSONException e) {
2922 e.printStackTrace();
2927 private void dumpProto(FileDescriptor fd, DumpFilter filter) {
2928 final ProtoOutputStream proto = new ProtoOutputStream(fd);
2929 synchronized (mNotificationLock) {
2930 long records = proto.start(NotificationServiceDumpProto.RECORDS);
2931 int N = mNotificationList.size();
2933 for (int i = 0; i < N; i++) {
2934 final NotificationRecord nr = mNotificationList.get(i);
2935 if (filter.filtered && !filter.matches(nr.sbn)) continue;
2936 nr.dump(proto, filter.redact);
2937 proto.write(NotificationRecordProto.STATE, NotificationServiceProto.POSTED);
2940 N = mEnqueuedNotifications.size();
2942 for (int i = 0; i < N; i++) {
2943 final NotificationRecord nr = mEnqueuedNotifications.get(i);
2944 if (filter.filtered && !filter.matches(nr.sbn)) continue;
2945 nr.dump(proto, filter.redact);
2946 proto.write(NotificationRecordProto.STATE, NotificationServiceProto.ENQUEUED);
2949 List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
2952 for (int i = 0; i < N; i++) {
2953 final NotificationRecord nr = snoozed.get(i);
2954 if (filter.filtered && !filter.matches(nr.sbn)) continue;
2955 nr.dump(proto, filter.redact);
2956 proto.write(NotificationRecordProto.STATE, NotificationServiceProto.SNOOZED);
2962 long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
2963 mZenModeHelper.dump(proto);
2964 for (ComponentName suppressor : mEffectsSuppressors) {
2965 proto.write(ZenModeProto.SUPPRESSORS, suppressor.toString());
2972 void dumpImpl(PrintWriter pw, DumpFilter filter) {
2973 pw.print("Current Notification Manager state");
2974 if (filter.filtered) {
2975 pw.print(" (filtered to "); pw.print(filter); pw.print(")");
2979 final boolean zenOnly = filter.filtered && filter.zen;
2982 synchronized (mToastQueue) {
2983 N = mToastQueue.size();
2985 pw.println(" Toast Queue:");
2986 for (int i=0; i<N; i++) {
2987 mToastQueue.get(i).dump(pw, " ", filter);
2994 synchronized (mNotificationLock) {
2996 N = mNotificationList.size();
2998 pw.println(" Notification List:");
2999 for (int i=0; i<N; i++) {
3000 final NotificationRecord nr = mNotificationList.get(i);
3001 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3002 nr.dump(pw, " ", getContext(), filter.redact);
3007 if (!filter.filtered) {
3010 pw.println(" Lights List:");
3011 for (int i=0; i<N; i++) {
3017 pw.println(mLights.get(i));
3021 pw.println(" mUseAttentionLight=" + mUseAttentionLight);
3022 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled);
3023 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey);
3024 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey);
3025 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects);
3026 pw.println(" mCallState=" + callStateToString(mCallState));
3027 pw.println(" mSystemReady=" + mSystemReady);
3028 pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
3030 pw.println(" mArchive=" + mArchive.toString());
3031 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
3033 while (iter.hasNext()) {
3034 final StatusBarNotification sbn = iter.next();
3035 if (filter != null && !filter.matches(sbn)) continue;
3036 pw.println(" " + sbn);
3038 if (iter.hasNext()) pw.println(" ...");
3044 N = mEnqueuedNotifications.size();
3046 pw.println(" Enqueued Notification List:");
3047 for (int i = 0; i < N; i++) {
3048 final NotificationRecord nr = mEnqueuedNotifications.get(i);
3049 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3050 nr.dump(pw, " ", getContext(), filter.redact);
3055 mSnoozeHelper.dump(pw, filter);
3060 pw.println("\n Ranking Config:");
3061 mRankingHelper.dump(pw, " ", filter);
3063 pw.println("\n Notification listeners:");
3064 mListeners.dump(pw, filter);
3065 pw.print(" mListenerHints: "); pw.println(mListenerHints);
3066 pw.print(" mListenersDisablingEffects: (");
3067 N = mListenersDisablingEffects.size();
3068 for (int i = 0; i < N; i++) {
3069 final int hint = mListenersDisablingEffects.keyAt(i);
3070 if (i > 0) pw.print(';');
3071 pw.print("hint[" + hint + "]:");
3073 final ArraySet<ManagedServiceInfo> listeners =
3074 mListenersDisablingEffects.valueAt(i);
3075 final int listenerSize = listeners.size();
3077 for (int j = 0; j < listenerSize; j++) {
3078 if (i > 0) pw.print(',');
3079 final ManagedServiceInfo listener = listeners.valueAt(i);
3080 pw.print(listener.component);
3084 pw.println("\n Notification assistant services:");
3085 mNotificationAssistants.dump(pw, filter);
3088 if (!filter.filtered || zenOnly) {
3089 pw.println("\n Zen Mode:");
3090 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter);
3091 mZenModeHelper.dump(pw, " ");
3093 pw.println("\n Zen Log:");
3094 ZenLog.dump(pw, " ");
3097 pw.println("\n Policy access:");
3098 pw.print(" mPolicyAccess: "); pw.println(mPolicyAccess);
3100 pw.println("\n Condition providers:");
3101 mConditionProviders.dump(pw, filter);
3103 pw.println("\n Group summaries:");
3104 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
3105 NotificationRecord r = entry.getValue();
3106 pw.println(" " + entry.getKey() + " -> " + r.getKey());
3107 if (mNotificationsByKey.get(r.getKey()) != r) {
3108 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
3109 r.dump(pw, " ", getContext(), filter.redact);
3114 pw.println("\n Usage Stats:");
3115 mUsageStats.dump(pw, " ", filter);
3121 * The private API only accessible to the system process.
3123 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
3125 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
3126 String tag, int id, Notification notification, int userId) {
3127 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
3132 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
3134 checkCallerIsSystem();
3135 mHandler.post(new Runnable() {
3138 synchronized (mNotificationLock) {
3139 removeForegroundServiceFlagByListLocked(
3140 mEnqueuedNotifications, pkg, notificationId, userId);
3141 removeForegroundServiceFlagByListLocked(
3142 mNotificationList, pkg, notificationId, userId);
3148 @GuardedBy("mNotificationLock")
3149 private void removeForegroundServiceFlagByListLocked(
3150 ArrayList<NotificationRecord> notificationList, String pkg, int notificationId,
3152 NotificationRecord r = findNotificationByListLocked(
3153 notificationList, pkg, null, notificationId, userId);
3157 StatusBarNotification sbn = r.sbn;
3158 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
3159 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
3160 // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
3161 // initially *and* force remove FLAG_FOREGROUND_SERVICE.
3162 sbn.getNotification().flags =
3163 (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
3164 mRankingHelper.sort(mNotificationList);
3165 mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
3166 mGroupHelper.onNotificationPosted(sbn);
3170 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
3171 final int callingPid, final String tag, final int id, final Notification notification,
3172 int incomingUserId) {
3174 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
3175 + " notification=" + notification);
3177 checkCallerIsSystemOrSameApp(pkg);
3179 final int userId = ActivityManager.handleIncomingUser(callingPid,
3180 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
3181 final UserHandle user = new UserHandle(userId);
3183 if (pkg == null || notification == null) {
3184 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
3185 + " id=" + id + " notification=" + notification);
3188 // The system can post notifications for any package, let us resolve that.
3189 final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);
3191 // Fix the notification as best we can.
3193 final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
3194 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
3195 (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
3196 Notification.addFieldsFromContext(ai, notification);
3197 } catch (NameNotFoundException e) {
3198 Slog.e(TAG, "Cannot create a context for sending app", e);
3202 mUsageStats.registerEnqueuedByApp(pkg);
3204 // setup local book-keeping
3205 String channelId = notification.getChannelId();
3206 if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
3207 channelId = (new Notification.TvExtender(notification)).getChannelId();
3209 final NotificationChannel channel = mRankingHelper.getNotificationChannel(pkg,
3210 notificationUid, channelId, false /* includeDeleted */);
3211 if (channel == null) {
3212 final String noChannelStr = "No Channel found for "
3214 + ", channelId=" + channelId
3217 + ", opPkg=" + opPkg
3218 + ", callingUid=" + callingUid
3219 + ", userId=" + userId
3220 + ", incomingUserId=" + incomingUserId
3221 + ", notificationUid=" + notificationUid
3222 + ", notification=" + notification;
3223 Log.e(TAG, noChannelStr);
3224 doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
3225 "Failed to post notification on channel \"" + channelId + "\"\n" +
3226 "See log for more details");
3230 final StatusBarNotification n = new StatusBarNotification(
3231 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
3232 user, null, System.currentTimeMillis());
3233 final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
3235 if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r)) {
3239 // Whitelist pending intents.
3240 if (notification.allPendingIntents != null) {
3241 final int intentCount = notification.allPendingIntents.size();
3242 if (intentCount > 0) {
3243 final ActivityManagerInternal am = LocalServices
3244 .getService(ActivityManagerInternal.class);
3245 final long duration = LocalServices.getService(
3246 DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
3247 for (int i = 0; i < intentCount; i++) {
3248 PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
3249 if (pendingIntent != null) {
3250 am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
3251 WHITELIST_TOKEN, duration);
3257 mHandler.post(new EnqueueNotificationRunnable(userId, r));
3260 private void doChannelWarningToast(CharSequence toastText) {
3261 final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
3262 final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
3263 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
3264 if (warningEnabled) {
3265 Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
3266 Toast.LENGTH_SHORT);
3271 private int resolveNotificationUid(String opPackageName, int callingUid, int userId) {
3272 // The system can post notifications on behalf of any package it wants
3273 if (isCallerSystemOrPhone() && opPackageName != null && !"android".equals(opPackageName)) {
3275 return getContext().getPackageManager()
3276 .getPackageUidAsUser(opPackageName, userId);
3277 } catch (NameNotFoundException e) {
3285 * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
3289 private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag,
3290 NotificationRecord r) {
3291 final String pkg = r.sbn.getPackageName();
3292 final boolean isSystemNotification =
3293 isUidSystemOrPhone(callingUid) || ("android".equals(pkg));
3294 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
3296 // Limit the number of notifications that any given package except the android
3297 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
3298 if (!isSystemNotification && !isNotificationFromListener) {
3299 synchronized (mNotificationLock) {
3300 if (mNotificationsByKey.get(r.sbn.getKey()) != null) {
3301 // this is an update, rate limit updates only
3302 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
3303 if (appEnqueueRate > mMaxPackageEnqueueRate) {
3304 mUsageStats.registerOverRateQuota(pkg);
3305 final long now = SystemClock.elapsedRealtime();
3306 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
3307 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
3308 + ". Shedding events. package=" + pkg);
3309 mLastOverRateLogTime = now;
3313 } else if (isCallerInstantApp(pkg)) {
3314 // Ephemeral apps have some special constraints for notifications.
3315 // They are not allowed to create new notifications however they are allowed to
3316 // update notifications created by the system (e.g. a foreground service
3318 throw new SecurityException("Instant app " + pkg
3319 + " cannot create notifications");
3323 final int N = mNotificationList.size();
3324 for (int i=0; i<N; i++) {
3325 final NotificationRecord existing = mNotificationList.get(i);
3326 if (existing.sbn.getPackageName().equals(pkg)
3327 && existing.sbn.getUserId() == userId) {
3328 if (existing.sbn.getId() == id
3329 && TextUtils.equals(existing.sbn.getTag(), tag)) {
3330 break; // Allow updating existing notification
3333 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
3334 mUsageStats.registerOverCountQuota(pkg);
3335 Slog.e(TAG, "Package has already posted " + count
3336 + " notifications. Not showing more. package=" + pkg);
3345 if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
3346 MetricsLogger.action(r.getLogMaker()
3347 .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
3348 .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
3350 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
3352 mSnoozeHelper.update(userId, r);
3359 if (isBlocked(r, mUsageStats)) {
3366 protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
3367 final String pkg = r.sbn.getPackageName();
3368 final int callingUid = r.sbn.getUid();
3370 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
3371 if (isPackageSuspended) {
3372 Slog.e(TAG, "Suppressing notification from package due to package "
3373 + "suspended by administrator.");
3374 usageStats.registerSuspendedByAdmin(r);
3375 return isPackageSuspended;
3378 final boolean isBlocked =
3379 mRankingHelper.getImportance(pkg, callingUid) == NotificationManager.IMPORTANCE_NONE
3380 || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE;
3382 Slog.e(TAG, "Suppressing notification from package by user request.");
3383 usageStats.registerBlocked(r);
3388 protected class SnoozeNotificationRunnable implements Runnable {
3389 private final String mKey;
3390 private final long mDuration;
3391 private final String mSnoozeCriterionId;
3393 SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) {
3395 mDuration = duration;
3396 mSnoozeCriterionId = snoozeCriterionId;
3401 synchronized (mNotificationLock) {
3402 final NotificationRecord r = findNotificationByKeyLocked(mKey);
3409 @GuardedBy("mNotificationLock")
3410 void snoozeLocked(NotificationRecord r) {
3411 if (r.sbn.isGroup()) {
3412 final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked(
3413 r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId());
3414 if (r.getNotification().isGroupSummary()) {
3415 // snooze summary and all children
3416 for (int i = 0; i < groupNotifications.size(); i++) {
3417 snoozeNotificationLocked(groupNotifications.get(i));
3420 // if there is a valid summary for this group, and we are snoozing the only
3421 // child, also snooze the summary
3422 if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) {
3423 if (groupNotifications.size() != 2) {
3424 snoozeNotificationLocked(r);
3426 // snooze summary and the one child
3427 for (int i = 0; i < groupNotifications.size(); i++) {
3428 snoozeNotificationLocked(groupNotifications.get(i));
3432 snoozeNotificationLocked(r);
3436 // just snooze the one notification
3437 snoozeNotificationLocked(r);
3441 @GuardedBy("mNotificationLock")
3442 void snoozeNotificationLocked(NotificationRecord r) {
3443 MetricsLogger.action(r.getLogMaker()
3444 .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
3445 .setType(MetricsEvent.TYPE_CLOSE)
3446 .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
3447 mSnoozeCriterionId == null ? 0 : 1));
3448 boolean wasPosted = removeFromNotificationListsLocked(r);
3449 cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted);
3450 updateLightsLocked();
3451 if (mSnoozeCriterionId != null) {
3452 mNotificationAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
3453 mSnoozeHelper.snooze(r);
3455 mSnoozeHelper.snooze(r, mDuration);
3461 protected class EnqueueNotificationRunnable implements Runnable {
3462 private final NotificationRecord r;
3463 private final int userId;
3465 EnqueueNotificationRunnable(int userId, NotificationRecord r) {
3466 this.userId = userId;
3472 synchronized (mNotificationLock) {
3473 mEnqueuedNotifications.add(r);
3474 scheduleTimeoutLocked(r);
3476 final StatusBarNotification n = r.sbn;
3477 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
3478 NotificationRecord old = mNotificationsByKey.get(n.getKey());
3480 // Retain ranking information from previous record
3481 r.copyRankingInformation(old);
3484 final int callingUid = n.getUid();
3485 final int callingPid = n.getInitialPid();
3486 final Notification notification = n.getNotification();
3487 final String pkg = n.getPackageName();
3488 final int id = n.getId();
3489 final String tag = n.getTag();
3491 // Handle grouped notifications and bail out early if we
3492 // can to avoid extracting signals.
3493 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
3495 // if this is a group child, unsnooze parent summary
3496 if (n.isGroup() && notification.isGroupChild()) {
3497 mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
3500 // This conditional is a dirty hack to limit the logging done on
3501 // behalf of the download manager without affecting other apps.
3502 if (!pkg.equals("com.android.providers.downloads")
3503 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
3504 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
3506 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
3508 EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
3509 pkg, id, tag, userId, notification.toString(),
3513 mRankingHelper.extractSignals(r);
3515 // tell the assistant service about the notification
3516 if (mNotificationAssistants.isEnabled()) {
3517 mNotificationAssistants.onNotificationEnqueued(r);
3518 mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
3519 DELAY_FOR_ASSISTANT_TIME);
3521 mHandler.post(new PostNotificationRunnable(r.getKey()));
3527 protected class PostNotificationRunnable implements Runnable {
3528 private final String key;
3530 PostNotificationRunnable(String key) {
3536 synchronized (mNotificationLock) {
3538 NotificationRecord r = null;
3539 int N = mEnqueuedNotifications.size();
3540 for (int i = 0; i < N; i++) {
3541 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
3542 if (Objects.equals(key, enqueued.getKey())) {
3548 Slog.i(TAG, "Cannot find enqueued record for key: " + key);
3551 NotificationRecord old = mNotificationsByKey.get(key);
3552 final StatusBarNotification n = r.sbn;
3553 final Notification notification = n.getNotification();
3554 int index = indexOfNotificationLocked(n.getKey());
3556 mNotificationList.add(r);
3557 mUsageStats.registerPostedByApp(r);
3559 old = mNotificationList.get(index);
3560 mNotificationList.set(index, r);
3561 mUsageStats.registerUpdatedByApp(r, old);
3562 // Make sure we don't lose the foreground service state.
3563 notification.flags |=
3564 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
3568 mNotificationsByKey.put(n.getKey(), r);
3570 // Ensure if this is a foreground service that the proper additional
3572 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
3573 notification.flags |= Notification.FLAG_ONGOING_EVENT
3574 | Notification.FLAG_NO_CLEAR;
3577 applyZenModeLocked(r);
3578 mRankingHelper.sort(mNotificationList);
3580 if (notification.getSmallIcon() != null) {
3581 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
3582 mListeners.notifyPostedLocked(n, oldSbn);
3583 mHandler.post(new Runnable() {
3586 mGroupHelper.onNotificationPosted(n);
3590 Slog.e(TAG, "Not posting notification without small icon: " + notification);
3591 if (old != null && !old.isCanceled) {
3592 mListeners.notifyRemovedLocked(n,
3593 NotificationListenerService.REASON_ERROR);
3594 mHandler.post(new Runnable() {
3597 mGroupHelper.onNotificationRemoved(n);
3601 // ATTENTION: in a future release we will bail out here
3602 // so that we do not play sounds, show lights, etc. for invalid
3604 Slog.e(TAG, "WARNING: In a future release this will crash the app: "
3605 + n.getPackageName());
3608 buzzBeepBlinkLocked(r);
3610 int N = mEnqueuedNotifications.size();
3611 for (int i = 0; i < N; i++) {
3612 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
3613 if (Objects.equals(key, enqueued.getKey())) {
3614 mEnqueuedNotifications.remove(i);
3624 * Ensures that grouped notification receive their special treatment.
3626 * <p>Cancels group children if the new notification causes a group to lose
3629 * <p>Updates mSummaryByGroupKey.</p>
3631 @GuardedBy("mNotificationLock")
3632 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
3633 int callingUid, int callingPid) {
3634 StatusBarNotification sbn = r.sbn;
3635 Notification n = sbn.getNotification();
3636 if (n.isGroupSummary() && !sbn.isAppGroup()) {
3637 // notifications without a group shouldn't be a summary, otherwise autobundling can
3639 n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
3642 String group = sbn.getGroupKey();
3643 boolean isSummary = n.isGroupSummary();
3645 Notification oldN = old != null ? old.sbn.getNotification() : null;
3646 String oldGroup = old != null ? old.sbn.getGroupKey() : null;
3647 boolean oldIsSummary = old != null && oldN.isGroupSummary();
3650 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
3651 if (removedSummary != old) {
3653 removedSummary != null ? removedSummary.getKey() : "<null>";
3654 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
3655 ", removed=" + removedKey);
3659 mSummaryByGroupKey.put(group, r);
3662 // Clear out group children of the old notification if the update
3663 // causes the group summary to go away. This happens when the old
3664 // notification was a summary and the new one isn't, or when the old
3665 // notification was a summary and its group key changed.
3666 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
3667 cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */);
3672 @GuardedBy("mNotificationLock")
3673 void scheduleTimeoutLocked(NotificationRecord record) {
3674 if (record.getNotification().getTimeoutAfter() > 0) {
3675 final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
3676 REQUEST_CODE_TIMEOUT,
3677 new Intent(ACTION_NOTIFICATION_TIMEOUT)
3678 .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
3679 .appendPath(record.getKey()).build())
3680 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
3681 .putExtra(EXTRA_KEY, record.getKey()),
3682 PendingIntent.FLAG_UPDATE_CURRENT);
3683 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
3684 SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
3689 @GuardedBy("mNotificationLock")
3690 void buzzBeepBlinkLocked(NotificationRecord record) {
3691 boolean buzz = false;
3692 boolean beep = false;
3693 boolean blink = false;
3695 final Notification notification = record.sbn.getNotification();
3696 final String key = record.getKey();
3698 // Should this notification make noise, vibe, or use the LED?
3699 final boolean aboveThreshold =
3700 record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
3701 final boolean canInterrupt = aboveThreshold && !record.isIntercepted();
3704 "pkg=" + record.sbn.getPackageName() + " canInterrupt=" + canInterrupt +
3705 " intercept=" + record.isIntercepted()
3708 // If we're not supposed to beep, vibrate, etc. then don't.
3709 final String disableEffects = disableNotificationEffects(record);
3710 if (disableEffects != null) {
3711 ZenLog.traceDisableEffects(record, disableEffects);
3714 // Remember if this notification already owns the notification channels.
3715 boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
3716 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
3717 // These are set inside the conditional if the notification is allowed to make noise.
3718 boolean hasValidVibrate = false;
3719 boolean hasValidSound = false;
3721 if (isNotificationForCurrentUser(record)) {
3722 // If the notification will appear in the status bar, it should send an accessibility
3724 if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) {
3725 sendAccessibilityEvent(notification, record.sbn.getPackageName());
3728 if (disableEffects == null
3731 && mAudioManager != null) {
3732 if (DBG) Slog.v(TAG, "Interrupting!");
3733 Uri soundUri = record.getSound();
3734 hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
3735 long[] vibration = record.getVibration();
3736 // Demote sound to vibration if vibration missing & phone in vibration mode.
3737 if (vibration == null
3739 && (mAudioManager.getRingerModeInternal()
3740 == AudioManager.RINGER_MODE_VIBRATE)) {
3741 vibration = mFallbackVibrationPattern;
3743 hasValidVibrate = vibration != null;
3745 if (!shouldMuteNotificationLocked(record)) {
3746 if (hasValidSound) {
3747 mSoundNotificationKey = key;
3749 playInCallNotification();
3752 beep = playSound(record, soundUri);
3756 final boolean ringerModeSilent =
3757 mAudioManager.getRingerModeInternal()
3758 == AudioManager.RINGER_MODE_SILENT;
3759 if (!mInCall && hasValidVibrate && !ringerModeSilent) {
3760 mVibrateNotificationKey = key;
3762 buzz = playVibration(record, vibration, hasValidSound);
3767 // If a notification is updated to remove the actively playing sound or vibrate,
3768 // cancel that feedback now
3769 if (wasBeep && !hasValidSound) {
3772 if (wasBuzz && !hasValidVibrate) {
3773 clearVibrateLocked();
3777 // release the light
3778 boolean wasShowLights = mLights.remove(key);
3779 if (record.getLight() != null && aboveThreshold
3780 && ((record.getSuppressedVisualEffects()
3781 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
3783 updateLightsLocked();
3784 if (mUseAttentionLight) {
3785 mAttentionLight.pulse();
3788 } else if (wasShowLights) {
3789 updateLightsLocked();
3791 if (buzz || beep || blink) {
3792 MetricsLogger.action(record.getLogMaker()
3793 .setCategory(MetricsEvent.NOTIFICATION_ALERT)
3794 .setType(MetricsEvent.TYPE_OPEN)
3795 .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
3796 EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
3800 @GuardedBy("mNotificationLock")
3801 boolean shouldMuteNotificationLocked(final NotificationRecord record) {
3802 final Notification notification = record.getNotification();
3804 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
3807 if (record.sbn.isGroup()) {
3808 return notification.suppressAlertingDueToGrouping();
3813 private boolean playSound(final NotificationRecord record, Uri soundUri) {
3814 boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
3815 // do not play notifications if there is a user of exclusive audio focus
3816 // or the device is in vibrate mode
3817 if (!mAudioManager.isAudioFocusExclusive() && mAudioManager.getRingerModeInternal()
3818 != AudioManager.RINGER_MODE_VIBRATE) {
3819 final long identity = Binder.clearCallingIdentity();
3821 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
3822 if (player != null) {
3823 if (DBG) Slog.v(TAG, "Playing sound " + soundUri
3824 + " with attributes " + record.getAudioAttributes());
3825 player.playAsync(soundUri, record.sbn.getUser(), looping,
3826 record.getAudioAttributes());
3829 } catch (RemoteException e) {
3831 Binder.restoreCallingIdentity(identity);
3837 private boolean playVibration(final NotificationRecord record, long[] vibration,
3838 boolean delayVibForSound) {
3839 // Escalate privileges so we can use the vibrator even if the
3840 // notifying app does not have the VIBRATE permission.
3841 long identity = Binder.clearCallingIdentity();
3843 final VibrationEffect effect;
3845 final boolean insistent =
3846 (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
3847 effect = VibrationEffect.createWaveform(
3848 vibration, insistent ? 0 : -1 /*repeatIndex*/);
3849 } catch (IllegalArgumentException e) {
3850 Slog.e(TAG, "Error creating vibration waveform with pattern: " +
3851 Arrays.toString(vibration));
3854 if (delayVibForSound) {
3856 // delay the vibration by the same amount as the notification sound
3857 final int waitMs = mAudioManager.getFocusRampTimeMs(
3858 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
3859 record.getAudioAttributes());
3860 if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms");
3862 Thread.sleep(waitMs);
3863 } catch (InterruptedException e) { }
3864 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
3865 effect, record.getAudioAttributes());
3868 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
3869 effect, record.getAudioAttributes());
3873 Binder.restoreCallingIdentity(identity);
3877 private boolean isNotificationForCurrentUser(NotificationRecord record) {
3878 final int currentUser;
3879 final long token = Binder.clearCallingIdentity();
3881 currentUser = ActivityManager.getCurrentUser();
3883 Binder.restoreCallingIdentity(token);
3885 return (record.getUserId() == UserHandle.USER_ALL ||
3886 record.getUserId() == currentUser ||
3887 mUserProfiles.isCurrentProfile(record.getUserId()));
3890 private void playInCallNotification() {
3894 // If toneGenerator creation fails, just continue the call
3895 // without playing the notification sound.
3897 synchronized (mInCallToneGeneratorLock) {
3898 if (mInCallToneGenerator != null) {
3899 // limit this tone to 1 second; BEEP2 should in fact be much shorter
3900 mInCallToneGenerator.startTone(ToneGenerator.TONE_PROP_BEEP2, 1000);
3903 } catch (RuntimeException e) {
3904 Log.w(TAG, "Exception from ToneGenerator: " + e);
3910 @GuardedBy("mToastQueue")
3911 void showNextToastLocked() {
3912 ToastRecord record = mToastQueue.get(0);
3913 while (record != null) {
3914 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
3916 record.callback.show(record.token);
3917 scheduleTimeoutLocked(record);
3919 } catch (RemoteException e) {
3920 Slog.w(TAG, "Object died trying to show notification " + record.callback
3921 + " in package " + record.pkg);
3922 // remove it from the list and let the process die
3923 int index = mToastQueue.indexOf(record);
3925 mToastQueue.remove(index);
3927 keepProcessAliveIfNeededLocked(record.pid);
3928 if (mToastQueue.size() > 0) {
3929 record = mToastQueue.get(0);
3937 @GuardedBy("mToastQueue")
3938 void cancelToastLocked(int index) {
3939 ToastRecord record = mToastQueue.get(index);
3941 record.callback.hide();
3942 } catch (RemoteException e) {
3943 Slog.w(TAG, "Object died trying to hide notification " + record.callback
3944 + " in package " + record.pkg);
3945 // don't worry about this, we're about to remove it from
3949 ToastRecord lastToast = mToastQueue.remove(index);
3950 mWindowManagerInternal.removeWindowToken(lastToast.token, true, DEFAULT_DISPLAY);
3952 keepProcessAliveIfNeededLocked(record.pid);
3953 if (mToastQueue.size() > 0) {
3954 // Show the next one. If the callback fails, this will remove
3955 // it from the list, so don't assume that the list hasn't changed
3956 // after this point.
3957 showNextToastLocked();
3961 @GuardedBy("mToastQueue")
3962 private void scheduleTimeoutLocked(ToastRecord r)
3964 mHandler.removeCallbacksAndMessages(r);
3965 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
3966 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
3967 mHandler.sendMessageDelayed(m, delay);
3970 private void handleTimeout(ToastRecord record)
3972 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
3973 synchronized (mToastQueue) {
3974 int index = indexOfToastLocked(record.pkg, record.callback);
3976 cancelToastLocked(index);
3981 @GuardedBy("mToastQueue")
3982 int indexOfToastLocked(String pkg, ITransientNotification callback)
3984 IBinder cbak = callback.asBinder();
3985 ArrayList<ToastRecord> list = mToastQueue;
3986 int len = list.size();
3987 for (int i=0; i<len; i++) {
3988 ToastRecord r = list.get(i);
3989 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
3996 @GuardedBy("mToastQueue")
3997 void keepProcessAliveIfNeededLocked(int pid)
3999 int toastCount = 0; // toasts from this pid
4000 ArrayList<ToastRecord> list = mToastQueue;
4001 int N = list.size();
4002 for (int i=0; i<N; i++) {
4003 ToastRecord r = list.get(i);
4009 mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
4010 } catch (RemoteException e) {
4011 // Shouldn't happen.
4015 private void handleRankingReconsideration(Message message) {
4016 if (!(message.obj instanceof RankingReconsideration)) return;
4017 RankingReconsideration recon = (RankingReconsideration) message.obj;
4020 synchronized (mNotificationLock) {
4021 final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
4022 if (record == null) {
4025 int indexBefore = findNotificationRecordIndexLocked(record);
4026 boolean interceptBefore = record.isIntercepted();
4027 int visibilityBefore = record.getPackageVisibilityOverride();
4028 recon.applyChangesLocked(record);
4029 applyZenModeLocked(record);
4030 mRankingHelper.sort(mNotificationList);
4031 int indexAfter = findNotificationRecordIndexLocked(record);
4032 boolean interceptAfter = record.isIntercepted();
4033 int visibilityAfter = record.getPackageVisibilityOverride();
4034 changed = indexBefore != indexAfter || interceptBefore != interceptAfter
4035 || visibilityBefore != visibilityAfter;
4036 if (interceptBefore && !interceptAfter) {
4037 buzzBeepBlinkLocked(record);
4041 scheduleSendRankingUpdate();
4045 private void handleRankingSort(Message msg) {
4046 if (!(msg.obj instanceof Boolean)) return;
4047 if (mRankingHelper == null) return;
4048 boolean forceUpdate = ((Boolean) msg.obj == null) ? false : (boolean) msg.obj;
4049 synchronized (mNotificationLock) {
4050 final int N = mNotificationList.size();
4051 // Any field that can change via one of the extractors or by the assistant
4052 // needs to be added here.
4053 ArrayList<String> orderBefore = new ArrayList<String>(N);
4054 ArrayList<String> groupOverrideBefore = new ArrayList<>(N);
4055 int[] visibilities = new int[N];
4056 boolean[] showBadges = new boolean[N];
4057 for (int i = 0; i < N; i++) {
4058 final NotificationRecord r = mNotificationList.get(i);
4059 orderBefore.add(r.getKey());
4060 groupOverrideBefore.add(r.sbn.getGroupKey());
4061 visibilities[i] = r.getPackageVisibilityOverride();
4062 showBadges[i] = r.canShowBadge();
4063 mRankingHelper.extractSignals(r);
4065 mRankingHelper.sort(mNotificationList);
4066 for (int i = 0; i < N; i++) {
4067 final NotificationRecord r = mNotificationList.get(i);
4069 || !orderBefore.get(i).equals(r.getKey())
4070 || visibilities[i] != r.getPackageVisibilityOverride()
4071 || !groupOverrideBefore.get(i).equals(r.sbn.getGroupKey())
4072 || showBadges[i] != r.canShowBadge()) {
4073 scheduleSendRankingUpdate();
4080 @GuardedBy("mNotificationLock")
4081 private void recordCallerLocked(NotificationRecord record) {
4082 if (mZenModeHelper.isCall(record)) {
4083 mZenModeHelper.recordCaller(record);
4087 // let zen mode evaluate this record
4088 @GuardedBy("mNotificationLock")
4089 private void applyZenModeLocked(NotificationRecord record) {
4090 record.setIntercepted(mZenModeHelper.shouldIntercept(record));
4091 if (record.isIntercepted()) {
4092 int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
4093 ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
4094 | (mZenModeHelper.shouldSuppressWhenScreenOn()
4095 ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
4096 record.setSuppressedVisualEffects(suppressed);
4098 record.setSuppressedVisualEffects(0);
4102 @GuardedBy("mNotificationLock")
4103 private int findNotificationRecordIndexLocked(NotificationRecord target) {
4104 return mRankingHelper.indexOf(mNotificationList, target);
4107 private void scheduleSendRankingUpdate() {
4108 if (!mHandler.hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
4109 Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE);
4110 mHandler.sendMessage(m);
4114 private void handleSendRankingUpdate() {
4115 synchronized (mNotificationLock) {
4116 mListeners.notifyRankingUpdateLocked();
4120 private void scheduleListenerHintsChanged(int state) {
4121 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
4122 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
4125 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
4126 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
4127 mHandler.obtainMessage(
4128 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
4129 listenerInterruptionFilter,
4133 private void handleListenerHintsChanged(int hints) {
4134 synchronized (mNotificationLock) {
4135 mListeners.notifyListenerHintsChangedLocked(hints);
4139 private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
4140 synchronized (mNotificationLock) {
4141 mListeners.notifyInterruptionFilterChanged(interruptionFilter);
4145 private final class WorkerHandler extends Handler
4147 public WorkerHandler(Looper looper) {
4152 public void handleMessage(Message msg)
4156 case MESSAGE_TIMEOUT:
4157 handleTimeout((ToastRecord)msg.obj);
4159 case MESSAGE_SAVE_POLICY_FILE:
4160 handleSavePolicyFile();
4162 case MESSAGE_SEND_RANKING_UPDATE:
4163 handleSendRankingUpdate();
4165 case MESSAGE_LISTENER_HINTS_CHANGED:
4166 handleListenerHintsChanged(msg.arg1);
4168 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
4169 handleListenerInterruptionFilterChanged(msg.arg1);
4176 private final class RankingHandlerWorker extends Handler implements RankingHandler
4178 public RankingHandlerWorker(Looper looper) {
4183 public void handleMessage(Message msg) {
4185 case MESSAGE_RECONSIDER_RANKING:
4186 handleRankingReconsideration(msg);
4188 case MESSAGE_RANKING_SORT:
4189 handleRankingSort(msg);
4194 public void requestSort(boolean forceUpdate) {
4195 removeMessages(MESSAGE_RANKING_SORT);
4196 Message msg = Message.obtain();
4197 msg.what = MESSAGE_RANKING_SORT;
4198 msg.obj = forceUpdate;
4202 public void requestReconsideration(RankingReconsideration recon) {
4203 Message m = Message.obtain(this,
4204 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
4205 long delay = recon.getDelay(TimeUnit.MILLISECONDS);
4206 sendMessageDelayed(m, delay);
4211 // ============================================================================
4212 static int clamp(int x, int low, int high) {
4213 return (x < low) ? low : ((x > high) ? high : x);
4216 void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
4217 AccessibilityManager manager = AccessibilityManager.getInstance(getContext());
4218 if (!manager.isEnabled()) {
4222 AccessibilityEvent event =
4223 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
4224 event.setPackageName(packageName);
4225 event.setClassName(Notification.class.getName());
4226 event.setParcelableData(notification);
4227 CharSequence tickerText = notification.tickerText;
4228 if (!TextUtils.isEmpty(tickerText)) {
4229 event.getText().add(tickerText);
4232 manager.sendAccessibilityEvent(event);
4236 * Removes all NotificationsRecords with the same key as the given notification record
4237 * from both lists. Do not call this method while iterating over either list.
4239 @GuardedBy("mNotificationLock")
4240 private boolean removeFromNotificationListsLocked(NotificationRecord r) {
4241 // Remove from both lists, either list could have a separate Record for what is
4242 // effectively the same notification.
4243 boolean wasPosted = false;
4244 NotificationRecord recordInList = null;
4245 if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))
4247 mNotificationList.remove(recordInList);
4248 mNotificationsByKey.remove(recordInList.sbn.getKey());
4251 while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
4253 mEnqueuedNotifications.remove(recordInList);
4258 @GuardedBy("mNotificationLock")
4259 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
4260 boolean wasPosted) {
4261 final String canceledKey = r.getKey();
4264 recordCallerLocked(r);
4268 if (r.getNotification().deleteIntent != null) {
4270 r.getNotification().deleteIntent.send();
4271 } catch (PendingIntent.CanceledException ex) {
4272 // do nothing - there's no relevant way to recover, and
4273 // no reason to let this propagate
4274 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
4279 // Only cancel these if this notification actually got to be posted.
4282 if (r.getNotification().getSmallIcon() != null) {
4283 if (reason != REASON_SNOOZED) {
4284 r.isCanceled = true;
4286 mListeners.notifyRemovedLocked(r.sbn, reason);
4287 mHandler.post(new Runnable() {
4290 mGroupHelper.onNotificationRemoved(r.sbn);
4296 if (canceledKey.equals(mSoundNotificationKey)) {
4297 mSoundNotificationKey = null;
4298 final long identity = Binder.clearCallingIdentity();
4300 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4301 if (player != null) {
4304 } catch (RemoteException e) {
4306 Binder.restoreCallingIdentity(identity);
4311 if (canceledKey.equals(mVibrateNotificationKey)) {
4312 mVibrateNotificationKey = null;
4313 long identity = Binder.clearCallingIdentity();
4318 Binder.restoreCallingIdentity(identity);
4323 mLights.remove(canceledKey);
4326 // Record usage stats
4327 // TODO: add unbundling stats?
4330 case REASON_CANCEL_ALL:
4331 case REASON_LISTENER_CANCEL:
4332 case REASON_LISTENER_CANCEL_ALL:
4333 mUsageStats.registerDismissedByUser(r);
4335 case REASON_APP_CANCEL:
4336 case REASON_APP_CANCEL_ALL:
4337 mUsageStats.registerRemovedByApp(r);
4341 String groupKey = r.getGroupKey();
4342 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
4343 if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
4344 mSummaryByGroupKey.remove(groupKey);
4346 final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
4347 if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
4348 summaries.remove(r.sbn.getPackageName());
4351 // Save it for users of getHistoricalNotifications()
4352 mArchive.record(r.sbn);
4354 final long now = System.currentTimeMillis();
4355 MetricsLogger.action(r.getLogMaker(now)
4356 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
4357 .setType(MetricsEvent.TYPE_DISMISS)
4358 .setSubtype(reason));
4359 EventLogTags.writeNotificationCanceled(canceledKey, reason,
4360 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
4364 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
4365 * and none of the {@code mustNotHaveFlags}.
4367 void cancelNotification(final int callingUid, final int callingPid,
4368 final String pkg, final String tag, final int id,
4369 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
4370 final int userId, final int reason, final ManagedServiceInfo listener) {
4371 // In enqueueNotificationInternal notifications are added by scheduling the
4372 // work on the worker handler. Hence, we also schedule the cancel on this
4373 // handler to avoid a scenario where an add notification call followed by a
4374 // remove notification call ends up in not removing the notification.
4375 mHandler.post(new Runnable() {
4378 String listenerName = listener == null ? null : listener.component.toShortString();
4379 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
4380 userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
4382 synchronized (mNotificationLock) {
4383 // Look for the notification, searching both the posted and enqueued lists.
4384 NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
4386 // The notification was found, check if it should be removed.
4388 // Ideally we'd do this in the caller of this method. However, that would
4389 // require the caller to also find the notification.
4390 if (reason == REASON_CLICK) {
4391 mUsageStats.registerClickedByUser(r);
4394 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
4397 if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
4401 // Cancel the notification.
4402 boolean wasPosted = removeFromNotificationListsLocked(r);
4403 cancelNotificationLocked(r, sendDelete, reason, wasPosted);
4404 cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
4406 updateLightsLocked();
4408 // No notification was found, assume that it is snoozed and cancel it.
4409 if (reason != REASON_SNOOZED) {
4410 final boolean wasSnoozed = mSnoozeHelper.cancel(userId, pkg, tag, id);
4422 * Determine whether the userId applies to the notification in question, either because
4423 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
4425 private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
4427 // looking for USER_ALL notifications? match everything
4428 userId == UserHandle.USER_ALL
4429 // a notification sent to USER_ALL matches any query
4430 || r.getUserId() == UserHandle.USER_ALL
4431 // an exact user match
4432 || r.getUserId() == userId;
4436 * Determine whether the userId applies to the notification in question, either because
4437 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
4438 * because it matches one of the users profiles.
4440 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
4441 return notificationMatchesUserId(r, userId)
4442 || mUserProfiles.isCurrentProfile(r.getUserId());
4446 * Cancels all notifications from a given package that have all of the
4447 * {@code mustHaveFlags}.
4449 void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
4450 int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
4451 ManagedServiceInfo listener) {
4452 mHandler.post(new Runnable() {
4455 String listenerName = listener == null ? null : listener.component.toShortString();
4456 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
4457 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
4460 // Why does this parameter exist? Do we actually want to execute the above if doit
4466 synchronized (mNotificationLock) {
4467 FlagChecker flagChecker = (int flags) -> {
4468 if ((flags & mustHaveFlags) != mustHaveFlags) {
4471 if ((flags & mustNotHaveFlags) != 0) {
4477 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
4478 pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
4479 false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
4480 listenerName, true /* wasPosted */);
4481 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
4482 callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
4483 flagChecker, false /*includeCurrentProfiles*/, userId,
4484 false /*sendDelete*/, reason, listenerName, false /* wasPosted */);
4485 mSnoozeHelper.cancel(userId, pkg);
4491 private interface FlagChecker {
4492 // Returns false if these flags do not pass the defined flag test.
4493 public boolean apply(int flags);
4496 @GuardedBy("mNotificationLock")
4497 private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
4498 int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
4499 String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
4500 boolean sendDelete, int reason, String listenerName, boolean wasPosted) {
4501 ArrayList<NotificationRecord> canceledNotifications = null;
4502 for (int i = notificationList.size() - 1; i >= 0; --i) {
4503 NotificationRecord r = notificationList.get(i);
4504 if (includeCurrentProfiles) {
4505 if (!notificationMatchesCurrentProfiles(r, userId)) {
4508 } else if (!notificationMatchesUserId(r, userId)) {
4511 // Don't remove notifications to all, if there's no package name specified
4512 if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
4515 if (!flagChecker.apply(r.getFlags())) {
4518 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
4521 if (channelId != null && !channelId.equals(r.getChannel().getId())) {
4525 if (canceledNotifications == null) {
4526 canceledNotifications = new ArrayList<>();
4528 notificationList.remove(i);
4529 mNotificationsByKey.remove(r.getKey());
4530 canceledNotifications.add(r);
4531 cancelNotificationLocked(r, sendDelete, reason, wasPosted);
4533 if (canceledNotifications != null) {
4534 final int M = canceledNotifications.size();
4535 for (int i = 0; i < M; i++) {
4536 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
4537 listenerName, false /* sendDelete */);
4539 updateLightsLocked();
4543 void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
4544 ManagedServiceInfo listener) {
4545 String listenerName = listener == null ? null : listener.component.toShortString();
4546 if (duration <= 0 && snoozeCriterionId == null || key == null) {
4551 Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
4552 snoozeCriterionId, listenerName));
4554 // Needs to post so that it can cancel notifications not yet enqueued.
4555 mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
4558 void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
4559 String listenerName = listener == null ? null : listener.component.toShortString();
4561 Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
4563 mSnoozeHelper.repost(key);
4567 @GuardedBy("mNotificationLock")
4568 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
4569 ManagedServiceInfo listener, boolean includeCurrentProfiles) {
4570 mHandler.post(new Runnable() {
4573 synchronized (mNotificationLock) {
4574 String listenerName =
4575 listener == null ? null : listener.component.toShortString();
4576 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
4577 null, userId, 0, 0, reason, listenerName);
4579 FlagChecker flagChecker = (int flags) -> {
4580 if ((flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR))
4587 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
4588 null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
4589 includeCurrentProfiles, userId, true /*sendDelete*/, reason,
4590 listenerName, true);
4591 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
4592 callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
4593 flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
4594 reason, listenerName, false);
4595 mSnoozeHelper.cancel(userId, includeCurrentProfiles);
4601 // Warning: The caller is responsible for invoking updateLightsLocked().
4602 @GuardedBy("mNotificationLock")
4603 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
4604 String listenerName, boolean sendDelete) {
4605 Notification n = r.getNotification();
4606 if (!n.isGroupSummary()) {
4610 String pkg = r.sbn.getPackageName();
4613 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
4617 cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
4619 cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
4620 listenerName, sendDelete, false);
4623 @GuardedBy("mNotificationLock")
4624 private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
4625 NotificationRecord parentNotification, int callingUid, int callingPid,
4626 String listenerName, boolean sendDelete, boolean wasPosted) {
4627 final String pkg = parentNotification.sbn.getPackageName();
4628 final int userId = parentNotification.getUserId();
4629 final int reason = REASON_GROUP_SUMMARY_CANCELED;
4630 for (int i = notificationList.size() - 1; i >= 0; i--) {
4631 final NotificationRecord childR = notificationList.get(i);
4632 final StatusBarNotification childSbn = childR.sbn;
4633 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
4634 childR.getGroupKey().equals(parentNotification.getGroupKey())
4635 && (childR.getFlags() & Notification.FLAG_FOREGROUND_SERVICE) == 0) {
4636 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
4637 childSbn.getTag(), userId, 0, 0, reason, listenerName);
4638 notificationList.remove(i);
4639 mNotificationsByKey.remove(childR.getKey());
4640 cancelNotificationLocked(childR, sendDelete, reason, wasPosted);
4645 @GuardedBy("mNotificationLock")
4646 void updateLightsLocked()
4648 // handle notification lights
4649 NotificationRecord ledNotification = null;
4650 while (ledNotification == null && !mLights.isEmpty()) {
4651 final String owner = mLights.get(mLights.size() - 1);
4652 ledNotification = mNotificationsByKey.get(owner);
4653 if (ledNotification == null) {
4654 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
4655 mLights.remove(owner);
4659 // Don't flash while we are in a call or screen is on
4660 if (ledNotification == null || mInCall || mScreenOn) {
4661 mNotificationLight.turnOff();
4663 NotificationRecord.Light light = ledNotification.getLight();
4664 if (light != null && mNotificationPulseEnabled) {
4666 mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
4667 light.onMs, light.offMs);
4672 @GuardedBy("mNotificationLock")
4673 @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
4674 String groupKey, int userId) {
4675 List<NotificationRecord> records = new ArrayList<>();
4676 records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
4678 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
4683 @GuardedBy("mNotificationLock")
4684 private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
4685 ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
4686 List<NotificationRecord> records = new ArrayList<>();
4687 final int len = list.size();
4688 for (int i = 0; i < len; i++) {
4689 NotificationRecord r = list.get(i);
4690 if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey)
4691 && r.sbn.getPackageName().equals(pkg)) {
4698 // Searches both enqueued and posted notifications by key.
4699 // TODO: need to combine a bunch of these getters with slightly different behavior.
4700 // TODO: Should enqueuing just add to mNotificationsByKey instead?
4701 @GuardedBy("mNotificationLock")
4702 private NotificationRecord findNotificationByKeyLocked(String key) {
4703 NotificationRecord r;
4704 if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
4707 if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
4713 @GuardedBy("mNotificationLock")
4714 NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
4715 NotificationRecord r;
4716 if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
4719 if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
4726 @GuardedBy("mNotificationLock")
4727 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
4728 String pkg, String tag, int id, int userId) {
4729 final int len = list.size();
4730 for (int i = 0; i < len; i++) {
4731 NotificationRecord r = list.get(i);
4732 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
4733 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
4740 @GuardedBy("mNotificationLock")
4741 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
4743 final int N = list.size();
4744 for (int i = 0; i < N; i++) {
4745 if (key.equals(list.get(i).getKey())) {
4752 @GuardedBy("mNotificationLock")
4753 int indexOfNotificationLocked(String key) {
4754 final int N = mNotificationList.size();
4755 for (int i = 0; i < N; i++) {
4756 if (key.equals(mNotificationList.get(i).getKey())) {
4763 private void updateNotificationPulse() {
4764 synchronized (mNotificationLock) {
4765 updateLightsLocked();
4769 protected boolean isCallingUidSystem() {
4770 final int uid = Binder.getCallingUid();
4771 return uid == Process.SYSTEM_UID;
4774 protected boolean isUidSystemOrPhone(int uid) {
4775 final int appid = UserHandle.getAppId(uid);
4776 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
4779 // TODO: Most calls should probably move to isCallerSystem.
4780 protected boolean isCallerSystemOrPhone() {
4781 return isUidSystemOrPhone(Binder.getCallingUid());
4784 private void checkCallerIsSystem() {
4785 if (isCallerSystemOrPhone()) {
4788 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
4791 private void checkCallerIsSystemOrSameApp(String pkg) {
4792 if (isCallerSystemOrPhone()) {
4795 checkCallerIsSameApp(pkg);
4798 private boolean isCallerInstantApp(String pkg) {
4799 // System is always allowed to act for ephemeral apps.
4800 if (isCallerSystemOrPhone()) {
4804 mAppOps.checkPackage(Binder.getCallingUid(), pkg);
4807 ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0,
4808 UserHandle.getCallingUserId());
4810 throw new SecurityException("Unknown package " + pkg);
4812 return ai.isInstantApp();
4813 } catch (RemoteException re) {
4814 throw new SecurityException("Unknown package " + pkg, re);
4819 private void checkCallerIsSameApp(String pkg) {
4820 final int uid = Binder.getCallingUid();
4822 ApplicationInfo ai = mPackageManager.getApplicationInfo(
4823 pkg, 0, UserHandle.getCallingUserId());
4825 throw new SecurityException("Unknown package " + pkg);
4827 if (!UserHandle.isSameApp(ai.uid, uid)) {
4828 throw new SecurityException("Calling uid " + uid + " gave package "
4829 + pkg + " which is owned by uid " + ai.uid);
4831 } catch (RemoteException re) {
4832 throw new SecurityException("Unknown package " + pkg + "\n" + re);
4836 private static String callStateToString(int state) {
4838 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
4839 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
4840 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
4841 default: return "CALL_STATE_UNKNOWN_" + state;
4845 private void listenForCallState() {
4846 TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
4848 public void onCallStateChanged(int state, String incomingNumber) {
4849 if (mCallState == state) return;
4850 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
4853 }, PhoneStateListener.LISTEN_CALL_STATE);
4857 * Generates a NotificationRankingUpdate from 'sbns', considering only
4858 * notifications visible to the given listener.
4860 @GuardedBy("mNotificationLock")
4861 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
4862 final int N = mNotificationList.size();
4863 ArrayList<String> keys = new ArrayList<String>(N);
4864 ArrayList<String> interceptedKeys = new ArrayList<String>(N);
4865 ArrayList<Integer> importance = new ArrayList<>(N);
4866 Bundle overrideGroupKeys = new Bundle();
4867 Bundle visibilityOverrides = new Bundle();
4868 Bundle suppressedVisualEffects = new Bundle();
4869 Bundle explanation = new Bundle();
4870 Bundle channels = new Bundle();
4871 Bundle overridePeople = new Bundle();
4872 Bundle snoozeCriteria = new Bundle();
4873 Bundle showBadge = new Bundle();
4874 for (int i = 0; i < N; i++) {
4875 NotificationRecord record = mNotificationList.get(i);
4876 if (!isVisibleToListener(record.sbn, info)) {
4879 final String key = record.sbn.getKey();
4881 importance.add(record.getImportance());
4882 if (record.getImportanceExplanation() != null) {
4883 explanation.putCharSequence(key, record.getImportanceExplanation());
4885 if (record.isIntercepted()) {
4886 interceptedKeys.add(key);
4889 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
4890 if (record.getPackageVisibilityOverride()
4891 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
4892 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
4894 overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
4895 channels.putParcelable(key, record.getChannel());
4896 overridePeople.putStringArrayList(key, record.getPeopleOverride());
4897 snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria());
4898 showBadge.putBoolean(key, record.canShowBadge());
4900 final int M = keys.size();
4901 String[] keysAr = keys.toArray(new String[M]);
4902 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
4903 int[] importanceAr = new int[M];
4904 for (int i = 0; i < M; i++) {
4905 importanceAr[i] = importance.get(i);
4907 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
4908 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
4909 channels, overridePeople, snoozeCriteria, showBadge);
4912 boolean hasCompanionDevice(ManagedServiceInfo info) {
4913 if (mCompanionManager == null) {
4914 mCompanionManager = getCompanionManager();
4916 // Companion mgr doesn't exist on all device types
4917 if (mCompanionManager == null) {
4920 long identity = Binder.clearCallingIdentity();
4922 List<String> associations = mCompanionManager.getAssociations(
4923 info.component.getPackageName(), info.userid);
4924 if (!ArrayUtils.isEmpty(associations)) {
4927 } catch (SecurityException se) {
4928 // Not a privileged listener
4929 } catch (RemoteException re) {
4930 Slog.e(TAG, "Cannot reach companion device service", re);
4931 } catch (Exception e) {
4932 Slog.e(TAG, "Cannot verify listener " + info, e);
4934 Binder.restoreCallingIdentity(identity);
4939 protected ICompanionDeviceManager getCompanionManager() {
4940 return ICompanionDeviceManager.Stub.asInterface(
4941 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
4944 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
4945 if (!listener.enabledAndUserMatches(sbn.getUserId())) {
4948 // TODO: remove this for older listeners.
4952 private boolean isPackageSuspendedForUser(String pkg, int uid) {
4953 int userId = UserHandle.getUserId(uid);
4955 return mPackageManager.isPackageSuspendedForUser(pkg, userId);
4956 } catch (RemoteException re) {
4957 throw new SecurityException("Could not talk to package manager service");
4958 } catch (IllegalArgumentException ex) {
4959 // Package not found.
4964 private class TrimCache {
4965 StatusBarNotification heavy;
4966 StatusBarNotification sbnClone;
4967 StatusBarNotification sbnCloneLight;
4969 TrimCache(StatusBarNotification sbn) {
4973 StatusBarNotification ForListener(ManagedServiceInfo info) {
4974 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
4975 if (sbnCloneLight == null) {
4976 sbnCloneLight = heavy.cloneLight();
4978 return sbnCloneLight;
4980 if (sbnClone == null) {
4981 sbnClone = heavy.clone();
4988 public class NotificationAssistants extends ManagedServices {
4990 public NotificationAssistants() {
4991 super(getContext(), mHandler, mNotificationLock, mUserProfiles);
4995 protected Config getConfig() {
4996 Config c = new Config();
4997 c.caption = "notification assistant service";
4998 c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
4999 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
5000 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
5001 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
5002 c.clientLabel = R.string.notification_ranker_binding_label;
5007 protected IInterface asInterface(IBinder binder) {
5008 return INotificationListener.Stub.asInterface(binder);
5012 protected boolean checkType(IInterface service) {
5013 return service instanceof INotificationListener;
5017 protected void onServiceAdded(ManagedServiceInfo info) {
5018 mListeners.registerGuestService(info);
5022 @GuardedBy("mNotificationLock")
5023 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
5024 mListeners.unregisterService(removed.service, removed.userid);
5027 public void onNotificationEnqueued(final NotificationRecord r) {
5028 final StatusBarNotification sbn = r.sbn;
5029 TrimCache trimCache = new TrimCache(sbn);
5031 // There should be only one, but it's a list, so while we enforce
5032 // singularity elsewhere, we keep it general here, to avoid surprises.
5033 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
5034 boolean sbnVisible = isVisibleToListener(sbn, info);
5039 final int importance = r.getImportance();
5040 final boolean fromUser = r.isImportanceFromUser();
5041 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
5042 mHandler.post(new Runnable() {
5045 notifyEnqueued(info, sbnToPost);
5051 private void notifyEnqueued(final ManagedServiceInfo info,
5052 final StatusBarNotification sbn) {
5053 final INotificationListener assistant = (INotificationListener) info.service;
5054 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5056 assistant.onNotificationEnqueued(sbnHolder);
5057 } catch (RemoteException ex) {
5058 Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
5063 * asynchronously notify the assistant that a notification has been snoozed until a
5066 @GuardedBy("mNotificationLock")
5067 public void notifyAssistantSnoozedLocked(final StatusBarNotification sbn,
5068 final String snoozeCriterionId) {
5069 TrimCache trimCache = new TrimCache(sbn);
5070 for (final ManagedServiceInfo info : getServices()) {
5071 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
5072 mHandler.post(new Runnable() {
5075 final INotificationListener assistant =
5076 (INotificationListener) info.service;
5077 StatusBarNotificationHolder sbnHolder
5078 = new StatusBarNotificationHolder(sbnToPost);
5080 assistant.onNotificationSnoozedUntilContext(
5081 sbnHolder, snoozeCriterionId);
5082 } catch (RemoteException ex) {
5083 Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
5090 public boolean isEnabled() {
5091 return !getServices().isEmpty();
5095 public class NotificationListeners extends ManagedServices {
5097 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
5099 public NotificationListeners() {
5100 super(getContext(), mHandler, mNotificationLock, mUserProfiles);
5104 protected Config getConfig() {
5105 Config c = new Config();
5106 c.caption = "notification listener";
5107 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
5108 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
5109 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
5110 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
5111 c.clientLabel = R.string.notification_listener_binding_label;
5116 protected IInterface asInterface(IBinder binder) {
5117 return INotificationListener.Stub.asInterface(binder);
5121 protected boolean checkType(IInterface service) {
5122 return service instanceof INotificationListener;
5126 public void onServiceAdded(ManagedServiceInfo info) {
5127 final INotificationListener listener = (INotificationListener) info.service;
5128 final NotificationRankingUpdate update;
5129 synchronized (mNotificationLock) {
5130 update = makeRankingUpdateLocked(info);
5133 listener.onListenerConnected(update);
5134 } catch (RemoteException e) {
5140 @GuardedBy("mNotificationLock")
5141 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
5142 if (removeDisabledHints(removed)) {
5143 updateListenerHintsLocked();
5144 updateEffectsSuppressorLocked();
5146 mLightTrimListeners.remove(removed);
5149 @GuardedBy("mNotificationLock")
5150 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
5151 if (trim == TRIM_LIGHT) {
5152 mLightTrimListeners.add(info);
5154 mLightTrimListeners.remove(info);
5158 public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
5159 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
5163 * asynchronously notify all listeners about a new notification
5166 * Also takes care of removing a notification that has been visible to a listener before,
5167 * but isn't anymore.
5169 @GuardedBy("mNotificationLock")
5170 public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
5171 // Lazily initialized snapshots of the notification.
5172 TrimCache trimCache = new TrimCache(sbn);
5174 for (final ManagedServiceInfo info : getServices()) {
5175 boolean sbnVisible = isVisibleToListener(sbn, info);
5176 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
5177 // This notification hasn't been and still isn't visible -> ignore.
5178 if (!oldSbnVisible && !sbnVisible) {
5181 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
5183 // This notification became invisible -> remove the old one.
5184 if (oldSbnVisible && !sbnVisible) {
5185 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
5186 mHandler.post(new Runnable() {
5189 notifyRemoved(info, oldSbnLightClone, update, REASON_USER_STOPPED);
5195 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
5196 mHandler.post(new Runnable() {
5199 notifyPosted(info, sbnToPost, update);
5206 * asynchronously notify all listeners about a removed notification
5208 @GuardedBy("mNotificationLock")
5209 public void notifyRemovedLocked(StatusBarNotification sbn, int reason) {
5210 // make a copy in case changes are made to the underlying Notification object
5211 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
5213 final StatusBarNotification sbnLight = sbn.cloneLight();
5214 for (final ManagedServiceInfo info : getServices()) {
5215 if (!isVisibleToListener(sbn, info)) {
5218 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
5219 mHandler.post(new Runnable() {
5222 notifyRemoved(info, sbnLight, update, reason);
5229 * asynchronously notify all listeners about a reordering of notifications
5231 @GuardedBy("mNotificationLock")
5232 public void notifyRankingUpdateLocked() {
5233 for (final ManagedServiceInfo serviceInfo : getServices()) {
5234 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5237 final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
5238 mHandler.post(new Runnable() {
5241 notifyRankingUpdate(serviceInfo, update);
5247 @GuardedBy("mNotificationLock")
5248 public void notifyListenerHintsChangedLocked(final int hints) {
5249 for (final ManagedServiceInfo serviceInfo : getServices()) {
5250 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5253 mHandler.post(new Runnable() {
5256 notifyListenerHintsChanged(serviceInfo, hints);
5262 public void notifyInterruptionFilterChanged(final int interruptionFilter) {
5263 for (final ManagedServiceInfo serviceInfo : getServices()) {
5264 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5267 mHandler.post(new Runnable() {
5270 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
5276 protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user,
5277 final NotificationChannel channel, final int modificationType) {
5278 if (channel == null) {
5281 for (final ManagedServiceInfo serviceInfo : getServices()) {
5282 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
5286 mHandler.post(new Runnable() {
5289 if (hasCompanionDevice(serviceInfo)) {
5290 notifyNotificationChannelChanged(
5291 serviceInfo, pkg, user, channel, modificationType);
5298 protected void notifyNotificationChannelGroupChanged(
5299 final String pkg, final UserHandle user, final NotificationChannelGroup group,
5300 final int modificationType) {
5301 if (group == null) {
5304 for (final ManagedServiceInfo serviceInfo : getServices()) {
5305 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
5309 mHandler.post(new Runnable() {
5312 if (hasCompanionDevice(serviceInfo)) {
5313 notifyNotificationChannelGroupChanged(
5314 serviceInfo, pkg, user, group, modificationType);
5321 private void notifyPosted(final ManagedServiceInfo info,
5322 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
5323 final INotificationListener listener = (INotificationListener) info.service;
5324 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5326 listener.onNotificationPosted(sbnHolder, rankingUpdate);
5327 } catch (RemoteException ex) {
5328 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
5332 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
5333 NotificationRankingUpdate rankingUpdate, int reason) {
5334 if (!info.enabledAndUserMatches(sbn.getUserId())) {
5337 final INotificationListener listener = (INotificationListener) info.service;
5338 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5340 listener.onNotificationRemoved(sbnHolder, rankingUpdate, reason);
5341 } catch (RemoteException ex) {
5342 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
5346 private void notifyRankingUpdate(ManagedServiceInfo info,
5347 NotificationRankingUpdate rankingUpdate) {
5348 final INotificationListener listener = (INotificationListener) info.service;
5350 listener.onNotificationRankingUpdate(rankingUpdate);
5351 } catch (RemoteException ex) {
5352 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
5356 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
5357 final INotificationListener listener = (INotificationListener) info.service;
5359 listener.onListenerHintsChanged(hints);
5360 } catch (RemoteException ex) {
5361 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
5365 private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
5366 int interruptionFilter) {
5367 final INotificationListener listener = (INotificationListener) info.service;
5369 listener.onInterruptionFilterChanged(interruptionFilter);
5370 } catch (RemoteException ex) {
5371 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
5375 void notifyNotificationChannelChanged(ManagedServiceInfo info,
5376 final String pkg, final UserHandle user, final NotificationChannel channel,
5377 final int modificationType) {
5378 final INotificationListener listener = (INotificationListener) info.service;
5380 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
5381 } catch (RemoteException ex) {
5382 Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
5386 private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
5387 final String pkg, final UserHandle user, final NotificationChannelGroup group,
5388 final int modificationType) {
5389 final INotificationListener listener = (INotificationListener) info.service;
5391 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
5392 } catch (RemoteException ex) {
5393 Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
5397 public boolean isListenerPackage(String packageName) {
5398 if (packageName == null) {
5401 // TODO: clean up locking object later
5402 synchronized (mNotificationLock) {
5403 for (final ManagedServiceInfo serviceInfo : getServices()) {
5404 if (packageName.equals(serviceInfo.component.getPackageName())) {
5413 public static final class DumpFilter {
5414 public boolean filtered = false;
5415 public String pkgFilter;
5418 public boolean stats;
5419 public boolean redact = true;
5420 public boolean proto = false;
5422 public static DumpFilter parseFromArguments(String[] args) {
5423 final DumpFilter filter = new DumpFilter();
5424 for (int ai = 0; ai < args.length; ai++) {
5425 final String a = args[ai];
5426 if ("--proto".equals(args[0])) {
5427 filter.proto = true;
5429 if ("--noredact".equals(a) || "--reveal".equals(a)) {
5430 filter.redact = false;
5431 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
5432 if (ai < args.length-1) {
5434 filter.pkgFilter = args[ai].trim().toLowerCase();
5435 if (filter.pkgFilter.isEmpty()) {
5436 filter.pkgFilter = null;
5438 filter.filtered = true;
5441 } else if ("--zen".equals(a) || "zen".equals(a)) {
5442 filter.filtered = true;
5444 } else if ("--stats".equals(a)) {
5445 filter.stats = true;
5446 if (ai < args.length-1) {
5448 filter.since = Long.parseLong(args[ai]);
5457 public boolean matches(StatusBarNotification sbn) {
5458 if (!filtered) return true;
5459 return zen ? true : sbn != null
5460 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
5463 public boolean matches(ComponentName component) {
5464 if (!filtered) return true;
5465 return zen ? true : component != null && matches(component.getPackageName());
5468 public boolean matches(String pkg) {
5469 if (!filtered) return true;
5470 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
5474 public String toString() {
5475 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
5480 * Wrapper for a StatusBarNotification object that allows transfer across a oneway
5481 * binder without sending large amounts of data over a oneway transaction.
5483 private static final class StatusBarNotificationHolder
5484 extends IStatusBarNotificationHolder.Stub {
5485 private StatusBarNotification mValue;
5487 public StatusBarNotificationHolder(StatusBarNotification value) {
5491 /** Get the held value and clear it. This function should only be called once per holder */
5493 public StatusBarNotification get() {
5494 StatusBarNotification value = mValue;
5500 private final class PolicyAccess {
5501 private static final String SEPARATOR = ":";
5502 private final String[] PERM = {
5503 android.Manifest.permission.ACCESS_NOTIFICATION_POLICY
5506 public boolean isPackageGranted(String pkg) {
5507 return pkg != null && getGrantedPackages().contains(pkg);
5510 public void put(String pkg, boolean granted) {
5511 if (pkg == null) return;
5512 final ArraySet<String> pkgs = getGrantedPackages();
5515 changed = pkgs.add(pkg);
5517 changed = pkgs.remove(pkg);
5519 if (!changed) return;
5520 final String setting = TextUtils.join(SEPARATOR, pkgs);
5521 final int currentUser = ActivityManager.getCurrentUser();
5522 Settings.Secure.putStringForUser(getContext().getContentResolver(),
5523 Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
5526 getContext().sendBroadcastAsUser(new Intent(NotificationManager
5527 .ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
5529 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), new UserHandle(currentUser), null);
5532 public ArraySet<String> getGrantedPackages() {
5533 final ArraySet<String> pkgs = new ArraySet<>();
5535 long identity = Binder.clearCallingIdentity();
5537 final String setting = Settings.Secure.getStringForUser(
5538 getContext().getContentResolver(),
5539 Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
5540 ActivityManager.getCurrentUser());
5541 if (setting != null) {
5542 final String[] tokens = setting.split(SEPARATOR);
5543 for (int i = 0; i < tokens.length; i++) {
5544 String token = tokens[i];
5545 if (token != null) {
5546 token = token.trim();
5548 if (TextUtils.isEmpty(token)) {
5555 Binder.restoreCallingIdentity(identity);
5560 public String[] getRequestingPackages() throws RemoteException {
5561 final ParceledListSlice list = mPackageManager
5562 .getPackagesHoldingPermissions(PERM, 0 /*flags*/,
5563 ActivityManager.getCurrentUser());
5564 final List<PackageInfo> pkgs = list.getList();
5565 if (pkgs == null || pkgs.isEmpty()) return new String[0];
5566 final int N = pkgs.size();
5567 final String[] rt = new String[N];
5568 for (int i = 0; i < N; i++) {
5569 rt[i] = pkgs.get(i).packageName;