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_LOW;
20 import static android.app.NotificationManager.IMPORTANCE_MIN;
21 import static android.app.NotificationManager.IMPORTANCE_NONE;
22 import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
23 import static android.content.pm.PackageManager.FEATURE_LEANBACK;
24 import static android.content.pm.PackageManager.FEATURE_TELEVISION;
25 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
26 import static android.os.UserHandle.USER_NULL;
27 import static android.service.notification.NotificationListenerService
28 .NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
29 import static android.service.notification.NotificationListenerService
30 .NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
31 import static android.service.notification.NotificationListenerService
32 .NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
33 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
34 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
35 import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
36 import static android.service.notification.NotificationListenerService.REASON_CANCEL;
37 import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
38 import static android.service.notification.NotificationListenerService.REASON_CLICK;
39 import static android.service.notification.NotificationListenerService.REASON_ERROR;
40 import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
41 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL;
42 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL;
43 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED;
44 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED;
45 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED;
46 import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF;
47 import static android.service.notification.NotificationListenerService.REASON_SNOOZED;
48 import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
49 import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
50 import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
51 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
52 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
53 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
54 import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
55 import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
56 import static android.service.notification.NotificationListenerService.TRIM_FULL;
57 import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
59 import static android.view.Display.DEFAULT_DISPLAY;
60 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
62 import android.Manifest;
63 import android.annotation.NonNull;
64 import android.annotation.Nullable;
65 import android.app.ActivityManager;
66 import android.app.ActivityManagerInternal;
67 import android.app.AlarmManager;
68 import android.app.AppGlobals;
69 import android.app.AppOpsManager;
70 import android.app.AutomaticZenRule;
71 import android.app.NotificationChannelGroup;
72 import android.app.backup.BackupManager;
73 import android.app.IActivityManager;
74 import android.app.INotificationManager;
75 import android.app.ITransientNotification;
76 import android.app.Notification;
77 import android.app.NotificationChannel;
78 import android.app.NotificationManager.Policy;
79 import android.app.NotificationManager;
80 import android.app.PendingIntent;
81 import android.app.StatusBarManager;
82 import android.app.usage.UsageEvents;
83 import android.app.usage.UsageStatsManagerInternal;
84 import android.companion.ICompanionDeviceManager;
85 import android.content.BroadcastReceiver;
86 import android.content.ComponentName;
87 import android.content.ContentResolver;
88 import android.content.Context;
89 import android.content.Intent;
90 import android.content.IntentFilter;
91 import android.content.pm.ApplicationInfo;
92 import android.content.pm.IPackageManager;
93 import android.content.pm.PackageManager;
94 import android.content.pm.PackageManager.NameNotFoundException;
95 import android.content.pm.ParceledListSlice;
96 import android.content.res.Resources;
97 import android.database.ContentObserver;
98 import android.media.AudioAttributes;
99 import android.media.AudioManager;
100 import android.media.AudioManagerInternal;
101 import android.media.IRingtonePlayer;
102 import android.net.Uri;
103 import android.os.Binder;
104 import android.os.Build;
105 import android.os.Bundle;
106 import android.os.Environment;
107 import android.os.Handler;
108 import android.os.HandlerThread;
109 import android.os.IBinder;
110 import android.os.IInterface;
111 import android.os.Looper;
112 import android.os.Message;
113 import android.os.Process;
114 import android.os.RemoteException;
115 import android.os.ResultReceiver;
116 import android.os.ServiceManager;
117 import android.os.ShellCallback;
118 import android.os.ShellCommand;
119 import android.os.SystemClock;
120 import android.os.SystemProperties;
121 import android.os.UserHandle;
122 import android.os.Vibrator;
123 import android.os.VibrationEffect;
124 import android.provider.Settings;
125 import android.service.notification.Adjustment;
126 import android.service.notification.Condition;
127 import android.service.notification.IConditionProvider;
128 import android.service.notification.INotificationListener;
129 import android.service.notification.IStatusBarNotificationHolder;
130 import android.service.notification.NotificationAssistantService;
131 import android.service.notification.NotificationListenerService;
132 import android.service.notification.NotificationRankingUpdate;
133 import android.service.notification.NotificationRecordProto;
134 import android.service.notification.NotificationServiceDumpProto;
135 import android.service.notification.NotificationServiceProto;
136 import android.service.notification.SnoozeCriterion;
137 import android.service.notification.StatusBarNotification;
138 import android.service.notification.ZenModeConfig;
139 import android.service.notification.ZenModeProto;
140 import android.telecom.TelecomManager;
141 import android.telephony.PhoneStateListener;
142 import android.telephony.TelephonyManager;
143 import android.text.TextUtils;
144 import android.util.ArrayMap;
145 import android.util.ArraySet;
146 import android.util.AtomicFile;
147 import android.util.Log;
148 import android.util.Slog;
149 import android.util.SparseArray;
150 import android.util.Xml;
151 import android.util.proto.ProtoOutputStream;
152 import android.view.WindowManagerInternal;
153 import android.view.accessibility.AccessibilityEvent;
154 import android.view.accessibility.AccessibilityManager;
155 import android.widget.Toast;
157 import com.android.internal.R;
158 import com.android.internal.annotations.GuardedBy;
159 import com.android.internal.annotations.VisibleForTesting;
160 import com.android.internal.logging.MetricsLogger;
161 import com.android.internal.logging.nano.MetricsProto;
162 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
163 import com.android.internal.os.BackgroundThread;
164 import com.android.internal.statusbar.NotificationVisibility;
165 import com.android.internal.util.ArrayUtils;
166 import com.android.internal.util.DumpUtils;
167 import com.android.internal.util.FastXmlSerializer;
168 import com.android.internal.util.Preconditions;
169 import com.android.internal.util.XmlUtils;
170 import com.android.server.DeviceIdleController;
171 import com.android.server.EventLogTags;
172 import com.android.server.LocalServices;
173 import com.android.server.SystemService;
174 import com.android.server.lights.Light;
175 import com.android.server.lights.LightsManager;
176 import com.android.server.notification.ManagedServices.ManagedServiceInfo;
177 import com.android.server.policy.PhoneWindowManager;
178 import com.android.server.statusbar.StatusBarManagerInternal;
179 import com.android.server.notification.ManagedServices.UserProfiles;
181 import libcore.io.IoUtils;
183 import org.json.JSONException;
184 import org.json.JSONObject;
185 import org.xmlpull.v1.XmlPullParser;
186 import org.xmlpull.v1.XmlPullParserException;
187 import org.xmlpull.v1.XmlSerializer;
189 import java.io.ByteArrayInputStream;
190 import java.io.ByteArrayOutputStream;
192 import java.io.FileDescriptor;
193 import java.io.FileNotFoundException;
194 import java.io.FileOutputStream;
195 import java.io.IOException;
196 import java.io.InputStream;
197 import java.io.OutputStream;
198 import java.io.PrintWriter;
200 import java.nio.charset.StandardCharsets;
201 import java.util.ArrayDeque;
202 import java.util.ArrayList;
203 import java.util.Arrays;
204 import java.util.Iterator;
205 import java.util.List;
206 import java.util.Map.Entry;
207 import java.util.Objects;
208 import java.util.Set;
209 import java.util.concurrent.TimeUnit;
212 public class NotificationManagerService extends SystemService {
213 static final String TAG = "NotificationService";
214 static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
215 public static final boolean ENABLE_CHILD_NOTIFICATIONS
216 = SystemProperties.getBoolean("debug.child_notifs", true);
218 static final int MAX_PACKAGE_NOTIFICATIONS = 50;
219 static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 5f;
222 static final int MESSAGE_TIMEOUT = 2;
223 static final int MESSAGE_SAVE_POLICY_FILE = 3;
224 static final int MESSAGE_SEND_RANKING_UPDATE = 4;
225 static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
226 static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
228 // ranking thread messages
229 private static final int MESSAGE_RECONSIDER_RANKING = 1000;
230 private static final int MESSAGE_RANKING_SORT = 1001;
232 static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
233 static final int SHORT_DELAY = 2000; // 2 seconds
235 static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
237 static final long SNOOZE_UNTIL_UNSPECIFIED = -1;
239 static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
241 static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
243 static final boolean ENABLE_BLOCKED_TOASTS = true;
245 // When #matchesCallFilter is called from the ringer, wait at most
246 // 3s to resolve the contacts. This timeout is required since
247 // ContactsProvider might take a long time to start up.
249 // Return STARRED_CONTACT when the timeout is hit in order to avoid
250 // missed calls in ZEN mode "Important".
251 static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
252 static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
253 ValidateNotificationPeople.STARRED_CONTACT;
255 /** notification_enqueue status value for a newly enqueued notification. */
256 private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
258 /** notification_enqueue status value for an existing notification. */
259 private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
261 /** notification_enqueue status value for an ignored notification. */
262 private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
263 private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
265 private static final long DELAY_FOR_ASSISTANT_TIME = 100;
267 private static final String ACTION_NOTIFICATION_TIMEOUT =
268 NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
269 private static final int REQUEST_CODE_TIMEOUT = 1;
270 private static final String SCHEME_TIMEOUT = "timeout";
271 private static final String EXTRA_KEY = "key";
273 private IActivityManager mAm;
274 private ActivityManager mActivityManager;
275 private IPackageManager mPackageManager;
276 private PackageManager mPackageManagerClient;
277 AudioManager mAudioManager;
278 AudioManagerInternal mAudioManagerInternal;
279 @Nullable StatusBarManagerInternal mStatusBar;
281 private WindowManagerInternal mWindowManagerInternal;
282 private AlarmManager mAlarmManager;
283 private ICompanionDeviceManager mCompanionManager;
284 private AccessibilityManager mAccessibilityManager;
286 final IBinder mForegroundToken = new Binder();
287 private WorkerHandler mHandler;
288 private final HandlerThread mRankingThread = new HandlerThread("ranker",
289 Process.THREAD_PRIORITY_BACKGROUND);
291 private Light mNotificationLight;
292 Light mAttentionLight;
294 private long[] mFallbackVibrationPattern;
295 private boolean mUseAttentionLight;
296 boolean mSystemReady;
298 private boolean mDisableNotificationEffects;
299 private int mCallState;
300 private String mSoundNotificationKey;
301 private String mVibrateNotificationKey;
303 private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
305 private List<ComponentName> mEffectsSuppressors = new ArrayList<>();
306 private int mListenerHints; // right now, all hints are global
307 private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
309 // for enabling and disabling notification pulse behavior
310 private boolean mScreenOn = true;
311 protected boolean mInCall = false;
312 private boolean mNotificationPulseEnabled;
314 private Uri mInCallNotificationUri;
315 private AudioAttributes mInCallNotificationAudioAttributes;
316 private float mInCallNotificationVolume;
318 // used as a mutex for access to all active notifications & listeners
319 final Object mNotificationLock = new Object();
320 @GuardedBy("mNotificationLock")
321 final ArrayList<NotificationRecord> mNotificationList = new ArrayList<>();
322 @GuardedBy("mNotificationLock")
323 final ArrayMap<String, NotificationRecord> mNotificationsByKey = new ArrayMap<>();
324 @GuardedBy("mNotificationLock")
325 final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();
326 @GuardedBy("mNotificationLock")
327 final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
328 final ArrayList<ToastRecord> mToastQueue = new ArrayList<>();
329 final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
331 // The last key in this list owns the hardware.
332 ArrayList<String> mLights = new ArrayList<>();
334 private AppOpsManager mAppOps;
335 private UsageStatsManagerInternal mAppUsageStats;
337 private Archive mArchive;
339 // Persistent storage for notification policy
340 private AtomicFile mPolicyFile;
342 private static final int DB_VERSION = 1;
344 private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
345 private static final String ATTR_VERSION = "version";
347 private RankingHelper mRankingHelper;
349 private final UserProfiles mUserProfiles = new UserProfiles();
350 private NotificationListeners mListeners;
351 private NotificationAssistants mAssistants;
352 private ConditionProviders mConditionProviders;
353 private NotificationUsageStats mUsageStats;
355 private static final int MY_UID = Process.myUid();
356 private static final int MY_PID = Process.myPid();
357 private static final IBinder WHITELIST_TOKEN = new Binder();
358 private RankingHandler mRankingHandler;
359 private long mLastOverRateLogTime;
360 private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
362 private SnoozeHelper mSnoozeHelper;
363 private GroupHelper mGroupHelper;
364 private boolean mIsTelevision;
366 private static class Archive {
367 final int mBufferSize;
368 final ArrayDeque<StatusBarNotification> mBuffer;
370 public Archive(int size) {
372 mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
375 public String toString() {
376 final StringBuilder sb = new StringBuilder();
377 final int N = mBuffer.size();
378 sb.append("Archive (");
380 sb.append(" notification");
381 sb.append((N==1)?")":"s)");
382 return sb.toString();
385 public void record(StatusBarNotification nr) {
386 if (mBuffer.size() == mBufferSize) {
387 mBuffer.removeFirst();
390 // We don't want to store the heavy bits of the notification in the archive,
391 // but other clients in the system process might be using the object, so we
392 // store a (lightened) copy.
393 mBuffer.addLast(nr.cloneLight());
396 public Iterator<StatusBarNotification> descendingIterator() {
397 return mBuffer.descendingIterator();
400 public StatusBarNotification[] getArray(int count) {
401 if (count == 0) count = mBufferSize;
402 final StatusBarNotification[] a
403 = new StatusBarNotification[Math.min(count, mBuffer.size())];
404 Iterator<StatusBarNotification> iter = descendingIterator();
406 while (iter.hasNext() && i < count) {
407 a[i++] = iter.next();
414 protected void readDefaultApprovedServices(int userId) {
415 String defaultListenerAccess = getContext().getResources().getString(
416 com.android.internal.R.string.config_defaultListenerAccessPackages);
417 if (defaultListenerAccess != null) {
418 for (String whitelisted :
419 defaultListenerAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
420 // Gather all notification listener components for candidate pkgs.
421 Set<ComponentName> approvedListeners =
422 mListeners.queryPackageForServices(whitelisted,
423 PackageManager.MATCH_DIRECT_BOOT_AWARE
424 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
425 for (ComponentName cn : approvedListeners) {
427 getBinderService().setNotificationListenerAccessGrantedForUser(cn,
429 } catch (RemoteException e) {
435 String defaultDndAccess = getContext().getResources().getString(
436 com.android.internal.R.string.config_defaultDndAccessPackages);
437 if (defaultListenerAccess != null) {
438 for (String whitelisted :
439 defaultDndAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
441 getBinderService().setNotificationPolicyAccessGranted(whitelisted, true);
442 } catch (RemoteException e) {
449 void readPolicyXml(InputStream stream, boolean forRestore)
450 throws XmlPullParserException, NumberFormatException, IOException {
451 final XmlPullParser parser = Xml.newPullParser();
452 parser.setInput(stream, StandardCharsets.UTF_8.name());
453 XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY);
454 boolean migratedManagedServices = false;
455 int outerDepth = parser.getDepth();
456 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
457 if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) {
458 mZenModeHelper.readXml(parser, forRestore);
459 } else if (RankingHelper.TAG_RANKING.equals(parser.getName())){
460 mRankingHelper.readXml(parser, forRestore);
462 // No non-system managed services are allowed on low ram devices
463 if (!ActivityManager.isLowRamDeviceStatic()) {
464 if (mListeners.getConfig().xmlTag.equals(parser.getName())) {
465 mListeners.readXml(parser);
466 migratedManagedServices = true;
467 } else if (mAssistants.getConfig().xmlTag.equals(parser.getName())) {
468 mAssistants.readXml(parser);
469 migratedManagedServices = true;
470 } else if (mConditionProviders.getConfig().xmlTag.equals(parser.getName())) {
471 mConditionProviders.readXml(parser);
472 migratedManagedServices = true;
477 if (!migratedManagedServices) {
478 mListeners.migrateToXml();
479 mAssistants.migrateToXml();
480 mConditionProviders.migrateToXml();
485 private void loadPolicyFile() {
486 if (DBG) Slog.d(TAG, "loadPolicyFile");
487 synchronized (mPolicyFile) {
489 InputStream infile = null;
491 infile = mPolicyFile.openRead();
492 readPolicyXml(infile, false /*forRestore*/);
493 } catch (FileNotFoundException e) {
495 // Load default managed services approvals
496 readDefaultApprovedServices(UserHandle.USER_SYSTEM);
497 } catch (IOException e) {
498 Log.wtf(TAG, "Unable to read notification policy", e);
499 } catch (NumberFormatException e) {
500 Log.wtf(TAG, "Unable to parse notification policy", e);
501 } catch (XmlPullParserException e) {
502 Log.wtf(TAG, "Unable to parse notification policy", e);
504 IoUtils.closeQuietly(infile);
509 public void savePolicyFile() {
510 mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
511 mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
514 private void handleSavePolicyFile() {
515 if (DBG) Slog.d(TAG, "handleSavePolicyFile");
516 synchronized (mPolicyFile) {
517 final FileOutputStream stream;
519 stream = mPolicyFile.startWrite();
520 } catch (IOException e) {
521 Slog.w(TAG, "Failed to save policy file", e);
526 writePolicyXml(stream, false /*forBackup*/);
527 mPolicyFile.finishWrite(stream);
528 } catch (IOException e) {
529 Slog.w(TAG, "Failed to save policy file, restoring backup", e);
530 mPolicyFile.failWrite(stream);
533 BackupManager.dataChanged(getContext().getPackageName());
536 private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
537 final XmlSerializer out = new FastXmlSerializer();
538 out.setOutput(stream, StandardCharsets.UTF_8.name());
539 out.startDocument(null, true);
540 out.startTag(null, TAG_NOTIFICATION_POLICY);
541 out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
542 mZenModeHelper.writeXml(out, forBackup);
543 mRankingHelper.writeXml(out, forBackup);
544 mListeners.writeXml(out, forBackup);
545 mAssistants.writeXml(out, forBackup);
546 mConditionProviders.writeXml(out, forBackup);
547 out.endTag(null, TAG_NOTIFICATION_POLICY);
551 /** Use this to check if a package can post a notification or toast. */
552 private boolean checkNotificationOp(String pkg, int uid) {
553 return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
554 == AppOpsManager.MODE_ALLOWED && !isPackageSuspendedForUser(pkg, uid);
557 private static final class ToastRecord
561 ITransientNotification callback;
565 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
569 this.callback = callback;
570 this.duration = duration;
574 void update(int duration) {
575 this.duration = duration;
578 void update(ITransientNotification callback) {
579 this.callback = callback;
582 void dump(PrintWriter pw, String prefix, DumpFilter filter) {
583 if (filter != null && !filter.matches(pkg)) return;
584 pw.println(prefix + this);
588 public final String toString()
590 return "ToastRecord{"
591 + Integer.toHexString(System.identityHashCode(this))
593 + " callback=" + callback
594 + " duration=" + duration;
599 final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
602 public void onSetDisabled(int status) {
603 synchronized (mNotificationLock) {
604 mDisableNotificationEffects =
605 (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
606 if (disableNotificationEffects(null) != null) {
607 // cancel whatever's going on
608 long identity = Binder.clearCallingIdentity();
610 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
611 if (player != null) {
614 } catch (RemoteException e) {
616 Binder.restoreCallingIdentity(identity);
619 identity = Binder.clearCallingIdentity();
623 Binder.restoreCallingIdentity(identity);
630 public void onClearAll(int callingUid, int callingPid, int userId) {
631 synchronized (mNotificationLock) {
632 cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null,
633 /*includeCurrentProfiles*/ true);
638 public void onNotificationClick(int callingUid, int callingPid, String key) {
639 synchronized (mNotificationLock) {
640 NotificationRecord r = mNotificationsByKey.get(key);
642 Log.w(TAG, "No notification with key: " + key);
645 final long now = System.currentTimeMillis();
646 MetricsLogger.action(r.getLogMaker(now)
647 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
648 .setType(MetricsEvent.TYPE_ACTION));
649 EventLogTags.writeNotificationClicked(key,
650 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
652 StatusBarNotification sbn = r.sbn;
653 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
654 sbn.getId(), Notification.FLAG_AUTO_CANCEL,
655 Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
661 public void onNotificationActionClick(int callingUid, int callingPid, String key,
663 synchronized (mNotificationLock) {
664 NotificationRecord r = mNotificationsByKey.get(key);
666 Log.w(TAG, "No notification with key: " + key);
669 final long now = System.currentTimeMillis();
670 MetricsLogger.action(r.getLogMaker(now)
671 .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION)
672 .setType(MetricsEvent.TYPE_ACTION)
673 .setSubtype(actionIndex));
674 EventLogTags.writeNotificationActionClicked(key, actionIndex,
675 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
676 // TODO: Log action click via UsageStats.
681 public void onNotificationClear(int callingUid, int callingPid,
682 String pkg, String tag, int id, int userId) {
683 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
684 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
685 true, userId, REASON_CANCEL, null);
689 public void onPanelRevealed(boolean clearEffects, int items) {
690 MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL);
691 MetricsLogger.histogram(getContext(), "note_load", items);
692 EventLogTags.writeNotificationPanelRevealed(items);
699 public void onPanelHidden() {
700 MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL);
701 EventLogTags.writeNotificationPanelHidden();
705 public void clearEffects() {
706 synchronized (mNotificationLock) {
707 if (DBG) Slog.d(TAG, "clearEffects");
709 clearVibrateLocked();
715 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
716 int uid, int initialPid, String message, int userId) {
717 Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
718 + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
719 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
721 long ident = Binder.clearCallingIdentity();
723 ActivityManager.getService().crashApplication(uid, initialPid, pkg, -1,
724 "Bad notification posted from package " + pkg
726 } catch (RemoteException e) {
728 Binder.restoreCallingIdentity(ident);
732 public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
733 NotificationVisibility[] noLongerVisibleKeys) {
734 synchronized (mNotificationLock) {
735 for (NotificationVisibility nv : newlyVisibleKeys) {
736 NotificationRecord r = mNotificationsByKey.get(nv.key);
737 if (r == null) continue;
738 r.setVisibility(true, nv.rank);
741 // Note that we might receive this event after notifications
742 // have already left the system, e.g. after dismissing from the
743 // shade. Hence not finding notifications in
744 // mNotificationsByKey is not an exceptional condition.
745 for (NotificationVisibility nv : noLongerVisibleKeys) {
746 NotificationRecord r = mNotificationsByKey.get(nv.key);
747 if (r == null) continue;
748 r.setVisibility(false, nv.rank);
755 public void onNotificationExpansionChanged(String key,
756 boolean userAction, boolean expanded) {
757 synchronized (mNotificationLock) {
758 NotificationRecord r = mNotificationsByKey.get(key);
760 r.stats.onExpansionChanged(userAction, expanded);
761 final long now = System.currentTimeMillis();
763 MetricsLogger.action(r.getLogMaker(now)
764 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
765 .setType(expanded ? MetricsEvent.TYPE_DETAIL
766 : MetricsEvent.TYPE_COLLAPSE));
768 EventLogTags.writeNotificationExpansion(key,
769 userAction ? 1 : 0, expanded ? 1 : 0,
770 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
776 @GuardedBy("mNotificationLock")
777 private void clearSoundLocked() {
778 mSoundNotificationKey = null;
779 long identity = Binder.clearCallingIdentity();
781 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
782 if (player != null) {
785 } catch (RemoteException e) {
787 Binder.restoreCallingIdentity(identity);
791 @GuardedBy("mNotificationLock")
792 private void clearVibrateLocked() {
793 mVibrateNotificationKey = null;
794 long identity = Binder.clearCallingIdentity();
798 Binder.restoreCallingIdentity(identity);
802 @GuardedBy("mNotificationLock")
803 private void clearLightsLocked() {
806 updateLightsLocked();
809 protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() {
811 public void onReceive(Context context, Intent intent) {
812 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
813 mZenModeHelper.updateDefaultZenRules();
814 mRankingHelper.onLocaleChanged(context, ActivityManager.getCurrentUser());
819 private final BroadcastReceiver mRestoreReceiver = new BroadcastReceiver() {
821 public void onReceive(Context context, Intent intent) {
822 if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
824 String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
825 String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
826 int restoredFromSdkInt = intent.getIntExtra(
827 Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, 0);
828 mListeners.onSettingRestored(
829 element, newValue, restoredFromSdkInt, getSendingUserId());
830 mConditionProviders.onSettingRestored(
831 element, newValue, restoredFromSdkInt, getSendingUserId());
832 } catch (Exception e) {
833 Slog.wtf(TAG, "Cannot restore managed services from settings", e);
839 private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() {
841 public void onReceive(Context context, Intent intent) {
842 String action = intent.getAction();
843 if (action == null) {
846 if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) {
847 final NotificationRecord record;
848 synchronized (mNotificationLock) {
849 record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
851 if (record != null) {
852 cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(),
853 record.sbn.getPackageName(), record.sbn.getTag(),
854 record.sbn.getId(), 0,
855 Notification.FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
856 REASON_TIMEOUT, null);
862 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
864 public void onReceive(Context context, Intent intent) {
865 String action = intent.getAction();
866 if (action == null) {
870 boolean queryRestart = false;
871 boolean queryRemove = false;
872 boolean packageChanged = false;
873 boolean cancelNotifications = true;
874 int reason = REASON_PACKAGE_CHANGED;
876 if (action.equals(Intent.ACTION_PACKAGE_ADDED)
877 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
878 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
879 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
880 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
881 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
882 || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
883 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
884 UserHandle.USER_ALL);
885 String pkgList[] = null;
886 int uidList[] = null;
887 boolean removingPackage = queryRemove &&
888 !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
889 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
890 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
891 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
892 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
893 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
894 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
895 reason = REASON_PACKAGE_SUSPENDED;
896 } else if (queryRestart) {
897 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
898 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
900 Uri uri = intent.getData();
904 String pkgName = uri.getSchemeSpecificPart();
905 if (pkgName == null) {
908 if (packageChanged) {
909 // We cancel notifications for packages which have just been disabled
911 final int enabled = mPackageManager.getApplicationEnabledSetting(
913 changeUserId != UserHandle.USER_ALL ? changeUserId :
914 UserHandle.USER_SYSTEM);
915 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
916 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
917 cancelNotifications = false;
919 } catch (IllegalArgumentException e) {
920 // Package doesn't exist; probably racing with uninstall.
921 // cancelNotifications is already true, so nothing to do here.
923 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
925 } catch (RemoteException e) {
926 // Failed to talk to PackageManagerService Should never happen!
929 pkgList = new String[]{pkgName};
930 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
932 if (pkgList != null && (pkgList.length > 0)) {
933 for (String pkgName : pkgList) {
934 if (cancelNotifications) {
935 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0,
936 !queryRestart, changeUserId, reason, null);
940 mListeners.onPackagesChanged(removingPackage, pkgList, uidList);
941 mAssistants.onPackagesChanged(removingPackage, pkgList, uidList);
942 mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList);
943 mRankingHelper.onPackagesChanged(removingPackage, changeUserId, pkgList, uidList);
949 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
951 public void onReceive(Context context, Intent intent) {
952 String action = intent.getAction();
954 if (action.equals(Intent.ACTION_SCREEN_ON)) {
955 // Keep track of screen on/off state, but do not turn off the notification light
956 // until user passes through the lock screen or views the notification.
958 updateNotificationPulse();
959 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
961 updateNotificationPulse();
962 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
963 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
964 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
965 updateNotificationPulse();
966 } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
967 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
968 if (userHandle >= 0) {
969 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
970 REASON_USER_STOPPED, null);
972 } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
973 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
974 if (userHandle >= 0) {
975 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
976 REASON_PROFILE_TURNED_OFF, null);
978 } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
979 // turn off LED when user passes through lock screen
980 mNotificationLight.turnOff();
981 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
982 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
983 // reload per-user settings
984 mSettingsObserver.update(null);
985 mUserProfiles.updateCache(context);
986 // Refresh managed services
987 mConditionProviders.onUserSwitched(user);
988 mListeners.onUserSwitched(user);
989 mAssistants.onUserSwitched(user);
990 mZenModeHelper.onUserSwitched(user);
991 } else if (action.equals(Intent.ACTION_USER_ADDED)) {
992 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
993 if (userId != USER_NULL) {
994 mUserProfiles.updateCache(context);
995 if (!mUserProfiles.isManagedProfile(userId)) {
996 readDefaultApprovedServices(userId);
999 } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
1000 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1001 mZenModeHelper.onUserRemoved(user);
1002 mRankingHelper.onUserRemoved(user);
1003 mListeners.onUserRemoved(user);
1004 mConditionProviders.onUserRemoved(user);
1005 mAssistants.onUserRemoved(user);
1007 } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
1008 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1009 mConditionProviders.onUserUnlocked(user);
1010 mListeners.onUserUnlocked(user);
1011 mAssistants.onUserUnlocked(user);
1012 mZenModeHelper.onUserUnlocked(user);
1017 private final class SettingsObserver extends ContentObserver {
1018 private final Uri NOTIFICATION_BADGING_URI
1019 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING);
1020 private final Uri NOTIFICATION_LIGHT_PULSE_URI
1021 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
1022 private final Uri NOTIFICATION_RATE_LIMIT_URI
1023 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
1025 SettingsObserver(Handler handler) {
1030 ContentResolver resolver = getContext().getContentResolver();
1031 resolver.registerContentObserver(NOTIFICATION_BADGING_URI,
1032 false, this, UserHandle.USER_ALL);
1033 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
1034 false, this, UserHandle.USER_ALL);
1035 resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
1036 false, this, UserHandle.USER_ALL);
1040 @Override public void onChange(boolean selfChange, Uri uri) {
1044 public void update(Uri uri) {
1045 ContentResolver resolver = getContext().getContentResolver();
1046 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
1047 boolean pulseEnabled = Settings.System.getIntForUser(resolver,
1048 Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT) != 0;
1049 if (mNotificationPulseEnabled != pulseEnabled) {
1050 mNotificationPulseEnabled = pulseEnabled;
1051 updateNotificationPulse();
1054 if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
1055 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
1056 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
1058 if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) {
1059 mRankingHelper.updateBadgingEnabled();
1064 private SettingsObserver mSettingsObserver;
1065 protected ZenModeHelper mZenModeHelper;
1067 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
1068 int[] ar = r.getIntArray(resid);
1072 final int len = ar.length > maxlen ? maxlen : ar.length;
1073 long[] out = new long[len];
1074 for (int i=0; i<len; i++) {
1080 public NotificationManagerService(Context context) {
1082 Notification.processWhitelistToken = WHITELIST_TOKEN;
1085 // TODO - replace these methods with a single VisibleForTesting constructor
1087 void setAudioManager(AudioManager audioMananger) {
1088 mAudioManager = audioMananger;
1092 void setVibrator(Vibrator vibrator) {
1093 mVibrator = vibrator;
1097 void setLights(Light light) {
1098 mNotificationLight = light;
1099 mAttentionLight = light;
1100 mNotificationPulseEnabled = true;
1104 void setScreenOn(boolean on) {
1109 int getNotificationRecordCount() {
1110 synchronized (mNotificationLock) {
1111 int count = mNotificationList.size() + mNotificationsByKey.size()
1112 + mSummaryByGroupKey.size() + mEnqueuedNotifications.size();
1113 // subtract duplicates
1114 for (NotificationRecord posted : mNotificationList) {
1115 if (mNotificationsByKey.containsKey(posted.getKey())) {
1118 if (posted.sbn.isGroup() && posted.getNotification().isGroupSummary()) {
1127 void clearNotifications() {
1128 mEnqueuedNotifications.clear();
1129 mNotificationList.clear();
1130 mNotificationsByKey.clear();
1131 mSummaryByGroupKey.clear();
1135 void addNotification(NotificationRecord r) {
1136 mNotificationList.add(r);
1137 mNotificationsByKey.put(r.sbn.getKey(), r);
1138 if (r.sbn.isGroup()) {
1139 mSummaryByGroupKey.put(r.getGroupKey(), r);
1144 void addEnqueuedNotification(NotificationRecord r) {
1145 mEnqueuedNotifications.add(r);
1149 NotificationRecord getNotificationRecord(String key) {
1150 return mNotificationsByKey.get(key);
1155 void setSystemReady(boolean systemReady) {
1156 mSystemReady = systemReady;
1160 void setHandler(WorkerHandler handler) {
1165 void setFallbackVibrationPattern(long[] vibrationPattern) {
1166 mFallbackVibrationPattern = vibrationPattern;
1170 void setPackageManager(IPackageManager packageManager) {
1171 mPackageManager = packageManager;
1175 void setRankingHelper(RankingHelper rankingHelper) {
1176 mRankingHelper = rankingHelper;
1180 void setRankingHandler(RankingHandler rankingHandler) {
1181 mRankingHandler = rankingHandler;
1185 void setIsTelevision(boolean isTelevision) {
1186 mIsTelevision = isTelevision;
1190 void setUsageStats(NotificationUsageStats us) {
1195 void setAccessibilityManager(AccessibilityManager am) {
1196 mAccessibilityManager = am;
1199 // TODO: All tests should use this init instead of the one-off setters above.
1201 void init(Looper looper, IPackageManager packageManager,
1202 PackageManager packageManagerClient,
1203 LightsManager lightsManager, NotificationListeners notificationListeners,
1204 NotificationAssistants notificationAssistants, ConditionProviders conditionProviders,
1205 ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
1206 NotificationUsageStats usageStats, AtomicFile policyFile,
1207 ActivityManager activityManager, GroupHelper groupHelper) {
1208 Resources resources = getContext().getResources();
1209 mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
1210 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
1211 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
1213 mAccessibilityManager =
1214 (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
1215 mAm = ActivityManager.getService();
1216 mPackageManager = packageManager;
1217 mPackageManagerClient = packageManagerClient;
1218 mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
1219 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
1220 mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
1221 mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
1222 mCompanionManager = companionManager;
1223 mActivityManager = activityManager;
1225 mHandler = new WorkerHandler(looper);
1226 mRankingThread.start();
1227 String[] extractorNames;
1229 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
1230 } catch (Resources.NotFoundException e) {
1231 extractorNames = new String[0];
1233 mUsageStats = usageStats;
1234 mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
1235 mRankingHelper = new RankingHelper(getContext(),
1236 mPackageManagerClient,
1240 mConditionProviders = conditionProviders;
1241 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
1242 mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
1244 public void onConfigChanged() {
1249 void onZenModeChanged() {
1250 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
1251 getContext().sendBroadcastAsUser(
1252 new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
1253 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
1254 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
1255 synchronized (mNotificationLock) {
1256 updateInterruptionFilterLocked();
1261 void onPolicyChanged() {
1262 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
1265 mSnoozeHelper = snoozeHelper;
1266 mGroupHelper = groupHelper;
1268 // This is a ManagedServices object that keeps track of the listeners.
1269 mListeners = notificationListeners;
1271 // This is a MangedServices object that keeps track of the assistant.
1272 mAssistants = notificationAssistants;
1274 mPolicyFile = policyFile;
1277 mStatusBar = getLocalService(StatusBarManagerInternal.class);
1278 if (mStatusBar != null) {
1279 mStatusBar.setNotificationDelegate(mNotificationDelegate);
1282 mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
1283 mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
1285 mFallbackVibrationPattern = getLongArray(resources,
1286 R.array.config_notificationFallbackVibePattern,
1287 VIBRATE_PATTERN_MAXLEN,
1288 DEFAULT_VIBRATE_PATTERN);
1289 mInCallNotificationUri = Uri.parse("file://" +
1290 resources.getString(R.string.config_inCallNotificationSound));
1291 mInCallNotificationAudioAttributes = new AudioAttributes.Builder()
1292 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
1293 .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
1295 mInCallNotificationVolume = resources.getFloat(R.dimen.config_inCallNotificationVolume);
1297 mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
1299 // Don't start allowing notifications until the setup wizard has run once.
1300 // After that, including subsequent boots, init with notifications turned on.
1301 // This works on the first boot because the setup wizard will toggle this
1302 // flag at least once and we'll go back to 0 after that.
1303 if (0 == Settings.Global.getInt(getContext().getContentResolver(),
1304 Settings.Global.DEVICE_PROVISIONED, 0)) {
1305 mDisableNotificationEffects = true;
1307 mZenModeHelper.initZenMode();
1308 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1310 mUserProfiles.updateCache(getContext());
1311 listenForCallState();
1313 mSettingsObserver = new SettingsObserver(mHandler);
1315 mArchive = new Archive(resources.getInteger(
1316 R.integer.config_notificationServiceArchiveSize));
1318 mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
1319 || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
1323 public void onStart() {
1324 SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() {
1326 public void repost(int userId, NotificationRecord r) {
1329 Slog.d(TAG, "Reposting " + r.getKey());
1331 enqueueNotificationInternal(r.sbn.getPackageName(), r.sbn.getOpPkg(),
1332 r.sbn.getUid(), r.sbn.getInitialPid(), r.sbn.getTag(), r.sbn.getId(),
1333 r.sbn.getNotification(), userId);
1334 } catch (Exception e) {
1335 Slog.e(TAG, "Cannot un-snooze notification", e);
1340 final File systemDir = new File(Environment.getDataDirectory(), "system");
1342 init(Looper.myLooper(),
1343 AppGlobals.getPackageManager(), getContext().getPackageManager(),
1344 getLocalService(LightsManager.class),
1345 new NotificationListeners(AppGlobals.getPackageManager()),
1346 new NotificationAssistants(AppGlobals.getPackageManager()),
1347 new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()),
1348 null, snoozeHelper, new NotificationUsageStats(getContext()),
1349 new AtomicFile(new File(systemDir, "notification_policy.xml")),
1350 (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE),
1353 // register for various Intents
1354 IntentFilter filter = new IntentFilter();
1355 filter.addAction(Intent.ACTION_SCREEN_ON);
1356 filter.addAction(Intent.ACTION_SCREEN_OFF);
1357 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
1358 filter.addAction(Intent.ACTION_USER_PRESENT);
1359 filter.addAction(Intent.ACTION_USER_STOPPED);
1360 filter.addAction(Intent.ACTION_USER_SWITCHED);
1361 filter.addAction(Intent.ACTION_USER_ADDED);
1362 filter.addAction(Intent.ACTION_USER_REMOVED);
1363 filter.addAction(Intent.ACTION_USER_UNLOCKED);
1364 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
1365 getContext().registerReceiver(mIntentReceiver, filter);
1367 IntentFilter pkgFilter = new IntentFilter();
1368 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
1369 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1370 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
1371 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1372 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1373 pkgFilter.addDataScheme("package");
1374 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1377 IntentFilter suspendedPkgFilter = new IntentFilter();
1378 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
1379 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1380 suspendedPkgFilter, null, null);
1382 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
1383 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1386 IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
1387 timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
1388 getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter);
1390 IntentFilter settingsRestoredFilter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
1391 getContext().registerReceiver(mRestoreReceiver, settingsRestoredFilter);
1393 IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
1394 getContext().registerReceiver(mLocaleChangeReceiver, localeChangedFilter);
1396 publishBinderService(Context.NOTIFICATION_SERVICE, mService);
1397 publishLocalService(NotificationManagerInternal.class, mInternalService);
1400 private GroupHelper getGroupHelper() {
1401 return new GroupHelper(new GroupHelper.Callback() {
1403 public void addAutoGroup(String key) {
1404 synchronized (mNotificationLock) {
1405 addAutogroupKeyLocked(key);
1410 public void removeAutoGroup(String key) {
1411 synchronized (mNotificationLock) {
1412 removeAutogroupKeyLocked(key);
1417 public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) {
1418 createAutoGroupSummary(userId, pkg, triggeringKey);
1422 public void removeAutoGroupSummary(int userId, String pkg) {
1423 synchronized (mNotificationLock) {
1424 clearAutogroupSummaryLocked(userId, pkg);
1430 private void sendRegisteredOnlyBroadcast(String action) {
1431 getContext().sendBroadcastAsUser(new Intent(action)
1432 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
1436 public void onBootPhase(int phase) {
1437 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1438 // no beeping until we're basically done booting
1439 mSystemReady = true;
1441 // Grab our optional AudioService
1442 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
1443 mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
1444 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
1445 mZenModeHelper.onSystemReady();
1446 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1447 // This observer will force an update when observe is called, causing us to
1448 // bind to listener services.
1449 mSettingsObserver.observe();
1450 mListeners.onBootPhaseAppsCanStart();
1451 mAssistants.onBootPhaseAppsCanStart();
1452 mConditionProviders.onBootPhaseAppsCanStart();
1456 @GuardedBy("mNotificationLock")
1457 private void updateListenerHintsLocked() {
1458 final int hints = calculateHints();
1459 if (hints == mListenerHints) return;
1460 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
1461 mListenerHints = hints;
1462 scheduleListenerHintsChanged(hints);
1465 @GuardedBy("mNotificationLock")
1466 private void updateEffectsSuppressorLocked() {
1467 final long updatedSuppressedEffects = calculateSuppressedEffects();
1468 if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1469 final List<ComponentName> suppressors = getSuppressors();
1470 ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1471 mEffectsSuppressors = suppressors;
1472 mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
1473 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
1476 private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
1477 boolean fromListener) {
1478 if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
1480 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
1481 UserHandle.getUserId(uid), REASON_CHANNEL_BANNED,
1483 if (isUidSystemOrPhone(uid)) {
1484 int[] profileIds = mUserProfiles.getCurrentProfileIds();
1485 int N = profileIds.length;
1486 for (int i = 0; i < N; i++) {
1487 int profileId = profileIds[i];
1488 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
1489 profileId, REASON_CHANNEL_BANNED,
1494 mRankingHelper.updateNotificationChannel(pkg, uid, channel, true);
1496 if (!fromListener) {
1497 final NotificationChannel modifiedChannel =
1498 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
1499 mListeners.notifyNotificationChannelChanged(
1500 pkg, UserHandle.getUserHandleForUid(uid),
1501 modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
1507 private ArrayList<ComponentName> getSuppressors() {
1508 ArrayList<ComponentName> names = new ArrayList<ComponentName>();
1509 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1510 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1512 for (ManagedServiceInfo info : serviceInfoList) {
1513 names.add(info.component);
1520 private boolean removeDisabledHints(ManagedServiceInfo info) {
1521 return removeDisabledHints(info, 0);
1524 private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
1525 boolean removed = false;
1527 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1528 final int hint = mListenersDisablingEffects.keyAt(i);
1529 final ArraySet<ManagedServiceInfo> listeners =
1530 mListenersDisablingEffects.valueAt(i);
1532 if (hints == 0 || (hint & hints) == hint) {
1533 removed = removed || listeners.remove(info);
1540 private void addDisabledHints(ManagedServiceInfo info, int hints) {
1541 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1542 addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
1545 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1546 addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1549 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1550 addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
1554 private void addDisabledHint(ManagedServiceInfo info, int hint) {
1555 if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
1556 mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
1559 ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
1560 hintListeners.add(info);
1563 private int calculateHints() {
1565 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1566 int hint = mListenersDisablingEffects.keyAt(i);
1567 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1569 if (!serviceInfoList.isEmpty()) {
1577 private long calculateSuppressedEffects() {
1578 int hints = calculateHints();
1579 long suppressedEffects = 0;
1581 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1582 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
1585 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1586 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
1589 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1590 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
1593 return suppressedEffects;
1596 @GuardedBy("mNotificationLock")
1597 private void updateInterruptionFilterLocked() {
1598 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1599 if (interruptionFilter == mInterruptionFilter) return;
1600 mInterruptionFilter = interruptionFilter;
1601 scheduleInterruptionFilterChanged(interruptionFilter);
1605 INotificationManager getBinderService() {
1606 return INotificationManager.Stub.asInterface(mService);
1610 NotificationManagerInternal getInternalService() {
1611 return mInternalService;
1614 private final IBinder mService = new INotificationManager.Stub() {
1616 // ============================================================================
1619 public void enqueueToast(String pkg, ITransientNotification callback, int duration)
1622 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1623 + " duration=" + duration);
1626 if (pkg == null || callback == null) {
1627 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1630 final boolean isSystemToast = isCallerSystemOrPhone() || ("android".equals(pkg));
1631 final boolean isPackageSuspended =
1632 isPackageSuspendedForUser(pkg, Binder.getCallingUid());
1634 if (ENABLE_BLOCKED_TOASTS && !isSystemToast &&
1635 (!areNotificationsEnabledForPackage(pkg, Binder.getCallingUid())
1636 || isPackageSuspended)) {
1637 Slog.e(TAG, "Suppressing toast from package " + pkg
1638 + (isPackageSuspended
1639 ? " due to package suspended by administrator."
1640 : " by user request."));
1644 synchronized (mToastQueue) {
1645 int callingPid = Binder.getCallingPid();
1646 long callingId = Binder.clearCallingIdentity();
1650 // All packages aside from the android package can enqueue one toast at a time
1651 if (!isSystemToast) {
1652 index = indexOfToastPackageLocked(pkg);
1654 index = indexOfToastLocked(pkg, callback);
1657 // If the package already has a toast, we update its toast
1658 // in the queue, we don't move it to the end of the queue.
1660 record = mToastQueue.get(index);
1661 record.update(duration);
1662 record.update(callback);
1664 Binder token = new Binder();
1665 mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, DEFAULT_DISPLAY);
1666 record = new ToastRecord(callingPid, pkg, callback, duration, token);
1667 mToastQueue.add(record);
1668 index = mToastQueue.size() - 1;
1670 keepProcessAliveIfNeededLocked(callingPid);
1671 // If it's at index 0, it's the current toast. It doesn't matter if it's
1672 // new or just been updated. Call back and tell it to show itself.
1673 // If the callback fails, this will remove it from the list, so don't
1674 // assume that it's valid after this.
1676 showNextToastLocked();
1679 Binder.restoreCallingIdentity(callingId);
1685 public void cancelToast(String pkg, ITransientNotification callback) {
1686 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
1688 if (pkg == null || callback == null) {
1689 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
1693 synchronized (mToastQueue) {
1694 long callingId = Binder.clearCallingIdentity();
1696 int index = indexOfToastLocked(pkg, callback);
1698 cancelToastLocked(index);
1700 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
1701 + " callback=" + callback);
1704 Binder.restoreCallingIdentity(callingId);
1710 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
1711 Notification notification, int userId) throws RemoteException {
1712 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
1713 Binder.getCallingPid(), tag, id, notification, userId);
1717 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
1718 checkCallerIsSystemOrSameApp(pkg);
1719 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1720 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
1721 // Don't allow client applications to cancel foreground service notis or autobundled
1723 final int mustNotHaveFlags = isCallingUidSystem() ? 0 :
1724 (Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTOGROUP_SUMMARY);
1725 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
1726 mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null);
1730 public void cancelAllNotifications(String pkg, int userId) {
1731 checkCallerIsSystemOrSameApp(pkg);
1733 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1734 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
1736 // Calling from user space, don't allow the canceling of actively
1737 // running foreground services.
1738 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
1739 pkg, null, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
1740 REASON_APP_CANCEL_ALL, null);
1744 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
1745 checkCallerIsSystem();
1747 mRankingHelper.setEnabled(pkg, uid, enabled);
1748 // Now, cancel any outstanding notifications that are part of a just-disabled app
1750 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
1751 UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
1757 * Use this when you just want to know if notifications are OK for this package.
1760 public boolean areNotificationsEnabled(String pkg) {
1761 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
1765 * Use this when you just want to know if notifications are OK for this package.
1768 public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
1769 checkCallerIsSystemOrSameApp(pkg);
1771 return mRankingHelper.getImportance(pkg, uid) != IMPORTANCE_NONE;
1775 public int getPackageImportance(String pkg) {
1776 checkCallerIsSystemOrSameApp(pkg);
1777 return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
1781 public boolean canShowBadge(String pkg, int uid) {
1782 checkCallerIsSystem();
1783 return mRankingHelper.canShowBadge(pkg, uid);
1787 public void setShowBadge(String pkg, int uid, boolean showBadge) {
1788 checkCallerIsSystem();
1789 mRankingHelper.setShowBadge(pkg, uid, showBadge);
1794 public void createNotificationChannelGroups(String pkg,
1795 ParceledListSlice channelGroupList) throws RemoteException {
1796 checkCallerIsSystemOrSameApp(pkg);
1797 List<NotificationChannelGroup> groups = channelGroupList.getList();
1798 final int groupSize = groups.size();
1799 for (int i = 0; i < groupSize; i++) {
1800 final NotificationChannelGroup group = groups.get(i);
1801 Preconditions.checkNotNull(group, "group in list is null");
1802 mRankingHelper.createNotificationChannelGroup(pkg, Binder.getCallingUid(), group,
1803 true /* fromTargetApp */);
1804 mListeners.notifyNotificationChannelGroupChanged(pkg,
1805 UserHandle.of(UserHandle.getCallingUserId()), group,
1806 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1811 private void createNotificationChannelsImpl(String pkg, int uid,
1812 ParceledListSlice channelsList) {
1813 List<NotificationChannel> channels = channelsList.getList();
1814 final int channelsSize = channels.size();
1815 for (int i = 0; i < channelsSize; i++) {
1816 final NotificationChannel channel = channels.get(i);
1817 Preconditions.checkNotNull(channel, "channel in list is null");
1818 mRankingHelper.createNotificationChannel(pkg, uid, channel,
1819 true /* fromTargetApp */);
1820 mListeners.notifyNotificationChannelChanged(pkg,
1821 UserHandle.getUserHandleForUid(uid),
1822 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false),
1823 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1829 public void createNotificationChannels(String pkg,
1830 ParceledListSlice channelsList) throws RemoteException {
1831 checkCallerIsSystemOrSameApp(pkg);
1832 createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList);
1836 public void createNotificationChannelsForPackage(String pkg, int uid,
1837 ParceledListSlice channelsList) throws RemoteException {
1838 checkCallerIsSystem();
1839 createNotificationChannelsImpl(pkg, uid, channelsList);
1843 public NotificationChannel getNotificationChannel(String pkg, String channelId) {
1844 checkCallerIsSystemOrSameApp(pkg);
1845 return mRankingHelper.getNotificationChannel(
1846 pkg, Binder.getCallingUid(), channelId, false /* includeDeleted */);
1850 public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
1851 String channelId, boolean includeDeleted) {
1852 checkCallerIsSystem();
1853 return mRankingHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted);
1857 public void deleteNotificationChannel(String pkg, String channelId) {
1858 checkCallerIsSystemOrSameApp(pkg);
1859 final int callingUid = Binder.getCallingUid();
1860 if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
1861 throw new IllegalArgumentException("Cannot delete default channel");
1863 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
1864 UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
1865 mRankingHelper.deleteNotificationChannel(pkg, callingUid, channelId);
1866 mListeners.notifyNotificationChannelChanged(pkg,
1867 UserHandle.getUserHandleForUid(callingUid),
1868 mRankingHelper.getNotificationChannel(pkg, callingUid, channelId, true),
1869 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1874 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
1876 checkCallerIsSystemOrSameApp(pkg);
1877 return new ParceledListSlice<>(new ArrayList(
1878 mRankingHelper.getNotificationChannelGroups(pkg, Binder.getCallingUid())));
1882 public void deleteNotificationChannelGroup(String pkg, String groupId) {
1883 checkCallerIsSystemOrSameApp(pkg);
1885 final int callingUid = Binder.getCallingUid();
1886 NotificationChannelGroup groupToDelete =
1887 mRankingHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
1888 if (groupToDelete != null) {
1889 List<NotificationChannel> deletedChannels =
1890 mRankingHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
1891 for (int i = 0; i < deletedChannels.size(); i++) {
1892 final NotificationChannel deletedChannel = deletedChannels.get(i);
1893 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
1895 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
1897 mListeners.notifyNotificationChannelChanged(pkg,
1898 UserHandle.getUserHandleForUid(callingUid),
1900 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1902 mListeners.notifyNotificationChannelGroupChanged(
1903 pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete,
1904 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1910 public void updateNotificationChannelForPackage(String pkg, int uid,
1911 NotificationChannel channel) {
1912 enforceSystemOrSystemUI("Caller not system or systemui");
1913 Preconditions.checkNotNull(channel);
1914 updateNotificationChannelInt(pkg, uid, channel, false);
1918 public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
1919 int uid, boolean includeDeleted) {
1920 enforceSystemOrSystemUI("getNotificationChannelsForPackage");
1921 return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted);
1925 public int getNumNotificationChannelsForPackage(String pkg, int uid,
1926 boolean includeDeleted) {
1927 enforceSystemOrSystemUI("getNumNotificationChannelsForPackage");
1928 return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted)
1933 public boolean onlyHasDefaultChannel(String pkg, int uid) {
1934 enforceSystemOrSystemUI("onlyHasDefaultChannel");
1935 return mRankingHelper.onlyHasDefaultChannel(pkg, uid);
1939 public int getDeletedChannelCount(String pkg, int uid) {
1940 enforceSystemOrSystemUI("getDeletedChannelCount");
1941 return mRankingHelper.getDeletedChannelCount(pkg, uid);
1945 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
1946 String pkg, int uid, boolean includeDeleted) {
1947 checkCallerIsSystem();
1948 return mRankingHelper.getNotificationChannelGroups(pkg, uid, includeDeleted);
1952 public NotificationChannelGroup getNotificationChannelGroupForPackage(
1953 String groupId, String pkg, int uid) {
1954 enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
1955 return mRankingHelper.getNotificationChannelGroup(groupId, pkg, uid);
1959 public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
1960 checkCallerIsSystemOrSameApp(pkg);
1961 return mRankingHelper.getNotificationChannels(
1962 pkg, Binder.getCallingUid(), false /* includeDeleted */);
1966 public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
1967 checkCallerIsSystem();
1969 // Cancel posted notifications
1970 cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true,
1971 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
1973 final String[] packages = new String[] {packageName};
1974 final int[] uids = new int[] {uid};
1976 // Listener & assistant
1977 mListeners.onPackagesChanged(true, packages, uids);
1978 mAssistants.onPackagesChanged(true, packages, uids);
1981 mConditionProviders.onPackagesChanged(true, packages, uids);
1983 // Reset notification preferences
1985 mRankingHelper.onPackagesChanged(
1986 true, UserHandle.getCallingUserId(), packages, uids);
1994 * System-only API for getting a list of current (i.e. not cleared) notifications.
1996 * Requires ACCESS_NOTIFICATIONS which is signature|system.
1997 * @returns A list of all the notifications, in natural order.
2000 public StatusBarNotification[] getActiveNotifications(String callingPkg) {
2001 // enforce() will ensure the calling uid has the correct permission
2002 getContext().enforceCallingOrSelfPermission(
2003 android.Manifest.permission.ACCESS_NOTIFICATIONS,
2004 "NotificationManagerService.getActiveNotifications");
2006 StatusBarNotification[] tmp = null;
2007 int uid = Binder.getCallingUid();
2009 // noteOp will check to make sure the callingPkg matches the uid
2010 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2011 == AppOpsManager.MODE_ALLOWED) {
2012 synchronized (mNotificationLock) {
2013 tmp = new StatusBarNotification[mNotificationList.size()];
2014 final int N = mNotificationList.size();
2015 for (int i=0; i<N; i++) {
2016 tmp[i] = mNotificationList.get(i).sbn;
2024 * Public API for getting a list of current notifications for the calling package/uid.
2026 * Note that since notification posting is done asynchronously, this will not return
2027 * notifications that are in the process of being posted.
2029 * @returns A list of all the package's notifications, in natural order.
2032 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
2033 int incomingUserId) {
2034 checkCallerIsSystemOrSameApp(pkg);
2035 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2036 Binder.getCallingUid(), incomingUserId, true, false,
2037 "getAppActiveNotifications", pkg);
2038 synchronized (mNotificationLock) {
2039 final ArrayMap<String, StatusBarNotification> map
2040 = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
2041 final int N = mNotificationList.size();
2042 for (int i = 0; i < N; i++) {
2043 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2044 mNotificationList.get(i).sbn);
2046 map.put(sbn.getKey(), sbn);
2049 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
2050 StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn);
2052 map.put(sbn.getKey(), sbn);
2055 final int M = mEnqueuedNotifications.size();
2056 for (int i = 0; i < M; i++) {
2057 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2058 mEnqueuedNotifications.get(i).sbn);
2060 map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
2063 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
2064 list.addAll(map.values());
2065 return new ParceledListSlice<StatusBarNotification>(list);
2069 private StatusBarNotification sanitizeSbn(String pkg, int userId,
2070 StatusBarNotification sbn) {
2071 if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId) {
2072 // We could pass back a cloneLight() but clients might get confused and
2073 // try to send this thing back to notify() again, which would not work
2075 return new StatusBarNotification(
2076 sbn.getPackageName(),
2078 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
2079 sbn.getNotification().clone(),
2080 sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
2086 * System-only API for getting a list of recent (cleared, no longer shown) notifications.
2088 * Requires ACCESS_NOTIFICATIONS which is signature|system.
2091 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
2092 // enforce() will ensure the calling uid has the correct permission
2093 getContext().enforceCallingOrSelfPermission(
2094 android.Manifest.permission.ACCESS_NOTIFICATIONS,
2095 "NotificationManagerService.getHistoricalNotifications");
2097 StatusBarNotification[] tmp = null;
2098 int uid = Binder.getCallingUid();
2100 // noteOp will check to make sure the callingPkg matches the uid
2101 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2102 == AppOpsManager.MODE_ALLOWED) {
2103 synchronized (mArchive) {
2104 tmp = mArchive.getArray(count);
2111 * Register a listener binder directly with the notification manager.
2113 * Only works with system callers. Apps should extend
2114 * {@link android.service.notification.NotificationListenerService}.
2117 public void registerListener(final INotificationListener listener,
2118 final ComponentName component, final int userid) {
2119 enforceSystemOrSystemUI("INotificationManager.registerListener");
2120 mListeners.registerService(listener, component, userid);
2124 * Remove a listener binder directly
2127 public void unregisterListener(INotificationListener token, int userid) {
2128 mListeners.unregisterService(token, userid);
2132 * Allow an INotificationListener to simulate a "clear all" operation.
2134 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
2136 * @param token The binder for the listener, to check that the caller is allowed
2139 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
2140 final int callingUid = Binder.getCallingUid();
2141 final int callingPid = Binder.getCallingPid();
2142 long identity = Binder.clearCallingIdentity();
2144 synchronized (mNotificationLock) {
2145 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2147 final int N = keys.length;
2148 for (int i = 0; i < N; i++) {
2149 NotificationRecord r = mNotificationsByKey.get(keys[i]);
2150 if (r == null) continue;
2151 final int userId = r.sbn.getUserId();
2152 if (userId != info.userid && userId != UserHandle.USER_ALL &&
2153 !mUserProfiles.isCurrentProfile(userId)) {
2154 throw new SecurityException("Disallowed call from listener: "
2157 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2158 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
2162 cancelAllLocked(callingUid, callingPid, info.userid,
2163 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
2167 Binder.restoreCallingIdentity(identity);
2172 * Handle request from an approved listener to re-enable itself.
2174 * @param component The componenet to be re-enabled, caller must match package.
2177 public void requestBindListener(ComponentName component) {
2178 checkCallerIsSystemOrSameApp(component.getPackageName());
2179 long identity = Binder.clearCallingIdentity();
2181 ManagedServices manager =
2182 mAssistants.isComponentEnabledForCurrentProfiles(component)
2185 manager.setComponentState(component, true);
2187 Binder.restoreCallingIdentity(identity);
2192 public void requestUnbindListener(INotificationListener token) {
2193 long identity = Binder.clearCallingIdentity();
2195 // allow bound services to disable themselves
2196 synchronized (mNotificationLock) {
2197 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2198 info.getOwner().setComponentState(info.component, false);
2201 Binder.restoreCallingIdentity(identity);
2206 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
2207 long identity = Binder.clearCallingIdentity();
2209 synchronized (mNotificationLock) {
2210 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2212 final int N = keys.length;
2213 for (int i = 0; i < N; i++) {
2214 NotificationRecord r = mNotificationsByKey.get(keys[i]);
2215 if (r == null) continue;
2216 final int userId = r.sbn.getUserId();
2217 if (userId != info.userid && userId != UserHandle.USER_ALL &&
2218 !mUserProfiles.isCurrentProfile(userId)) {
2219 throw new SecurityException("Disallowed call from listener: "
2223 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
2224 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
2225 userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM
2227 UsageEvents.Event.USER_INTERACTION);
2234 Binder.restoreCallingIdentity(identity);
2239 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2241 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2243 * @param info The binder for the listener, to check that the caller is allowed
2245 @GuardedBy("mNotificationLock")
2246 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
2247 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
2248 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
2249 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
2251 userId, REASON_LISTENER_CANCEL, info);
2255 * Allow an INotificationListener to snooze a single notification until a context.
2257 * @param token The binder for the listener, to check that the caller is allowed
2260 public void snoozeNotificationUntilContextFromListener(INotificationListener token,
2261 String key, String snoozeCriterionId) {
2262 long identity = Binder.clearCallingIdentity();
2264 synchronized (mNotificationLock) {
2265 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2266 snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info);
2269 Binder.restoreCallingIdentity(identity);
2274 * Allow an INotificationListener to snooze a single notification until a time.
2276 * @param token The binder for the listener, to check that the caller is allowed
2279 public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
2281 long identity = Binder.clearCallingIdentity();
2283 synchronized (mNotificationLock) {
2284 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2285 snoozeNotificationInt(key, duration, null, info);
2288 Binder.restoreCallingIdentity(identity);
2293 * Allows the notification assistant to un-snooze a single notification.
2295 * @param token The binder for the assistant, to check that the caller is allowed
2298 public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
2299 long identity = Binder.clearCallingIdentity();
2301 synchronized (mNotificationLock) {
2302 final ManagedServiceInfo info =
2303 mAssistants.checkServiceTokenLocked(token);
2304 unsnoozeNotificationInt(key, info);
2307 Binder.restoreCallingIdentity(identity);
2312 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2314 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2316 * @param token The binder for the listener, to check that the caller is allowed
2319 public void cancelNotificationFromListener(INotificationListener token, String pkg,
2320 String tag, int id) {
2321 final int callingUid = Binder.getCallingUid();
2322 final int callingPid = Binder.getCallingPid();
2323 long identity = Binder.clearCallingIdentity();
2325 synchronized (mNotificationLock) {
2326 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2327 if (info.supportsProfiles()) {
2328 Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
2329 + "from " + info.component
2330 + " use cancelNotification(key) instead.");
2332 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2333 pkg, tag, id, info.userid);
2337 Binder.restoreCallingIdentity(identity);
2342 * Allow an INotificationListener to request the list of outstanding notifications seen by
2343 * the current user. Useful when starting up, after which point the listener callbacks
2346 * @param token The binder for the listener, to check that the caller is allowed
2347 * @param keys An array of notification keys to fetch, or null to fetch everything
2348 * @returns The return value will contain the notifications specified in keys, in that
2349 * order, or if keys is null, all the notifications, in natural order.
2352 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
2353 INotificationListener token, String[] keys, int trim) {
2354 synchronized (mNotificationLock) {
2355 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2356 final boolean getKeys = keys != null;
2357 final int N = getKeys ? keys.length : mNotificationList.size();
2358 final ArrayList<StatusBarNotification> list
2359 = new ArrayList<StatusBarNotification>(N);
2360 for (int i=0; i<N; i++) {
2361 final NotificationRecord r = getKeys
2362 ? mNotificationsByKey.get(keys[i])
2363 : mNotificationList.get(i);
2364 if (r == null) continue;
2365 StatusBarNotification sbn = r.sbn;
2366 if (!isVisibleToListener(sbn, info)) continue;
2367 StatusBarNotification sbnToSend =
2368 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2369 list.add(sbnToSend);
2371 return new ParceledListSlice<StatusBarNotification>(list);
2376 * Allow an INotificationListener to request the list of outstanding snoozed notifications
2377 * seen by the current user. Useful when starting up, after which point the listener
2378 * callbacks should be used.
2380 * @param token The binder for the listener, to check that the caller is allowed
2381 * @returns The return value will contain the notifications specified in keys, in that
2382 * order, or if keys is null, all the notifications, in natural order.
2385 public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
2386 INotificationListener token, int trim) {
2387 synchronized (mNotificationLock) {
2388 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2389 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
2390 final int N = snoozedRecords.size();
2391 final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
2392 for (int i=0; i < N; i++) {
2393 final NotificationRecord r = snoozedRecords.get(i);
2394 if (r == null) continue;
2395 StatusBarNotification sbn = r.sbn;
2396 if (!isVisibleToListener(sbn, info)) continue;
2397 StatusBarNotification sbnToSend =
2398 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2399 list.add(sbnToSend);
2401 return new ParceledListSlice<>(list);
2406 public void requestHintsFromListener(INotificationListener token, int hints) {
2407 final long identity = Binder.clearCallingIdentity();
2409 synchronized (mNotificationLock) {
2410 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2411 final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
2412 | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
2413 | HINT_HOST_DISABLE_CALL_EFFECTS;
2414 final boolean disableEffects = (hints & disableEffectsMask) != 0;
2415 if (disableEffects) {
2416 addDisabledHints(info, hints);
2418 removeDisabledHints(info, hints);
2420 updateListenerHintsLocked();
2421 updateEffectsSuppressorLocked();
2424 Binder.restoreCallingIdentity(identity);
2429 public int getHintsFromListener(INotificationListener token) {
2430 synchronized (mNotificationLock) {
2431 return mListenerHints;
2436 public void requestInterruptionFilterFromListener(INotificationListener token,
2437 int interruptionFilter) throws RemoteException {
2438 final long identity = Binder.clearCallingIdentity();
2440 synchronized (mNotificationLock) {
2441 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2442 mZenModeHelper.requestFromListener(info.component, interruptionFilter);
2443 updateInterruptionFilterLocked();
2446 Binder.restoreCallingIdentity(identity);
2451 public int getInterruptionFilterFromListener(INotificationListener token)
2452 throws RemoteException {
2453 synchronized (mNotificationLight) {
2454 return mInterruptionFilter;
2459 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
2460 throws RemoteException {
2461 synchronized (mNotificationLock) {
2462 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2463 if (info == null) return;
2464 mListeners.setOnNotificationPostedTrimLocked(info, trim);
2469 public int getZenMode() {
2470 return mZenModeHelper.getZenMode();
2474 public ZenModeConfig getZenModeConfig() {
2475 enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
2476 return mZenModeHelper.getConfig();
2480 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
2481 enforceSystemOrSystemUI("INotificationManager.setZenMode");
2482 final long identity = Binder.clearCallingIdentity();
2484 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
2486 Binder.restoreCallingIdentity(identity);
2491 public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
2492 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
2493 return mZenModeHelper.getZenRules();
2497 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
2498 Preconditions.checkNotNull(id, "Id is null");
2499 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
2500 return mZenModeHelper.getAutomaticZenRule(id);
2504 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
2505 throws RemoteException {
2506 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2507 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2508 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2509 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2510 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
2512 return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
2513 "addAutomaticZenRule");
2517 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
2518 throws RemoteException {
2519 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2520 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2521 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2522 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2523 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
2525 return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
2526 "updateAutomaticZenRule");
2530 public boolean removeAutomaticZenRule(String id) throws RemoteException {
2531 Preconditions.checkNotNull(id, "Id is null");
2532 // Verify that they can modify zen rules.
2533 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
2535 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
2539 public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
2540 Preconditions.checkNotNull(packageName, "Package name is null");
2541 enforceSystemOrSystemUI("removeAutomaticZenRules");
2543 return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
2547 public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
2548 Preconditions.checkNotNull(owner, "Owner is null");
2549 enforceSystemOrSystemUI("getRuleInstanceCount");
2551 return mZenModeHelper.getCurrentInstanceCount(owner);
2555 public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
2556 enforcePolicyAccess(pkg, "setInterruptionFilter");
2557 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
2558 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
2559 final long identity = Binder.clearCallingIdentity();
2561 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
2563 Binder.restoreCallingIdentity(identity);
2568 public void notifyConditions(final String pkg, IConditionProvider provider,
2569 final Condition[] conditions) {
2570 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2571 checkCallerIsSystemOrSameApp(pkg);
2572 mHandler.post(new Runnable() {
2575 mConditionProviders.notifyConditions(pkg, info, conditions);
2581 public void requestUnbindProvider(IConditionProvider provider) {
2582 long identity = Binder.clearCallingIdentity();
2584 // allow bound services to disable themselves
2585 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2586 info.getOwner().setComponentState(info.component, false);
2588 Binder.restoreCallingIdentity(identity);
2593 public void requestBindProvider(ComponentName component) {
2594 checkCallerIsSystemOrSameApp(component.getPackageName());
2595 long identity = Binder.clearCallingIdentity();
2597 mConditionProviders.setComponentState(component, true);
2599 Binder.restoreCallingIdentity(identity);
2603 private void enforceSystemOrSystemUI(String message) {
2604 if (isCallerSystemOrPhone()) return;
2605 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
2609 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
2611 checkCallerIsSystemOrSameApp(pkg);
2612 } catch (SecurityException e) {
2613 getContext().enforceCallingPermission(
2614 android.Manifest.permission.STATUS_BAR_SERVICE,
2619 private void enforcePolicyAccess(int uid, String method) {
2620 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2621 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2624 boolean accessAllowed = false;
2625 String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
2626 final int packageCount = packages.length;
2627 for (int i = 0; i < packageCount; i++) {
2628 if (mConditionProviders.isPackageOrComponentAllowed(
2629 packages[i], UserHandle.getUserId(uid))) {
2630 accessAllowed = true;
2633 if (!accessAllowed) {
2634 Slog.w(TAG, "Notification policy access denied calling " + method);
2635 throw new SecurityException("Notification policy access denied");
2639 private void enforcePolicyAccess(String pkg, String method) {
2640 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2641 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2644 checkCallerIsSameApp(pkg);
2645 if (!checkPolicyAccess(pkg)) {
2646 Slog.w(TAG, "Notification policy access denied calling " + method);
2647 throw new SecurityException("Notification policy access denied");
2651 private boolean checkPackagePolicyAccess(String pkg) {
2652 return mConditionProviders.isPackageOrComponentAllowed(
2653 pkg, getCallingUserHandle().getIdentifier());
2656 private boolean checkPolicyAccess(String pkg) {
2658 int uid = getContext().getPackageManager().getPackageUidAsUser(
2659 pkg, UserHandle.getCallingUserId());
2660 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
2661 android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
2665 } catch (NameNotFoundException e) {
2668 return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
2672 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2673 if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
2674 final DumpFilter filter = DumpFilter.parseFromArguments(args);
2675 if (filter != null && filter.stats) {
2676 dumpJson(pw, filter);
2677 } else if (filter != null && filter.proto) {
2678 dumpProto(fd, filter);
2680 dumpImpl(pw, filter);
2685 public ComponentName getEffectsSuppressor() {
2686 return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
2690 public boolean matchesCallFilter(Bundle extras) {
2691 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
2692 return mZenModeHelper.matchesCallFilter(
2693 Binder.getCallingUserHandle(),
2695 mRankingHelper.findExtractor(ValidateNotificationPeople.class),
2696 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
2697 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
2701 public boolean isSystemConditionProviderEnabled(String path) {
2702 enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
2703 return mConditionProviders.isSystemProviderEnabled(path);
2706 // Backup/restore interface
2708 public byte[] getBackupPayload(int user) {
2709 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
2710 //TODO: http://b/22388012
2711 if (user != UserHandle.USER_SYSTEM) {
2712 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
2715 synchronized(mPolicyFile) {
2716 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
2718 writePolicyXml(baos, true /*forBackup*/);
2719 return baos.toByteArray();
2720 } catch (IOException e) {
2721 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
2728 public void applyRestore(byte[] payload, int user) {
2729 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
2730 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
2731 if (payload == null) {
2732 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
2735 //TODO: http://b/22388012
2736 if (user != UserHandle.USER_SYSTEM) {
2737 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
2740 synchronized(mPolicyFile) {
2741 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
2743 readPolicyXml(bais, true /*forRestore*/);
2745 } catch (NumberFormatException | XmlPullParserException | IOException e) {
2746 Slog.w(TAG, "applyRestore: error reading payload", e);
2752 public boolean isNotificationPolicyAccessGranted(String pkg) {
2753 return checkPolicyAccess(pkg);
2757 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
2758 enforceSystemOrSystemUIOrSamePackage(pkg,
2759 "request policy access status for another package");
2760 return checkPolicyAccess(pkg);
2764 public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
2765 throws RemoteException {
2766 setNotificationPolicyAccessGrantedForUser(
2767 pkg, getCallingUserHandle().getIdentifier(), granted);
2771 public void setNotificationPolicyAccessGrantedForUser(
2772 String pkg, int userId, boolean granted) {
2773 checkCallerIsSystemOrShell();
2774 final long identity = Binder.clearCallingIdentity();
2776 if (!mActivityManager.isLowRamDevice()) {
2777 mConditionProviders.setPackageOrComponentEnabled(
2778 pkg, userId, true, granted);
2780 getContext().sendBroadcastAsUser(new Intent(
2781 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
2783 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
2784 UserHandle.of(userId), null);
2788 Binder.restoreCallingIdentity(identity);
2793 public Policy getNotificationPolicy(String pkg) {
2794 enforcePolicyAccess(pkg, "getNotificationPolicy");
2795 final long identity = Binder.clearCallingIdentity();
2797 return mZenModeHelper.getNotificationPolicy();
2799 Binder.restoreCallingIdentity(identity);
2804 public void setNotificationPolicy(String pkg, Policy policy) {
2805 enforcePolicyAccess(pkg, "setNotificationPolicy");
2806 final long identity = Binder.clearCallingIdentity();
2808 mZenModeHelper.setNotificationPolicy(policy);
2810 Binder.restoreCallingIdentity(identity);
2815 public List<String> getEnabledNotificationListenerPackages() {
2816 checkCallerIsSystem();
2817 return mListeners.getAllowedPackages(getCallingUserHandle().getIdentifier());
2821 public List<ComponentName> getEnabledNotificationListeners(int userId) {
2822 checkCallerIsSystem();
2823 return mListeners.getAllowedComponents(userId);
2827 public boolean isNotificationListenerAccessGranted(ComponentName listener) {
2828 Preconditions.checkNotNull(listener);
2829 checkCallerIsSystemOrSameApp(listener.getPackageName());
2830 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
2831 getCallingUserHandle().getIdentifier());
2835 public boolean isNotificationListenerAccessGrantedForUser(ComponentName listener,
2837 Preconditions.checkNotNull(listener);
2838 checkCallerIsSystem();
2839 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
2844 public boolean isNotificationAssistantAccessGranted(ComponentName assistant) {
2845 Preconditions.checkNotNull(assistant);
2846 checkCallerIsSystemOrSameApp(assistant.getPackageName());
2847 return mAssistants.isPackageOrComponentAllowed(assistant.flattenToString(),
2848 getCallingUserHandle().getIdentifier());
2852 public void setNotificationListenerAccessGranted(ComponentName listener,
2853 boolean granted) throws RemoteException {
2854 setNotificationListenerAccessGrantedForUser(
2855 listener, getCallingUserHandle().getIdentifier(), granted);
2859 public void setNotificationAssistantAccessGranted(ComponentName assistant,
2860 boolean granted) throws RemoteException {
2861 setNotificationAssistantAccessGrantedForUser(
2862 assistant, getCallingUserHandle().getIdentifier(), granted);
2866 public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
2867 boolean granted) throws RemoteException {
2868 Preconditions.checkNotNull(listener);
2869 checkCallerIsSystemOrShell();
2870 final long identity = Binder.clearCallingIdentity();
2872 if (!mActivityManager.isLowRamDevice()) {
2873 mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
2874 userId, false, granted);
2875 mListeners.setPackageOrComponentEnabled(listener.flattenToString(),
2876 userId, true, granted);
2878 getContext().sendBroadcastAsUser(new Intent(
2879 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
2880 .setPackage(listener.getPackageName())
2881 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
2882 UserHandle.of(userId), null);
2887 Binder.restoreCallingIdentity(identity);
2892 public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
2893 int userId, boolean granted) throws RemoteException {
2894 Preconditions.checkNotNull(assistant);
2895 checkCallerIsSystemOrShell();
2896 final long identity = Binder.clearCallingIdentity();
2898 if (!mActivityManager.isLowRamDevice()) {
2899 mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
2900 userId, false, granted);
2901 mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
2902 userId, true, granted);
2904 getContext().sendBroadcastAsUser(new Intent(
2905 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
2906 .setPackage(assistant.getPackageName())
2907 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
2908 UserHandle.of(userId), null);
2913 Binder.restoreCallingIdentity(identity);
2918 public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
2919 Adjustment adjustment) throws RemoteException {
2920 final long identity = Binder.clearCallingIdentity();
2922 synchronized (mNotificationLock) {
2923 mAssistants.checkServiceTokenLocked(token);
2924 int N = mEnqueuedNotifications.size();
2925 for (int i = 0; i < N; i++) {
2926 final NotificationRecord n = mEnqueuedNotifications.get(i);
2927 if (Objects.equals(adjustment.getKey(), n.getKey())
2928 && Objects.equals(adjustment.getUser(), n.getUserId())) {
2929 applyAdjustment(n, adjustment);
2935 Binder.restoreCallingIdentity(identity);
2940 public void applyAdjustmentFromAssistant(INotificationListener token,
2941 Adjustment adjustment) throws RemoteException {
2942 final long identity = Binder.clearCallingIdentity();
2944 synchronized (mNotificationLock) {
2945 mAssistants.checkServiceTokenLocked(token);
2946 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2947 applyAdjustment(n, adjustment);
2949 mRankingHandler.requestSort();
2951 Binder.restoreCallingIdentity(identity);
2956 public void applyAdjustmentsFromAssistant(INotificationListener token,
2957 List<Adjustment> adjustments) throws RemoteException {
2959 final long identity = Binder.clearCallingIdentity();
2961 synchronized (mNotificationLock) {
2962 mAssistants.checkServiceTokenLocked(token);
2963 for (Adjustment adjustment : adjustments) {
2964 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2965 applyAdjustment(n, adjustment);
2968 mRankingHandler.requestSort();
2970 Binder.restoreCallingIdentity(identity);
2975 public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
2976 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
2977 Preconditions.checkNotNull(channel);
2978 Preconditions.checkNotNull(pkg);
2979 Preconditions.checkNotNull(user);
2981 verifyPrivilegedListener(token, user);
2982 updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
2986 public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
2987 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
2988 Preconditions.checkNotNull(pkg);
2989 Preconditions.checkNotNull(user);
2990 verifyPrivilegedListener(token, user);
2992 return mRankingHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user),
2993 false /* includeDeleted */);
2997 public ParceledListSlice<NotificationChannelGroup>
2998 getNotificationChannelGroupsFromPrivilegedListener(
2999 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
3000 Preconditions.checkNotNull(pkg);
3001 Preconditions.checkNotNull(user);
3002 verifyPrivilegedListener(token, user);
3004 List<NotificationChannelGroup> groups = new ArrayList<>();
3005 groups.addAll(mRankingHelper.getNotificationChannelGroups(
3006 pkg, getUidForPackageAndUser(pkg, user)));
3007 return new ParceledListSlice<>(groups);
3010 private void verifyPrivilegedListener(INotificationListener token, UserHandle user) {
3011 ManagedServiceInfo info;
3012 synchronized (mNotificationLock) {
3013 info = mListeners.checkServiceTokenLocked(token);
3015 if (!hasCompanionDevice(info)) {
3016 throw new SecurityException(info + " does not have access");
3018 if (!info.enabledAndUserMatches(user.getIdentifier())) {
3019 throw new SecurityException(info + " does not have access");
3023 private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
3025 long identity = Binder.clearCallingIdentity();
3027 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
3029 Binder.restoreCallingIdentity(identity);
3035 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
3036 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
3037 throws RemoteException {
3038 new ShellCmd().exec(this, in, out, err, args, callback, resultReceiver);
3042 private void applyAdjustment(NotificationRecord r, Adjustment adjustment) {
3046 if (adjustment.getSignals() != null) {
3047 Bundle.setDefusable(adjustment.getSignals(), true);
3048 r.addAdjustment(adjustment);
3052 @GuardedBy("mNotificationLock")
3053 void addAutogroupKeyLocked(String key) {
3054 NotificationRecord r = mNotificationsByKey.get(key);
3058 if (r.sbn.getOverrideGroupKey() == null) {
3059 addAutoGroupAdjustment(r, GroupHelper.AUTOGROUP_KEY);
3060 EventLogTags.writeNotificationAutogrouped(key);
3061 mRankingHandler.requestSort();
3065 @GuardedBy("mNotificationLock")
3066 void removeAutogroupKeyLocked(String key) {
3067 NotificationRecord r = mNotificationsByKey.get(key);
3071 if (r.sbn.getOverrideGroupKey() != null) {
3072 addAutoGroupAdjustment(r, null);
3073 EventLogTags.writeNotificationUnautogrouped(key);
3074 mRankingHandler.requestSort();
3078 private void addAutoGroupAdjustment(NotificationRecord r, String overrideGroupKey) {
3079 Bundle signals = new Bundle();
3080 signals.putString(Adjustment.KEY_GROUP_KEY, overrideGroupKey);
3081 Adjustment adjustment =
3082 new Adjustment(r.sbn.getPackageName(), r.getKey(), signals, "", r.sbn.getUserId());
3083 r.addAdjustment(adjustment);
3086 // Clears the 'fake' auto-group summary.
3087 @GuardedBy("mNotificationLock")
3088 private void clearAutogroupSummaryLocked(int userId, String pkg) {
3089 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3090 if (summaries != null && summaries.containsKey(pkg)) {
3092 final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
3093 if (removed != null) {
3094 boolean wasPosted = removeFromNotificationListsLocked(removed);
3095 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED, wasPosted, null);
3100 @GuardedBy("mNotificationLock")
3101 private boolean hasAutoGroupSummaryLocked(StatusBarNotification sbn) {
3102 ArrayMap<String, String> summaries = mAutobundledSummaries.get(sbn.getUserId());
3103 return summaries != null && summaries.containsKey(sbn.getPackageName());
3106 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
3107 private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
3108 NotificationRecord summaryRecord = null;
3109 synchronized (mNotificationLock) {
3110 NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
3111 if (notificationRecord == null) {
3112 // The notification could have been cancelled again already. A successive
3113 // adjustment will post a summary if needed.
3116 final StatusBarNotification adjustedSbn = notificationRecord.sbn;
3117 userId = adjustedSbn.getUser().getIdentifier();
3118 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3119 if (summaries == null) {
3120 summaries = new ArrayMap<>();
3122 mAutobundledSummaries.put(userId, summaries);
3123 if (!summaries.containsKey(pkg)) {
3125 final ApplicationInfo appInfo =
3126 adjustedSbn.getNotification().extras.getParcelable(
3127 Notification.EXTRA_BUILDER_APPLICATION_INFO);
3128 final Bundle extras = new Bundle();
3129 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
3130 final String channelId = notificationRecord.getChannel().getId();
3131 final Notification summaryNotification =
3132 new Notification.Builder(getContext(), channelId)
3133 .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
3134 .setGroupSummary(true)
3135 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN)
3136 .setGroup(GroupHelper.AUTOGROUP_KEY)
3137 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
3138 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
3139 .setColor(adjustedSbn.getNotification().color)
3142 summaryNotification.extras.putAll(extras);
3143 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
3144 if (appIntent != null) {
3145 summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
3146 getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
3148 final StatusBarNotification summarySbn =
3149 new StatusBarNotification(adjustedSbn.getPackageName(),
3150 adjustedSbn.getOpPkg(),
3152 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
3153 adjustedSbn.getInitialPid(), summaryNotification,
3154 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
3155 System.currentTimeMillis());
3156 summaryRecord = new NotificationRecord(getContext(), summarySbn,
3157 notificationRecord.getChannel());
3158 summaries.put(pkg, summarySbn.getKey());
3161 if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
3162 summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord, true)) {
3163 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
3167 private String disableNotificationEffects(NotificationRecord record) {
3168 if (mDisableNotificationEffects) {
3169 return "booleanState";
3171 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
3172 return "listenerHints";
3174 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
3180 private void dumpJson(PrintWriter pw, DumpFilter filter) {
3181 JSONObject dump = new JSONObject();
3183 dump.put("service", "Notification Manager");
3184 dump.put("bans", mRankingHelper.dumpBansJson(filter));
3185 dump.put("ranking", mRankingHelper.dumpJson(filter));
3186 dump.put("stats", mUsageStats.dumpJson(filter));
3187 dump.put("channels", mRankingHelper.dumpChannelsJson(filter));
3188 } catch (JSONException e) {
3189 e.printStackTrace();
3194 private void dumpProto(FileDescriptor fd, DumpFilter filter) {
3195 final ProtoOutputStream proto = new ProtoOutputStream(fd);
3196 synchronized (mNotificationLock) {
3197 long records = proto.start(NotificationServiceDumpProto.RECORDS);
3198 int N = mNotificationList.size();
3200 for (int i = 0; i < N; i++) {
3201 final NotificationRecord nr = mNotificationList.get(i);
3202 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3203 nr.dump(proto, filter.redact);
3204 proto.write(NotificationRecordProto.STATE, NotificationServiceProto.POSTED);
3207 N = mEnqueuedNotifications.size();
3209 for (int i = 0; i < N; i++) {
3210 final NotificationRecord nr = mEnqueuedNotifications.get(i);
3211 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3212 nr.dump(proto, filter.redact);
3213 proto.write(NotificationRecordProto.STATE, NotificationServiceProto.ENQUEUED);
3216 List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
3219 for (int i = 0; i < N; i++) {
3220 final NotificationRecord nr = snoozed.get(i);
3221 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3222 nr.dump(proto, filter.redact);
3223 proto.write(NotificationRecordProto.STATE, NotificationServiceProto.SNOOZED);
3229 long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
3230 mZenModeHelper.dump(proto);
3231 for (ComponentName suppressor : mEffectsSuppressors) {
3232 proto.write(ZenModeProto.SUPPRESSORS, suppressor.toString());
3239 void dumpImpl(PrintWriter pw, DumpFilter filter) {
3240 pw.print("Current Notification Manager state");
3241 if (filter.filtered) {
3242 pw.print(" (filtered to "); pw.print(filter); pw.print(")");
3246 final boolean zenOnly = filter.filtered && filter.zen;
3249 synchronized (mToastQueue) {
3250 N = mToastQueue.size();
3252 pw.println(" Toast Queue:");
3253 for (int i=0; i<N; i++) {
3254 mToastQueue.get(i).dump(pw, " ", filter);
3261 synchronized (mNotificationLock) {
3263 N = mNotificationList.size();
3265 pw.println(" Notification List:");
3266 for (int i=0; i<N; i++) {
3267 final NotificationRecord nr = mNotificationList.get(i);
3268 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3269 nr.dump(pw, " ", getContext(), filter.redact);
3274 if (!filter.filtered) {
3277 pw.println(" Lights List:");
3278 for (int i=0; i<N; i++) {
3284 pw.println(mLights.get(i));
3288 pw.println(" mUseAttentionLight=" + mUseAttentionLight);
3289 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled);
3290 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey);
3291 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey);
3292 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects);
3293 pw.println(" mCallState=" + callStateToString(mCallState));
3294 pw.println(" mSystemReady=" + mSystemReady);
3295 pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
3297 pw.println(" mArchive=" + mArchive.toString());
3298 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
3300 while (iter.hasNext()) {
3301 final StatusBarNotification sbn = iter.next();
3302 if (filter != null && !filter.matches(sbn)) continue;
3303 pw.println(" " + sbn);
3305 if (iter.hasNext()) pw.println(" ...");
3311 N = mEnqueuedNotifications.size();
3313 pw.println(" Enqueued Notification List:");
3314 for (int i = 0; i < N; i++) {
3315 final NotificationRecord nr = mEnqueuedNotifications.get(i);
3316 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3317 nr.dump(pw, " ", getContext(), filter.redact);
3322 mSnoozeHelper.dump(pw, filter);
3327 pw.println("\n Ranking Config:");
3328 mRankingHelper.dump(pw, " ", filter);
3330 pw.println("\n Notification listeners:");
3331 mListeners.dump(pw, filter);
3332 pw.print(" mListenerHints: "); pw.println(mListenerHints);
3333 pw.print(" mListenersDisablingEffects: (");
3334 N = mListenersDisablingEffects.size();
3335 for (int i = 0; i < N; i++) {
3336 final int hint = mListenersDisablingEffects.keyAt(i);
3337 if (i > 0) pw.print(';');
3338 pw.print("hint[" + hint + "]:");
3340 final ArraySet<ManagedServiceInfo> listeners =
3341 mListenersDisablingEffects.valueAt(i);
3342 final int listenerSize = listeners.size();
3344 for (int j = 0; j < listenerSize; j++) {
3345 if (i > 0) pw.print(',');
3346 final ManagedServiceInfo listener = listeners.valueAt(i);
3347 pw.print(listener.component);
3351 pw.println("\n Notification assistant services:");
3352 mAssistants.dump(pw, filter);
3355 if (!filter.filtered || zenOnly) {
3356 pw.println("\n Zen Mode:");
3357 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter);
3358 mZenModeHelper.dump(pw, " ");
3360 pw.println("\n Zen Log:");
3361 ZenLog.dump(pw, " ");
3364 pw.println("\n Condition providers:");
3365 mConditionProviders.dump(pw, filter);
3367 pw.println("\n Group summaries:");
3368 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
3369 NotificationRecord r = entry.getValue();
3370 pw.println(" " + entry.getKey() + " -> " + r.getKey());
3371 if (mNotificationsByKey.get(r.getKey()) != r) {
3372 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
3373 r.dump(pw, " ", getContext(), filter.redact);
3378 pw.println("\n Usage Stats:");
3379 mUsageStats.dump(pw, " ", filter);
3385 * The private API only accessible to the system process.
3387 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
3389 public NotificationChannel getNotificationChannel(String pkg, int uid, String
3391 return mRankingHelper.getNotificationChannel(pkg, uid, channelId, false);
3395 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
3396 String tag, int id, Notification notification, int userId) {
3397 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
3402 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
3404 checkCallerIsSystem();
3405 mHandler.post(new Runnable() {
3408 synchronized (mNotificationLock) {
3409 removeForegroundServiceFlagByListLocked(
3410 mEnqueuedNotifications, pkg, notificationId, userId);
3411 removeForegroundServiceFlagByListLocked(
3412 mNotificationList, pkg, notificationId, userId);
3418 @GuardedBy("mNotificationLock")
3419 private void removeForegroundServiceFlagByListLocked(
3420 ArrayList<NotificationRecord> notificationList, String pkg, int notificationId,
3422 NotificationRecord r = findNotificationByListLocked(
3423 notificationList, pkg, null, notificationId, userId);
3427 StatusBarNotification sbn = r.sbn;
3428 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
3429 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
3430 // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
3431 // initially *and* force remove FLAG_FOREGROUND_SERVICE.
3432 sbn.getNotification().flags =
3433 (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
3434 mRankingHelper.sort(mNotificationList);
3435 mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
3439 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
3440 final int callingPid, final String tag, final int id, final Notification notification,
3441 int incomingUserId) {
3443 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
3444 + " notification=" + notification);
3446 checkCallerIsSystemOrSameApp(pkg);
3448 final int userId = ActivityManager.handleIncomingUser(callingPid,
3449 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
3450 final UserHandle user = new UserHandle(userId);
3452 if (pkg == null || notification == null) {
3453 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
3454 + " id=" + id + " notification=" + notification);
3457 // The system can post notifications for any package, let us resolve that.
3458 final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);
3460 // Fix the notification as best we can.
3462 final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
3463 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
3464 (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
3465 Notification.addFieldsFromContext(ai, notification);
3467 int canColorize = mPackageManagerClient.checkPermission(
3468 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, pkg);
3469 if (canColorize == PERMISSION_GRANTED) {
3470 notification.flags |= Notification.FLAG_CAN_COLORIZE;
3472 notification.flags &= ~Notification.FLAG_CAN_COLORIZE;
3475 } catch (NameNotFoundException e) {
3476 Slog.e(TAG, "Cannot create a context for sending app", e);
3480 mUsageStats.registerEnqueuedByApp(pkg);
3482 // setup local book-keeping
3483 String channelId = notification.getChannelId();
3484 if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
3485 channelId = (new Notification.TvExtender(notification)).getChannelId();
3487 final NotificationChannel channel = mRankingHelper.getNotificationChannel(pkg,
3488 notificationUid, channelId, false /* includeDeleted */);
3489 if (channel == null) {
3490 final String noChannelStr = "No Channel found for "
3492 + ", channelId=" + channelId
3495 + ", opPkg=" + opPkg
3496 + ", callingUid=" + callingUid
3497 + ", userId=" + userId
3498 + ", incomingUserId=" + incomingUserId
3499 + ", notificationUid=" + notificationUid
3500 + ", notification=" + notification;
3501 Log.e(TAG, noChannelStr);
3502 doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
3503 "Failed to post notification on channel \"" + channelId + "\"\n" +
3504 "See log for more details");
3508 final StatusBarNotification n = new StatusBarNotification(
3509 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
3510 user, null, System.currentTimeMillis());
3511 final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
3513 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0
3514 && (channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
3515 && (r.getImportance() == IMPORTANCE_MIN || r.getImportance() == IMPORTANCE_NONE)) {
3516 // Increase the importance of foreground service notifications unless the user had an
3517 // opinion otherwise
3518 if (TextUtils.isEmpty(channelId)
3519 || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
3520 r.setImportance(IMPORTANCE_LOW, "Bumped for foreground service");
3522 channel.setImportance(IMPORTANCE_LOW);
3523 mRankingHelper.updateNotificationChannel(pkg, notificationUid, channel, false);
3524 r.updateNotificationChannel(channel);
3528 if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
3529 r.sbn.getOverrideGroupKey() != null)) {
3533 // Whitelist pending intents.
3534 if (notification.allPendingIntents != null) {
3535 final int intentCount = notification.allPendingIntents.size();
3536 if (intentCount > 0) {
3537 final ActivityManagerInternal am = LocalServices
3538 .getService(ActivityManagerInternal.class);
3539 final long duration = LocalServices.getService(
3540 DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
3541 for (int i = 0; i < intentCount; i++) {
3542 PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
3543 if (pendingIntent != null) {
3544 am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
3545 WHITELIST_TOKEN, duration);
3551 mHandler.post(new EnqueueNotificationRunnable(userId, r));
3554 private void doChannelWarningToast(CharSequence toastText) {
3555 final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
3556 final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
3557 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
3558 if (warningEnabled) {
3559 Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
3560 Toast.LENGTH_SHORT);
3565 private int resolveNotificationUid(String opPackageName, int callingUid, int userId) {
3566 // The system can post notifications on behalf of any package it wants
3567 if (isCallerSystemOrPhone() && opPackageName != null && !"android".equals(opPackageName)) {
3569 return getContext().getPackageManager()
3570 .getPackageUidAsUser(opPackageName, userId);
3571 } catch (NameNotFoundException e) {
3579 * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
3583 private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag,
3584 NotificationRecord r, boolean isAutogroup) {
3585 final String pkg = r.sbn.getPackageName();
3586 final String dialerPackage =
3587 getContext().getSystemService(TelecomManager.class).getSystemDialerPackage();
3588 final boolean isSystemNotification =
3589 isUidSystemOrPhone(callingUid) || ("android".equals(pkg))
3590 || TextUtils.equals(pkg, dialerPackage);
3591 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
3593 // Limit the number of notifications that any given package except the android
3594 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
3595 if (!isSystemNotification && !isNotificationFromListener) {
3596 synchronized (mNotificationLock) {
3597 if (mNotificationsByKey.get(r.sbn.getKey()) == null && isCallerInstantApp(pkg)) {
3598 // Ephemeral apps have some special constraints for notifications.
3599 // They are not allowed to create new notifications however they are allowed to
3600 // update notifications created by the system (e.g. a foreground service
3602 throw new SecurityException("Instant app " + pkg
3603 + " cannot create notifications");
3606 // rate limit updates that aren't completed progress notifications
3607 if (mNotificationsByKey.get(r.sbn.getKey()) != null
3608 && !r.getNotification().hasCompletedProgress()
3611 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
3612 if (appEnqueueRate > mMaxPackageEnqueueRate) {
3613 mUsageStats.registerOverRateQuota(pkg);
3614 final long now = SystemClock.elapsedRealtime();
3615 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
3616 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
3617 + ". Shedding " + r.sbn.getKey() + ". package=" + pkg);
3618 mLastOverRateLogTime = now;
3624 // limit the number of outstanding notificationrecords an app can have
3625 int count = getNotificationCountLocked(pkg, userId, id, tag);
3626 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
3627 mUsageStats.registerOverCountQuota(pkg);
3628 Slog.e(TAG, "Package has already posted or enqueued " + count
3629 + " notifications. Not showing more. package=" + pkg);
3636 if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
3637 MetricsLogger.action(r.getLogMaker()
3638 .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
3639 .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
3641 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
3643 mSnoozeHelper.update(userId, r);
3650 if (isBlocked(r, mUsageStats)) {
3657 protected int getNotificationCountLocked(String pkg, int userId, int excludedId,
3658 String excludedTag) {
3660 final int N = mNotificationList.size();
3661 for (int i = 0; i < N; i++) {
3662 final NotificationRecord existing = mNotificationList.get(i);
3663 if (existing.sbn.getPackageName().equals(pkg)
3664 && existing.sbn.getUserId() == userId) {
3665 if (existing.sbn.getId() == excludedId
3666 && TextUtils.equals(existing.sbn.getTag(), excludedTag)) {
3672 final int M = mEnqueuedNotifications.size();
3673 for (int i = 0; i < M; i++) {
3674 final NotificationRecord existing = mEnqueuedNotifications.get(i);
3675 if (existing.sbn.getPackageName().equals(pkg)
3676 && existing.sbn.getUserId() == userId) {
3683 protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
3684 final String pkg = r.sbn.getPackageName();
3685 final int callingUid = r.sbn.getUid();
3687 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
3688 if (isPackageSuspended) {
3689 Slog.e(TAG, "Suppressing notification from package due to package "
3690 + "suspended by administrator.");
3691 usageStats.registerSuspendedByAdmin(r);
3692 return isPackageSuspended;
3695 final boolean isBlocked =
3696 mRankingHelper.getImportance(pkg, callingUid) == NotificationManager.IMPORTANCE_NONE
3697 || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE;
3699 Slog.e(TAG, "Suppressing notification from package by user request.");
3700 usageStats.registerBlocked(r);
3705 protected class SnoozeNotificationRunnable implements Runnable {
3706 private final String mKey;
3707 private final long mDuration;
3708 private final String mSnoozeCriterionId;
3710 SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) {
3712 mDuration = duration;
3713 mSnoozeCriterionId = snoozeCriterionId;
3718 synchronized (mNotificationLock) {
3719 final NotificationRecord r = findNotificationByKeyLocked(mKey);
3726 @GuardedBy("mNotificationLock")
3727 void snoozeLocked(NotificationRecord r) {
3728 if (r.sbn.isGroup()) {
3729 final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked(
3730 r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId());
3731 if (r.getNotification().isGroupSummary()) {
3732 // snooze summary and all children
3733 for (int i = 0; i < groupNotifications.size(); i++) {
3734 snoozeNotificationLocked(groupNotifications.get(i));
3737 // if there is a valid summary for this group, and we are snoozing the only
3738 // child, also snooze the summary
3739 if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) {
3740 if (groupNotifications.size() != 2) {
3741 snoozeNotificationLocked(r);
3743 // snooze summary and the one child
3744 for (int i = 0; i < groupNotifications.size(); i++) {
3745 snoozeNotificationLocked(groupNotifications.get(i));
3749 snoozeNotificationLocked(r);
3753 // just snooze the one notification
3754 snoozeNotificationLocked(r);
3758 @GuardedBy("mNotificationLock")
3759 void snoozeNotificationLocked(NotificationRecord r) {
3760 MetricsLogger.action(r.getLogMaker()
3761 .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
3762 .setType(MetricsEvent.TYPE_CLOSE)
3763 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS,
3765 .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
3766 mSnoozeCriterionId == null ? 0 : 1));
3767 boolean wasPosted = removeFromNotificationListsLocked(r);
3768 cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null);
3769 updateLightsLocked();
3770 if (mSnoozeCriterionId != null) {
3771 mAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
3772 mSnoozeHelper.snooze(r);
3774 mSnoozeHelper.snooze(r, mDuration);
3780 protected class EnqueueNotificationRunnable implements Runnable {
3781 private final NotificationRecord r;
3782 private final int userId;
3784 EnqueueNotificationRunnable(int userId, NotificationRecord r) {
3785 this.userId = userId;
3791 synchronized (mNotificationLock) {
3792 mEnqueuedNotifications.add(r);
3793 scheduleTimeoutLocked(r);
3795 final StatusBarNotification n = r.sbn;
3796 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
3797 NotificationRecord old = mNotificationsByKey.get(n.getKey());
3799 // Retain ranking information from previous record
3800 r.copyRankingInformation(old);
3803 final int callingUid = n.getUid();
3804 final int callingPid = n.getInitialPid();
3805 final Notification notification = n.getNotification();
3806 final String pkg = n.getPackageName();
3807 final int id = n.getId();
3808 final String tag = n.getTag();
3810 // Handle grouped notifications and bail out early if we
3811 // can to avoid extracting signals.
3812 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
3814 // if this is a group child, unsnooze parent summary
3815 if (n.isGroup() && notification.isGroupChild()) {
3816 mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
3819 // This conditional is a dirty hack to limit the logging done on
3820 // behalf of the download manager without affecting other apps.
3821 if (!pkg.equals("com.android.providers.downloads")
3822 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
3823 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
3825 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
3827 EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
3828 pkg, id, tag, userId, notification.toString(),
3832 mRankingHelper.extractSignals(r);
3834 // tell the assistant service about the notification
3835 if (mAssistants.isEnabled()) {
3836 mAssistants.onNotificationEnqueued(r);
3837 mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
3838 DELAY_FOR_ASSISTANT_TIME);
3840 mHandler.post(new PostNotificationRunnable(r.getKey()));
3846 protected class PostNotificationRunnable implements Runnable {
3847 private final String key;
3849 PostNotificationRunnable(String key) {
3855 synchronized (mNotificationLock) {
3857 NotificationRecord r = null;
3858 int N = mEnqueuedNotifications.size();
3859 for (int i = 0; i < N; i++) {
3860 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
3861 if (Objects.equals(key, enqueued.getKey())) {
3867 Slog.i(TAG, "Cannot find enqueued record for key: " + key);
3870 NotificationRecord old = mNotificationsByKey.get(key);
3871 final StatusBarNotification n = r.sbn;
3872 final Notification notification = n.getNotification();
3873 int index = indexOfNotificationLocked(n.getKey());
3875 mNotificationList.add(r);
3876 mUsageStats.registerPostedByApp(r);
3878 old = mNotificationList.get(index);
3879 mNotificationList.set(index, r);
3880 mUsageStats.registerUpdatedByApp(r, old);
3881 // Make sure we don't lose the foreground service state.
3882 notification.flags |=
3883 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
3887 mNotificationsByKey.put(n.getKey(), r);
3889 // Ensure if this is a foreground service that the proper additional
3891 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
3892 notification.flags |= Notification.FLAG_ONGOING_EVENT
3893 | Notification.FLAG_NO_CLEAR;
3896 applyZenModeLocked(r);
3897 mRankingHelper.sort(mNotificationList);
3899 if (notification.getSmallIcon() != null) {
3900 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
3901 mListeners.notifyPostedLocked(n, oldSbn);
3902 if (oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())) {
3903 mHandler.post(new Runnable() {
3906 mGroupHelper.onNotificationPosted(
3907 n, hasAutoGroupSummaryLocked(n));
3912 Slog.e(TAG, "Not posting notification without small icon: " + notification);
3913 if (old != null && !old.isCanceled) {
3914 mListeners.notifyRemovedLocked(n,
3915 NotificationListenerService.REASON_ERROR);
3916 mHandler.post(new Runnable() {
3919 mGroupHelper.onNotificationRemoved(n);
3923 // ATTENTION: in a future release we will bail out here
3924 // so that we do not play sounds, show lights, etc. for invalid
3926 Slog.e(TAG, "WARNING: In a future release this will crash the app: "
3927 + n.getPackageName());
3930 buzzBeepBlinkLocked(r);
3932 int N = mEnqueuedNotifications.size();
3933 for (int i = 0; i < N; i++) {
3934 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
3935 if (Objects.equals(key, enqueued.getKey())) {
3936 mEnqueuedNotifications.remove(i);
3946 * Ensures that grouped notification receive their special treatment.
3948 * <p>Cancels group children if the new notification causes a group to lose
3951 * <p>Updates mSummaryByGroupKey.</p>
3953 @GuardedBy("mNotificationLock")
3954 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
3955 int callingUid, int callingPid) {
3956 StatusBarNotification sbn = r.sbn;
3957 Notification n = sbn.getNotification();
3958 if (n.isGroupSummary() && !sbn.isAppGroup()) {
3959 // notifications without a group shouldn't be a summary, otherwise autobundling can
3961 n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
3964 String group = sbn.getGroupKey();
3965 boolean isSummary = n.isGroupSummary();
3967 Notification oldN = old != null ? old.sbn.getNotification() : null;
3968 String oldGroup = old != null ? old.sbn.getGroupKey() : null;
3969 boolean oldIsSummary = old != null && oldN.isGroupSummary();
3972 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
3973 if (removedSummary != old) {
3975 removedSummary != null ? removedSummary.getKey() : "<null>";
3976 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
3977 ", removed=" + removedKey);
3981 mSummaryByGroupKey.put(group, r);
3984 // Clear out group children of the old notification if the update
3985 // causes the group summary to go away. This happens when the old
3986 // notification was a summary and the new one isn't, or when the old
3987 // notification was a summary and its group key changed.
3988 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
3989 cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */,
3995 @GuardedBy("mNotificationLock")
3996 void scheduleTimeoutLocked(NotificationRecord record) {
3997 if (record.getNotification().getTimeoutAfter() > 0) {
3998 final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
3999 REQUEST_CODE_TIMEOUT,
4000 new Intent(ACTION_NOTIFICATION_TIMEOUT)
4001 .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
4002 .appendPath(record.getKey()).build())
4003 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
4004 .putExtra(EXTRA_KEY, record.getKey()),
4005 PendingIntent.FLAG_UPDATE_CURRENT);
4006 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
4007 SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
4012 @GuardedBy("mNotificationLock")
4013 void buzzBeepBlinkLocked(NotificationRecord record) {
4014 boolean buzz = false;
4015 boolean beep = false;
4016 boolean blink = false;
4018 final Notification notification = record.sbn.getNotification();
4019 final String key = record.getKey();
4021 // Should this notification make noise, vibe, or use the LED?
4022 final boolean aboveThreshold =
4023 record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
4025 // Remember if this notification already owns the notification channels.
4026 boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
4027 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
4028 // These are set inside the conditional if the notification is allowed to make noise.
4029 boolean hasValidVibrate = false;
4030 boolean hasValidSound = false;
4031 boolean sentAccessibilityEvent = false;
4032 // If the notification will appear in the status bar, it should send an accessibility
4034 if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) {
4035 sendAccessibilityEvent(notification, record.sbn.getPackageName());
4036 sentAccessibilityEvent = true;
4039 if (aboveThreshold && isNotificationForCurrentUser(record)) {
4041 if (mSystemReady && mAudioManager != null) {
4042 Uri soundUri = record.getSound();
4043 hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
4044 long[] vibration = record.getVibration();
4045 // Demote sound to vibration if vibration missing & phone in vibration mode.
4046 if (vibration == null
4048 && (mAudioManager.getRingerModeInternal()
4049 == AudioManager.RINGER_MODE_VIBRATE)
4050 && mAudioManager.getStreamVolume(
4051 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) == 0) {
4052 vibration = mFallbackVibrationPattern;
4054 hasValidVibrate = vibration != null;
4056 boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
4057 if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
4058 if (!sentAccessibilityEvent) {
4059 sendAccessibilityEvent(notification, record.sbn.getPackageName());
4060 sentAccessibilityEvent = true;
4062 if (DBG) Slog.v(TAG, "Interrupting!");
4063 if (hasValidSound) {
4064 mSoundNotificationKey = key;
4066 playInCallNotification();
4069 beep = playSound(record, soundUri);
4073 final boolean ringerModeSilent =
4074 mAudioManager.getRingerModeInternal()
4075 == AudioManager.RINGER_MODE_SILENT;
4076 if (!mInCall && hasValidVibrate && !ringerModeSilent) {
4077 mVibrateNotificationKey = key;
4079 buzz = playVibration(record, vibration, hasValidSound);
4084 // If a notification is updated to remove the actively playing sound or vibrate,
4085 // cancel that feedback now
4086 if (wasBeep && !hasValidSound) {
4089 if (wasBuzz && !hasValidVibrate) {
4090 clearVibrateLocked();
4094 // release the light
4095 boolean wasShowLights = mLights.remove(key);
4096 if (record.getLight() != null && aboveThreshold
4097 && ((record.getSuppressedVisualEffects()
4098 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
4100 updateLightsLocked();
4101 if (mUseAttentionLight) {
4102 mAttentionLight.pulse();
4105 } else if (wasShowLights) {
4106 updateLightsLocked();
4108 if (buzz || beep || blink) {
4109 MetricsLogger.action(record.getLogMaker()
4110 .setCategory(MetricsEvent.NOTIFICATION_ALERT)
4111 .setType(MetricsEvent.TYPE_OPEN)
4112 .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
4113 EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
4117 @GuardedBy("mNotificationLock")
4118 boolean shouldMuteNotificationLocked(final NotificationRecord record) {
4119 // Suppressed because it's a silent update
4120 final Notification notification = record.getNotification();
4122 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
4126 // muted by listener
4127 final String disableEffects = disableNotificationEffects(record);
4128 if (disableEffects != null) {
4129 ZenLog.traceDisableEffects(record, disableEffects);
4133 // suppressed due to DND
4134 if (record.isIntercepted()) {
4138 // Suppressed because another notification in its group handles alerting
4139 if (record.sbn.isGroup()) {
4140 return notification.suppressAlertingDueToGrouping();
4143 // Suppressed for being too recently noisy
4144 final String pkg = record.sbn.getPackageName();
4145 if (mUsageStats.isAlertRateLimited(pkg)) {
4146 Slog.e(TAG, "Muting recently noisy " + record.getKey());
4153 private boolean playSound(final NotificationRecord record, Uri soundUri) {
4154 boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
4155 // do not play notifications if there is a user of exclusive audio focus
4156 // or the device is in vibrate mode
4157 if (!mAudioManager.isAudioFocusExclusive() && (mAudioManager.getRingerModeInternal()
4158 != AudioManager.RINGER_MODE_VIBRATE || mAudioManager.getStreamVolume(
4159 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) {
4160 final long identity = Binder.clearCallingIdentity();
4162 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4163 if (player != null) {
4164 if (DBG) Slog.v(TAG, "Playing sound " + soundUri
4165 + " with attributes " + record.getAudioAttributes());
4166 player.playAsync(soundUri, record.sbn.getUser(), looping,
4167 record.getAudioAttributes());
4170 } catch (RemoteException e) {
4172 Binder.restoreCallingIdentity(identity);
4178 private boolean playVibration(final NotificationRecord record, long[] vibration,
4179 boolean delayVibForSound) {
4180 // Escalate privileges so we can use the vibrator even if the
4181 // notifying app does not have the VIBRATE permission.
4182 long identity = Binder.clearCallingIdentity();
4184 final VibrationEffect effect;
4186 final boolean insistent =
4187 (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
4188 effect = VibrationEffect.createWaveform(
4189 vibration, insistent ? 0 : -1 /*repeatIndex*/);
4190 } catch (IllegalArgumentException e) {
4191 Slog.e(TAG, "Error creating vibration waveform with pattern: " +
4192 Arrays.toString(vibration));
4195 if (delayVibForSound) {
4197 // delay the vibration by the same amount as the notification sound
4198 final int waitMs = mAudioManager.getFocusRampTimeMs(
4199 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
4200 record.getAudioAttributes());
4201 if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms");
4203 Thread.sleep(waitMs);
4204 } catch (InterruptedException e) { }
4205 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
4206 effect, record.getAudioAttributes());
4209 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
4210 effect, record.getAudioAttributes());
4214 Binder.restoreCallingIdentity(identity);
4218 private boolean isNotificationForCurrentUser(NotificationRecord record) {
4219 final int currentUser;
4220 final long token = Binder.clearCallingIdentity();
4222 currentUser = ActivityManager.getCurrentUser();
4224 Binder.restoreCallingIdentity(token);
4226 return (record.getUserId() == UserHandle.USER_ALL ||
4227 record.getUserId() == currentUser ||
4228 mUserProfiles.isCurrentProfile(record.getUserId()));
4231 protected void playInCallNotification() {
4235 final long identity = Binder.clearCallingIdentity();
4237 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4238 if (player != null) {
4239 player.play(new Binder(), mInCallNotificationUri,
4240 mInCallNotificationAudioAttributes,
4241 mInCallNotificationVolume, false);
4243 } catch (RemoteException e) {
4245 Binder.restoreCallingIdentity(identity);
4251 @GuardedBy("mToastQueue")
4252 void showNextToastLocked() {
4253 ToastRecord record = mToastQueue.get(0);
4254 while (record != null) {
4255 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
4257 record.callback.show(record.token);
4258 scheduleTimeoutLocked(record);
4260 } catch (RemoteException e) {
4261 Slog.w(TAG, "Object died trying to show notification " + record.callback
4262 + " in package " + record.pkg);
4263 // remove it from the list and let the process die
4264 int index = mToastQueue.indexOf(record);
4266 mToastQueue.remove(index);
4268 keepProcessAliveIfNeededLocked(record.pid);
4269 if (mToastQueue.size() > 0) {
4270 record = mToastQueue.get(0);
4278 @GuardedBy("mToastQueue")
4279 void cancelToastLocked(int index) {
4280 ToastRecord record = mToastQueue.get(index);
4282 record.callback.hide();
4283 } catch (RemoteException e) {
4284 Slog.w(TAG, "Object died trying to hide notification " + record.callback
4285 + " in package " + record.pkg);
4286 // don't worry about this, we're about to remove it from
4290 ToastRecord lastToast = mToastQueue.remove(index);
4291 mWindowManagerInternal.removeWindowToken(lastToast.token, true, DEFAULT_DISPLAY);
4293 keepProcessAliveIfNeededLocked(record.pid);
4294 if (mToastQueue.size() > 0) {
4295 // Show the next one. If the callback fails, this will remove
4296 // it from the list, so don't assume that the list hasn't changed
4297 // after this point.
4298 showNextToastLocked();
4302 @GuardedBy("mToastQueue")
4303 private void scheduleTimeoutLocked(ToastRecord r)
4305 mHandler.removeCallbacksAndMessages(r);
4306 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
4307 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
4308 mHandler.sendMessageDelayed(m, delay);
4311 private void handleTimeout(ToastRecord record)
4313 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
4314 synchronized (mToastQueue) {
4315 int index = indexOfToastLocked(record.pkg, record.callback);
4317 cancelToastLocked(index);
4322 @GuardedBy("mToastQueue")
4323 int indexOfToastLocked(String pkg, ITransientNotification callback)
4325 IBinder cbak = callback.asBinder();
4326 ArrayList<ToastRecord> list = mToastQueue;
4327 int len = list.size();
4328 for (int i=0; i<len; i++) {
4329 ToastRecord r = list.get(i);
4330 if (r.pkg.equals(pkg) && r.callback.asBinder().equals(cbak)) {
4337 @GuardedBy("mToastQueue")
4338 int indexOfToastPackageLocked(String pkg)
4340 ArrayList<ToastRecord> list = mToastQueue;
4341 int len = list.size();
4342 for (int i=0; i<len; i++) {
4343 ToastRecord r = list.get(i);
4344 if (r.pkg.equals(pkg)) {
4351 @GuardedBy("mToastQueue")
4352 void keepProcessAliveIfNeededLocked(int pid)
4354 int toastCount = 0; // toasts from this pid
4355 ArrayList<ToastRecord> list = mToastQueue;
4356 int N = list.size();
4357 for (int i=0; i<N; i++) {
4358 ToastRecord r = list.get(i);
4364 mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
4365 } catch (RemoteException e) {
4366 // Shouldn't happen.
4370 private void handleRankingReconsideration(Message message) {
4371 if (!(message.obj instanceof RankingReconsideration)) return;
4372 RankingReconsideration recon = (RankingReconsideration) message.obj;
4375 synchronized (mNotificationLock) {
4376 final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
4377 if (record == null) {
4380 int indexBefore = findNotificationRecordIndexLocked(record);
4381 boolean interceptBefore = record.isIntercepted();
4382 float contactAffinityBefore = record.getContactAffinity();
4383 int visibilityBefore = record.getPackageVisibilityOverride();
4384 recon.applyChangesLocked(record);
4385 applyZenModeLocked(record);
4386 mRankingHelper.sort(mNotificationList);
4387 int indexAfter = findNotificationRecordIndexLocked(record);
4388 boolean interceptAfter = record.isIntercepted();
4389 float contactAffinityAfter = record.getContactAffinity();
4390 int visibilityAfter = record.getPackageVisibilityOverride();
4391 changed = indexBefore != indexAfter || interceptBefore != interceptAfter
4392 || visibilityBefore != visibilityAfter;
4393 if (interceptBefore && !interceptAfter
4394 && Float.compare(contactAffinityBefore, contactAffinityAfter) != 0) {
4395 buzzBeepBlinkLocked(record);
4399 mHandler.scheduleSendRankingUpdate();
4403 void handleRankingSort() {
4404 if (mRankingHelper == null) return;
4405 synchronized (mNotificationLock) {
4406 final int N = mNotificationList.size();
4407 // Any field that can change via one of the extractors needs to be added here.
4408 ArrayList<String> orderBefore = new ArrayList<>(N);
4409 int[] visibilities = new int[N];
4410 boolean[] showBadges = new boolean[N];
4411 ArrayList<NotificationChannel> channelBefore = new ArrayList<>(N);
4412 ArrayList<String> groupKeyBefore = new ArrayList<>(N);
4413 ArrayList<ArrayList<String>> overridePeopleBefore = new ArrayList<>(N);
4414 ArrayList<ArrayList<SnoozeCriterion>> snoozeCriteriaBefore = new ArrayList<>(N);
4415 for (int i = 0; i < N; i++) {
4416 final NotificationRecord r = mNotificationList.get(i);
4417 orderBefore.add(r.getKey());
4418 visibilities[i] = r.getPackageVisibilityOverride();
4419 showBadges[i] = r.canShowBadge();
4420 channelBefore.add(r.getChannel());
4421 groupKeyBefore.add(r.getGroupKey());
4422 overridePeopleBefore.add(r.getPeopleOverride());
4423 snoozeCriteriaBefore.add(r.getSnoozeCriteria());
4424 mRankingHelper.extractSignals(r);
4426 mRankingHelper.sort(mNotificationList);
4427 for (int i = 0; i < N; i++) {
4428 final NotificationRecord r = mNotificationList.get(i);
4429 if (!orderBefore.get(i).equals(r.getKey())
4430 || visibilities[i] != r.getPackageVisibilityOverride()
4431 || showBadges[i] != r.canShowBadge()
4432 || !Objects.equals(channelBefore.get(i), r.getChannel())
4433 || !Objects.equals(groupKeyBefore.get(i), r.getGroupKey())
4434 || !Objects.equals(overridePeopleBefore.get(i), r.getPeopleOverride())
4435 || !Objects.equals(snoozeCriteriaBefore.get(i), r.getSnoozeCriteria())) {
4436 mHandler.scheduleSendRankingUpdate();
4443 @GuardedBy("mNotificationLock")
4444 private void recordCallerLocked(NotificationRecord record) {
4445 if (mZenModeHelper.isCall(record)) {
4446 mZenModeHelper.recordCaller(record);
4450 // let zen mode evaluate this record
4451 @GuardedBy("mNotificationLock")
4452 private void applyZenModeLocked(NotificationRecord record) {
4453 record.setIntercepted(mZenModeHelper.shouldIntercept(record));
4454 if (record.isIntercepted()) {
4455 int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
4456 ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
4457 | (mZenModeHelper.shouldSuppressWhenScreenOn()
4458 ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
4459 record.setSuppressedVisualEffects(suppressed);
4461 record.setSuppressedVisualEffects(0);
4465 @GuardedBy("mNotificationLock")
4466 private int findNotificationRecordIndexLocked(NotificationRecord target) {
4467 return mRankingHelper.indexOf(mNotificationList, target);
4470 private void handleSendRankingUpdate() {
4471 synchronized (mNotificationLock) {
4472 mListeners.notifyRankingUpdateLocked();
4476 private void scheduleListenerHintsChanged(int state) {
4477 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
4478 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
4481 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
4482 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
4483 mHandler.obtainMessage(
4484 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
4485 listenerInterruptionFilter,
4489 private void handleListenerHintsChanged(int hints) {
4490 synchronized (mNotificationLock) {
4491 mListeners.notifyListenerHintsChangedLocked(hints);
4495 private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
4496 synchronized (mNotificationLock) {
4497 mListeners.notifyInterruptionFilterChanged(interruptionFilter);
4501 protected class WorkerHandler extends Handler
4503 public WorkerHandler(Looper looper) {
4508 public void handleMessage(Message msg)
4512 case MESSAGE_TIMEOUT:
4513 handleTimeout((ToastRecord)msg.obj);
4515 case MESSAGE_SAVE_POLICY_FILE:
4516 handleSavePolicyFile();
4518 case MESSAGE_SEND_RANKING_UPDATE:
4519 handleSendRankingUpdate();
4521 case MESSAGE_LISTENER_HINTS_CHANGED:
4522 handleListenerHintsChanged(msg.arg1);
4524 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
4525 handleListenerInterruptionFilterChanged(msg.arg1);
4530 protected void scheduleSendRankingUpdate() {
4531 if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
4532 Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE);
4539 private final class RankingHandlerWorker extends Handler implements RankingHandler
4541 public RankingHandlerWorker(Looper looper) {
4546 public void handleMessage(Message msg) {
4548 case MESSAGE_RECONSIDER_RANKING:
4549 handleRankingReconsideration(msg);
4551 case MESSAGE_RANKING_SORT:
4552 handleRankingSort();
4557 public void requestSort() {
4558 removeMessages(MESSAGE_RANKING_SORT);
4559 Message msg = Message.obtain();
4560 msg.what = MESSAGE_RANKING_SORT;
4564 public void requestReconsideration(RankingReconsideration recon) {
4565 Message m = Message.obtain(this,
4566 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
4567 long delay = recon.getDelay(TimeUnit.MILLISECONDS);
4568 sendMessageDelayed(m, delay);
4573 // ============================================================================
4574 static int clamp(int x, int low, int high) {
4575 return (x < low) ? low : ((x > high) ? high : x);
4578 void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
4579 if (!mAccessibilityManager.isEnabled()) {
4583 AccessibilityEvent event =
4584 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
4585 event.setPackageName(packageName);
4586 event.setClassName(Notification.class.getName());
4587 event.setParcelableData(notification);
4588 CharSequence tickerText = notification.tickerText;
4589 if (!TextUtils.isEmpty(tickerText)) {
4590 event.getText().add(tickerText);
4593 mAccessibilityManager.sendAccessibilityEvent(event);
4597 * Removes all NotificationsRecords with the same key as the given notification record
4598 * from both lists. Do not call this method while iterating over either list.
4600 @GuardedBy("mNotificationLock")
4601 private boolean removeFromNotificationListsLocked(NotificationRecord r) {
4602 // Remove from both lists, either list could have a separate Record for what is
4603 // effectively the same notification.
4604 boolean wasPosted = false;
4605 NotificationRecord recordInList = null;
4606 if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))
4608 mNotificationList.remove(recordInList);
4609 mNotificationsByKey.remove(recordInList.sbn.getKey());
4612 while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
4614 mEnqueuedNotifications.remove(recordInList);
4619 @GuardedBy("mNotificationLock")
4620 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
4621 boolean wasPosted, String listenerName) {
4622 final String canceledKey = r.getKey();
4625 recordCallerLocked(r);
4629 if (r.getNotification().deleteIntent != null) {
4631 r.getNotification().deleteIntent.send();
4632 } catch (PendingIntent.CanceledException ex) {
4633 // do nothing - there's no relevant way to recover, and
4634 // no reason to let this propagate
4635 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
4640 // Only cancel these if this notification actually got to be posted.
4643 if (r.getNotification().getSmallIcon() != null) {
4644 if (reason != REASON_SNOOZED) {
4645 r.isCanceled = true;
4647 mListeners.notifyRemovedLocked(r.sbn, reason);
4648 mHandler.post(new Runnable() {
4651 mGroupHelper.onNotificationRemoved(r.sbn);
4657 if (canceledKey.equals(mSoundNotificationKey)) {
4658 mSoundNotificationKey = null;
4659 final long identity = Binder.clearCallingIdentity();
4661 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4662 if (player != null) {
4665 } catch (RemoteException e) {
4667 Binder.restoreCallingIdentity(identity);
4672 if (canceledKey.equals(mVibrateNotificationKey)) {
4673 mVibrateNotificationKey = null;
4674 long identity = Binder.clearCallingIdentity();
4679 Binder.restoreCallingIdentity(identity);
4684 mLights.remove(canceledKey);
4687 // Record usage stats
4688 // TODO: add unbundling stats?
4691 case REASON_CANCEL_ALL:
4692 case REASON_LISTENER_CANCEL:
4693 case REASON_LISTENER_CANCEL_ALL:
4694 mUsageStats.registerDismissedByUser(r);
4696 case REASON_APP_CANCEL:
4697 case REASON_APP_CANCEL_ALL:
4698 mUsageStats.registerRemovedByApp(r);
4702 String groupKey = r.getGroupKey();
4703 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
4704 if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
4705 mSummaryByGroupKey.remove(groupKey);
4707 final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
4708 if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
4709 summaries.remove(r.sbn.getPackageName());
4712 // Save it for users of getHistoricalNotifications()
4713 mArchive.record(r.sbn);
4715 final long now = System.currentTimeMillis();
4716 MetricsLogger.action(r.getLogMaker(now)
4717 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
4718 .setType(MetricsEvent.TYPE_DISMISS)
4719 .setSubtype(reason));
4720 EventLogTags.writeNotificationCanceled(canceledKey, reason,
4721 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), listenerName);
4725 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
4726 * and none of the {@code mustNotHaveFlags}.
4728 void cancelNotification(final int callingUid, final int callingPid,
4729 final String pkg, final String tag, final int id,
4730 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
4731 final int userId, final int reason, final ManagedServiceInfo listener) {
4732 // In enqueueNotificationInternal notifications are added by scheduling the
4733 // work on the worker handler. Hence, we also schedule the cancel on this
4734 // handler to avoid a scenario where an add notification call followed by a
4735 // remove notification call ends up in not removing the notification.
4736 mHandler.post(new Runnable() {
4739 String listenerName = listener == null ? null : listener.component.toShortString();
4740 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
4741 userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
4743 synchronized (mNotificationLock) {
4744 // Look for the notification, searching both the posted and enqueued lists.
4745 NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
4747 // The notification was found, check if it should be removed.
4749 // Ideally we'd do this in the caller of this method. However, that would
4750 // require the caller to also find the notification.
4751 if (reason == REASON_CLICK) {
4752 mUsageStats.registerClickedByUser(r);
4755 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
4758 if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
4762 // Cancel the notification.
4763 boolean wasPosted = removeFromNotificationListsLocked(r);
4764 cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
4765 cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
4767 updateLightsLocked();
4769 // No notification was found, assume that it is snoozed and cancel it.
4770 if (reason != REASON_SNOOZED) {
4771 final boolean wasSnoozed = mSnoozeHelper.cancel(userId, pkg, tag, id);
4783 * Determine whether the userId applies to the notification in question, either because
4784 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
4786 private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
4788 // looking for USER_ALL notifications? match everything
4789 userId == UserHandle.USER_ALL
4790 // a notification sent to USER_ALL matches any query
4791 || r.getUserId() == UserHandle.USER_ALL
4792 // an exact user match
4793 || r.getUserId() == userId;
4797 * Determine whether the userId applies to the notification in question, either because
4798 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
4799 * because it matches one of the users profiles.
4801 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
4802 return notificationMatchesUserId(r, userId)
4803 || mUserProfiles.isCurrentProfile(r.getUserId());
4807 * Cancels all notifications from a given package that have all of the
4808 * {@code mustHaveFlags}.
4810 void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
4811 int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
4812 ManagedServiceInfo listener) {
4813 mHandler.post(new Runnable() {
4816 String listenerName = listener == null ? null : listener.component.toShortString();
4817 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
4818 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
4821 // Why does this parameter exist? Do we actually want to execute the above if doit
4827 synchronized (mNotificationLock) {
4828 FlagChecker flagChecker = (int flags) -> {
4829 if ((flags & mustHaveFlags) != mustHaveFlags) {
4832 if ((flags & mustNotHaveFlags) != 0) {
4837 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
4838 pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
4839 false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
4840 listenerName, true /* wasPosted */);
4841 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
4842 callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
4843 flagChecker, false /*includeCurrentProfiles*/, userId,
4844 false /*sendDelete*/, reason, listenerName, false /* wasPosted */);
4845 mSnoozeHelper.cancel(userId, pkg);
4851 private interface FlagChecker {
4852 // Returns false if these flags do not pass the defined flag test.
4853 public boolean apply(int flags);
4856 @GuardedBy("mNotificationLock")
4857 private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
4858 int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
4859 String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
4860 boolean sendDelete, int reason, String listenerName, boolean wasPosted) {
4861 ArrayList<NotificationRecord> canceledNotifications = null;
4862 for (int i = notificationList.size() - 1; i >= 0; --i) {
4863 NotificationRecord r = notificationList.get(i);
4864 if (includeCurrentProfiles) {
4865 if (!notificationMatchesCurrentProfiles(r, userId)) {
4868 } else if (!notificationMatchesUserId(r, userId)) {
4871 // Don't remove notifications to all, if there's no package name specified
4872 if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
4875 if (!flagChecker.apply(r.getFlags())) {
4878 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
4881 if (channelId != null && !channelId.equals(r.getChannel().getId())) {
4884 if (canceledNotifications == null) {
4885 canceledNotifications = new ArrayList<>();
4887 notificationList.remove(i);
4888 mNotificationsByKey.remove(r.getKey());
4889 canceledNotifications.add(r);
4890 cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
4892 if (canceledNotifications != null) {
4893 final int M = canceledNotifications.size();
4894 for (int i = 0; i < M; i++) {
4895 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
4896 listenerName, false /* sendDelete */, flagChecker);
4898 updateLightsLocked();
4902 void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
4903 ManagedServiceInfo listener) {
4904 String listenerName = listener == null ? null : listener.component.toShortString();
4905 if (duration <= 0 && snoozeCriterionId == null || key == null) {
4910 Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
4911 snoozeCriterionId, listenerName));
4913 // Needs to post so that it can cancel notifications not yet enqueued.
4914 mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
4917 void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
4918 String listenerName = listener == null ? null : listener.component.toShortString();
4920 Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
4922 mSnoozeHelper.repost(key);
4926 @GuardedBy("mNotificationLock")
4927 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
4928 ManagedServiceInfo listener, boolean includeCurrentProfiles) {
4929 mHandler.post(new Runnable() {
4932 synchronized (mNotificationLock) {
4933 String listenerName =
4934 listener == null ? null : listener.component.toShortString();
4935 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
4936 null, userId, 0, 0, reason, listenerName);
4938 FlagChecker flagChecker = (int flags) -> {
4939 if ((flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR))
4946 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
4947 null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
4948 includeCurrentProfiles, userId, true /*sendDelete*/, reason,
4949 listenerName, true);
4950 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
4951 callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
4952 flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
4953 reason, listenerName, false);
4954 mSnoozeHelper.cancel(userId, includeCurrentProfiles);
4960 // Warning: The caller is responsible for invoking updateLightsLocked().
4961 @GuardedBy("mNotificationLock")
4962 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
4963 String listenerName, boolean sendDelete, FlagChecker flagChecker) {
4964 Notification n = r.getNotification();
4965 if (!n.isGroupSummary()) {
4969 String pkg = r.sbn.getPackageName();
4972 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
4976 cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
4977 sendDelete, true, flagChecker);
4978 cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
4979 listenerName, sendDelete, false, flagChecker);
4982 @GuardedBy("mNotificationLock")
4983 private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
4984 NotificationRecord parentNotification, int callingUid, int callingPid,
4985 String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker) {
4986 final String pkg = parentNotification.sbn.getPackageName();
4987 final int userId = parentNotification.getUserId();
4988 final int reason = REASON_GROUP_SUMMARY_CANCELED;
4989 for (int i = notificationList.size() - 1; i >= 0; i--) {
4990 final NotificationRecord childR = notificationList.get(i);
4991 final StatusBarNotification childSbn = childR.sbn;
4992 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
4993 childR.getGroupKey().equals(parentNotification.getGroupKey())
4994 && (childR.getFlags() & Notification.FLAG_FOREGROUND_SERVICE) == 0
4995 && (flagChecker == null || flagChecker.apply(childR.getFlags()))) {
4996 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
4997 childSbn.getTag(), userId, 0, 0, reason, listenerName);
4998 notificationList.remove(i);
4999 mNotificationsByKey.remove(childR.getKey());
5000 cancelNotificationLocked(childR, sendDelete, reason, wasPosted, listenerName);
5005 @GuardedBy("mNotificationLock")
5006 void updateLightsLocked()
5008 // handle notification lights
5009 NotificationRecord ledNotification = null;
5010 while (ledNotification == null && !mLights.isEmpty()) {
5011 final String owner = mLights.get(mLights.size() - 1);
5012 ledNotification = mNotificationsByKey.get(owner);
5013 if (ledNotification == null) {
5014 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
5015 mLights.remove(owner);
5019 // Don't flash while we are in a call or screen is on
5020 if (ledNotification == null || mInCall || mScreenOn) {
5021 mNotificationLight.turnOff();
5023 NotificationRecord.Light light = ledNotification.getLight();
5024 if (light != null && mNotificationPulseEnabled) {
5026 mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
5027 light.onMs, light.offMs);
5032 @GuardedBy("mNotificationLock")
5033 @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
5034 String groupKey, int userId) {
5035 List<NotificationRecord> records = new ArrayList<>();
5036 records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
5038 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
5043 @GuardedBy("mNotificationLock")
5044 private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
5045 ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
5046 List<NotificationRecord> records = new ArrayList<>();
5047 final int len = list.size();
5048 for (int i = 0; i < len; i++) {
5049 NotificationRecord r = list.get(i);
5050 if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey)
5051 && r.sbn.getPackageName().equals(pkg)) {
5058 // Searches both enqueued and posted notifications by key.
5059 // TODO: need to combine a bunch of these getters with slightly different behavior.
5060 // TODO: Should enqueuing just add to mNotificationsByKey instead?
5061 @GuardedBy("mNotificationLock")
5062 private NotificationRecord findNotificationByKeyLocked(String key) {
5063 NotificationRecord r;
5064 if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
5067 if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
5073 @GuardedBy("mNotificationLock")
5074 NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
5075 NotificationRecord r;
5076 if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
5079 if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
5086 @GuardedBy("mNotificationLock")
5087 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
5088 String pkg, String tag, int id, int userId) {
5089 final int len = list.size();
5090 for (int i = 0; i < len; i++) {
5091 NotificationRecord r = list.get(i);
5092 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
5093 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
5100 @GuardedBy("mNotificationLock")
5101 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
5103 final int N = list.size();
5104 for (int i = 0; i < N; i++) {
5105 if (key.equals(list.get(i).getKey())) {
5112 @GuardedBy("mNotificationLock")
5113 int indexOfNotificationLocked(String key) {
5114 final int N = mNotificationList.size();
5115 for (int i = 0; i < N; i++) {
5116 if (key.equals(mNotificationList.get(i).getKey())) {
5123 private void updateNotificationPulse() {
5124 synchronized (mNotificationLock) {
5125 updateLightsLocked();
5129 protected boolean isCallingUidSystem() {
5130 final int uid = Binder.getCallingUid();
5131 return uid == Process.SYSTEM_UID;
5134 protected boolean isUidSystemOrPhone(int uid) {
5135 final int appid = UserHandle.getAppId(uid);
5136 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
5139 // TODO: Most calls should probably move to isCallerSystem.
5140 protected boolean isCallerSystemOrPhone() {
5141 return isUidSystemOrPhone(Binder.getCallingUid());
5144 private void checkCallerIsSystemOrShell() {
5145 if (Binder.getCallingUid() == Process.SHELL_UID) {
5148 checkCallerIsSystem();
5151 private void checkCallerIsSystem() {
5152 if (isCallerSystemOrPhone()) {
5155 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
5158 private void checkCallerIsSystemOrSameApp(String pkg) {
5159 if (isCallerSystemOrPhone()) {
5162 checkCallerIsSameApp(pkg);
5165 private boolean isCallerInstantApp(String pkg) {
5166 // System is always allowed to act for ephemeral apps.
5167 if (isCallerSystemOrPhone()) {
5171 mAppOps.checkPackage(Binder.getCallingUid(), pkg);
5174 ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0,
5175 UserHandle.getCallingUserId());
5177 throw new SecurityException("Unknown package " + pkg);
5179 return ai.isInstantApp();
5180 } catch (RemoteException re) {
5181 throw new SecurityException("Unknown package " + pkg, re);
5186 private void checkCallerIsSameApp(String pkg) {
5187 final int uid = Binder.getCallingUid();
5189 ApplicationInfo ai = mPackageManager.getApplicationInfo(
5190 pkg, 0, UserHandle.getCallingUserId());
5192 throw new SecurityException("Unknown package " + pkg);
5194 if (!UserHandle.isSameApp(ai.uid, uid)) {
5195 throw new SecurityException("Calling uid " + uid + " gave package "
5196 + pkg + " which is owned by uid " + ai.uid);
5198 } catch (RemoteException re) {
5199 throw new SecurityException("Unknown package " + pkg + "\n" + re);
5203 private static String callStateToString(int state) {
5205 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
5206 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
5207 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
5208 default: return "CALL_STATE_UNKNOWN_" + state;
5212 private void listenForCallState() {
5213 TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
5215 public void onCallStateChanged(int state, String incomingNumber) {
5216 if (mCallState == state) return;
5217 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
5220 }, PhoneStateListener.LISTEN_CALL_STATE);
5224 * Generates a NotificationRankingUpdate from 'sbns', considering only
5225 * notifications visible to the given listener.
5227 @GuardedBy("mNotificationLock")
5228 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
5229 final int N = mNotificationList.size();
5230 ArrayList<String> keys = new ArrayList<String>(N);
5231 ArrayList<String> interceptedKeys = new ArrayList<String>(N);
5232 ArrayList<Integer> importance = new ArrayList<>(N);
5233 Bundle overrideGroupKeys = new Bundle();
5234 Bundle visibilityOverrides = new Bundle();
5235 Bundle suppressedVisualEffects = new Bundle();
5236 Bundle explanation = new Bundle();
5237 Bundle channels = new Bundle();
5238 Bundle overridePeople = new Bundle();
5239 Bundle snoozeCriteria = new Bundle();
5240 Bundle showBadge = new Bundle();
5241 for (int i = 0; i < N; i++) {
5242 NotificationRecord record = mNotificationList.get(i);
5243 if (!isVisibleToListener(record.sbn, info)) {
5246 final String key = record.sbn.getKey();
5248 importance.add(record.getImportance());
5249 if (record.getImportanceExplanation() != null) {
5250 explanation.putCharSequence(key, record.getImportanceExplanation());
5252 if (record.isIntercepted()) {
5253 interceptedKeys.add(key);
5256 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
5257 if (record.getPackageVisibilityOverride()
5258 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
5259 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
5261 overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
5262 channels.putParcelable(key, record.getChannel());
5263 overridePeople.putStringArrayList(key, record.getPeopleOverride());
5264 snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria());
5265 showBadge.putBoolean(key, record.canShowBadge());
5267 final int M = keys.size();
5268 String[] keysAr = keys.toArray(new String[M]);
5269 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
5270 int[] importanceAr = new int[M];
5271 for (int i = 0; i < M; i++) {
5272 importanceAr[i] = importance.get(i);
5274 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
5275 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
5276 channels, overridePeople, snoozeCriteria, showBadge);
5279 boolean hasCompanionDevice(ManagedServiceInfo info) {
5280 if (mCompanionManager == null) {
5281 mCompanionManager = getCompanionManager();
5283 // Companion mgr doesn't exist on all device types
5284 if (mCompanionManager == null) {
5287 long identity = Binder.clearCallingIdentity();
5289 List<String> associations = mCompanionManager.getAssociations(
5290 info.component.getPackageName(), info.userid);
5291 if (!ArrayUtils.isEmpty(associations)) {
5294 } catch (SecurityException se) {
5295 // Not a privileged listener
5296 } catch (RemoteException re) {
5297 Slog.e(TAG, "Cannot reach companion device service", re);
5298 } catch (Exception e) {
5299 Slog.e(TAG, "Cannot verify listener " + info, e);
5301 Binder.restoreCallingIdentity(identity);
5306 protected ICompanionDeviceManager getCompanionManager() {
5307 return ICompanionDeviceManager.Stub.asInterface(
5308 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
5311 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
5312 if (!listener.enabledAndUserMatches(sbn.getUserId())) {
5315 // TODO: remove this for older listeners.
5319 private boolean isPackageSuspendedForUser(String pkg, int uid) {
5320 int userId = UserHandle.getUserId(uid);
5322 return mPackageManager.isPackageSuspendedForUser(pkg, userId);
5323 } catch (RemoteException re) {
5324 throw new SecurityException("Could not talk to package manager service");
5325 } catch (IllegalArgumentException ex) {
5326 // Package not found.
5331 private class TrimCache {
5332 StatusBarNotification heavy;
5333 StatusBarNotification sbnClone;
5334 StatusBarNotification sbnCloneLight;
5336 TrimCache(StatusBarNotification sbn) {
5340 StatusBarNotification ForListener(ManagedServiceInfo info) {
5341 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
5342 if (sbnCloneLight == null) {
5343 sbnCloneLight = heavy.cloneLight();
5345 return sbnCloneLight;
5347 if (sbnClone == null) {
5348 sbnClone = heavy.clone();
5355 public class NotificationAssistants extends ManagedServices {
5356 static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
5358 public NotificationAssistants(IPackageManager pm) {
5359 super(getContext(), mNotificationLock, mUserProfiles, pm);
5363 protected Config getConfig() {
5364 Config c = new Config();
5365 c.caption = "notification assistant service";
5366 c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
5367 c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS;
5368 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
5369 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
5370 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
5371 c.clientLabel = R.string.notification_ranker_binding_label;
5376 protected IInterface asInterface(IBinder binder) {
5377 return INotificationListener.Stub.asInterface(binder);
5381 protected boolean checkType(IInterface service) {
5382 return service instanceof INotificationListener;
5386 protected void onServiceAdded(ManagedServiceInfo info) {
5387 mListeners.registerGuestService(info);
5391 @GuardedBy("mNotificationLock")
5392 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
5393 mListeners.unregisterService(removed.service, removed.userid);
5396 public void onNotificationEnqueued(final NotificationRecord r) {
5397 final StatusBarNotification sbn = r.sbn;
5398 TrimCache trimCache = new TrimCache(sbn);
5400 // There should be only one, but it's a list, so while we enforce
5401 // singularity elsewhere, we keep it general here, to avoid surprises.
5402 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
5403 boolean sbnVisible = isVisibleToListener(sbn, info);
5408 final int importance = r.getImportance();
5409 final boolean fromUser = r.isImportanceFromUser();
5410 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
5411 mHandler.post(new Runnable() {
5414 notifyEnqueued(info, sbnToPost);
5420 private void notifyEnqueued(final ManagedServiceInfo info,
5421 final StatusBarNotification sbn) {
5422 final INotificationListener assistant = (INotificationListener) info.service;
5423 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5425 assistant.onNotificationEnqueued(sbnHolder);
5426 } catch (RemoteException ex) {
5427 Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
5432 * asynchronously notify the assistant that a notification has been snoozed until a
5435 @GuardedBy("mNotificationLock")
5436 public void notifyAssistantSnoozedLocked(final StatusBarNotification sbn,
5437 final String snoozeCriterionId) {
5438 TrimCache trimCache = new TrimCache(sbn);
5439 for (final ManagedServiceInfo info : getServices()) {
5440 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
5441 mHandler.post(new Runnable() {
5444 final INotificationListener assistant =
5445 (INotificationListener) info.service;
5446 StatusBarNotificationHolder sbnHolder
5447 = new StatusBarNotificationHolder(sbnToPost);
5449 assistant.onNotificationSnoozedUntilContext(
5450 sbnHolder, snoozeCriterionId);
5451 } catch (RemoteException ex) {
5452 Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
5459 public boolean isEnabled() {
5460 return !getServices().isEmpty();
5464 public class NotificationListeners extends ManagedServices {
5465 static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners";
5467 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
5469 public NotificationListeners(IPackageManager pm) {
5470 super(getContext(), mNotificationLock, mUserProfiles, pm);
5475 protected Config getConfig() {
5476 Config c = new Config();
5477 c.caption = "notification listener";
5478 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
5479 c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS;
5480 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
5481 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
5482 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
5483 c.clientLabel = R.string.notification_listener_binding_label;
5488 protected IInterface asInterface(IBinder binder) {
5489 return INotificationListener.Stub.asInterface(binder);
5493 protected boolean checkType(IInterface service) {
5494 return service instanceof INotificationListener;
5498 public void onServiceAdded(ManagedServiceInfo info) {
5499 final INotificationListener listener = (INotificationListener) info.service;
5500 final NotificationRankingUpdate update;
5501 synchronized (mNotificationLock) {
5502 update = makeRankingUpdateLocked(info);
5505 listener.onListenerConnected(update);
5506 } catch (RemoteException e) {
5512 @GuardedBy("mNotificationLock")
5513 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
5514 if (removeDisabledHints(removed)) {
5515 updateListenerHintsLocked();
5516 updateEffectsSuppressorLocked();
5518 mLightTrimListeners.remove(removed);
5521 @GuardedBy("mNotificationLock")
5522 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
5523 if (trim == TRIM_LIGHT) {
5524 mLightTrimListeners.add(info);
5526 mLightTrimListeners.remove(info);
5530 public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
5531 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
5535 * asynchronously notify all listeners about a new notification
5538 * Also takes care of removing a notification that has been visible to a listener before,
5539 * but isn't anymore.
5541 @GuardedBy("mNotificationLock")
5542 public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
5543 // Lazily initialized snapshots of the notification.
5544 TrimCache trimCache = new TrimCache(sbn);
5546 for (final ManagedServiceInfo info : getServices()) {
5547 boolean sbnVisible = isVisibleToListener(sbn, info);
5548 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
5549 // This notification hasn't been and still isn't visible -> ignore.
5550 if (!oldSbnVisible && !sbnVisible) {
5553 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
5555 // This notification became invisible -> remove the old one.
5556 if (oldSbnVisible && !sbnVisible) {
5557 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
5558 mHandler.post(new Runnable() {
5561 notifyRemoved(info, oldSbnLightClone, update, REASON_USER_STOPPED);
5567 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
5568 mHandler.post(new Runnable() {
5571 notifyPosted(info, sbnToPost, update);
5578 * asynchronously notify all listeners about a removed notification
5580 @GuardedBy("mNotificationLock")
5581 public void notifyRemovedLocked(StatusBarNotification sbn, int reason) {
5582 // make a copy in case changes are made to the underlying Notification object
5583 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
5585 final StatusBarNotification sbnLight = sbn.cloneLight();
5586 for (final ManagedServiceInfo info : getServices()) {
5587 if (!isVisibleToListener(sbn, info)) {
5590 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
5591 mHandler.post(new Runnable() {
5594 notifyRemoved(info, sbnLight, update, reason);
5601 * asynchronously notify all listeners about a reordering of notifications
5603 @GuardedBy("mNotificationLock")
5604 public void notifyRankingUpdateLocked() {
5605 for (final ManagedServiceInfo serviceInfo : getServices()) {
5606 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5609 final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
5610 mHandler.post(new Runnable() {
5613 notifyRankingUpdate(serviceInfo, update);
5619 @GuardedBy("mNotificationLock")
5620 public void notifyListenerHintsChangedLocked(final int hints) {
5621 for (final ManagedServiceInfo serviceInfo : getServices()) {
5622 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5625 mHandler.post(new Runnable() {
5628 notifyListenerHintsChanged(serviceInfo, hints);
5634 public void notifyInterruptionFilterChanged(final int interruptionFilter) {
5635 for (final ManagedServiceInfo serviceInfo : getServices()) {
5636 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5639 mHandler.post(new Runnable() {
5642 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
5648 protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user,
5649 final NotificationChannel channel, final int modificationType) {
5650 if (channel == null) {
5653 for (final ManagedServiceInfo serviceInfo : getServices()) {
5654 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
5658 BackgroundThread.getHandler().post(() -> {
5659 if (hasCompanionDevice(serviceInfo)) {
5660 notifyNotificationChannelChanged(
5661 serviceInfo, pkg, user, channel, modificationType);
5667 protected void notifyNotificationChannelGroupChanged(
5668 final String pkg, final UserHandle user, final NotificationChannelGroup group,
5669 final int modificationType) {
5670 if (group == null) {
5673 for (final ManagedServiceInfo serviceInfo : getServices()) {
5674 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
5678 BackgroundThread.getHandler().post(() -> {
5679 if (hasCompanionDevice(serviceInfo)) {
5680 notifyNotificationChannelGroupChanged(
5681 serviceInfo, pkg, user, group, modificationType);
5687 private void notifyPosted(final ManagedServiceInfo info,
5688 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
5689 final INotificationListener listener = (INotificationListener) info.service;
5690 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5692 listener.onNotificationPosted(sbnHolder, rankingUpdate);
5693 } catch (RemoteException ex) {
5694 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
5698 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
5699 NotificationRankingUpdate rankingUpdate, int reason) {
5700 if (!info.enabledAndUserMatches(sbn.getUserId())) {
5703 final INotificationListener listener = (INotificationListener) info.service;
5704 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5706 listener.onNotificationRemoved(sbnHolder, rankingUpdate, reason);
5707 } catch (RemoteException ex) {
5708 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
5712 private void notifyRankingUpdate(ManagedServiceInfo info,
5713 NotificationRankingUpdate rankingUpdate) {
5714 final INotificationListener listener = (INotificationListener) info.service;
5716 listener.onNotificationRankingUpdate(rankingUpdate);
5717 } catch (RemoteException ex) {
5718 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
5722 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
5723 final INotificationListener listener = (INotificationListener) info.service;
5725 listener.onListenerHintsChanged(hints);
5726 } catch (RemoteException ex) {
5727 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
5731 private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
5732 int interruptionFilter) {
5733 final INotificationListener listener = (INotificationListener) info.service;
5735 listener.onInterruptionFilterChanged(interruptionFilter);
5736 } catch (RemoteException ex) {
5737 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
5741 void notifyNotificationChannelChanged(ManagedServiceInfo info,
5742 final String pkg, final UserHandle user, final NotificationChannel channel,
5743 final int modificationType) {
5744 final INotificationListener listener = (INotificationListener) info.service;
5746 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
5747 } catch (RemoteException ex) {
5748 Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
5752 private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
5753 final String pkg, final UserHandle user, final NotificationChannelGroup group,
5754 final int modificationType) {
5755 final INotificationListener listener = (INotificationListener) info.service;
5757 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
5758 } catch (RemoteException ex) {
5759 Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
5763 public boolean isListenerPackage(String packageName) {
5764 if (packageName == null) {
5767 // TODO: clean up locking object later
5768 synchronized (mNotificationLock) {
5769 for (final ManagedServiceInfo serviceInfo : getServices()) {
5770 if (packageName.equals(serviceInfo.component.getPackageName())) {
5779 public static final class DumpFilter {
5780 public boolean filtered = false;
5781 public String pkgFilter;
5784 public boolean stats;
5785 public boolean redact = true;
5786 public boolean proto = false;
5788 public static DumpFilter parseFromArguments(String[] args) {
5789 final DumpFilter filter = new DumpFilter();
5790 for (int ai = 0; ai < args.length; ai++) {
5791 final String a = args[ai];
5792 if ("--proto".equals(args[0])) {
5793 filter.proto = true;
5795 if ("--noredact".equals(a) || "--reveal".equals(a)) {
5796 filter.redact = false;
5797 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
5798 if (ai < args.length-1) {
5800 filter.pkgFilter = args[ai].trim().toLowerCase();
5801 if (filter.pkgFilter.isEmpty()) {
5802 filter.pkgFilter = null;
5804 filter.filtered = true;
5807 } else if ("--zen".equals(a) || "zen".equals(a)) {
5808 filter.filtered = true;
5810 } else if ("--stats".equals(a)) {
5811 filter.stats = true;
5812 if (ai < args.length-1) {
5814 filter.since = Long.parseLong(args[ai]);
5823 public boolean matches(StatusBarNotification sbn) {
5824 if (!filtered) return true;
5825 return zen ? true : sbn != null
5826 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
5829 public boolean matches(ComponentName component) {
5830 if (!filtered) return true;
5831 return zen ? true : component != null && matches(component.getPackageName());
5834 public boolean matches(String pkg) {
5835 if (!filtered) return true;
5836 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
5840 public String toString() {
5841 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
5846 * Wrapper for a StatusBarNotification object that allows transfer across a oneway
5847 * binder without sending large amounts of data over a oneway transaction.
5849 private static final class StatusBarNotificationHolder
5850 extends IStatusBarNotificationHolder.Stub {
5851 private StatusBarNotification mValue;
5853 public StatusBarNotificationHolder(StatusBarNotification value) {
5857 /** Get the held value and clear it. This function should only be called once per holder */
5859 public StatusBarNotification get() {
5860 StatusBarNotification value = mValue;
5866 private class ShellCmd extends ShellCommand {
5867 public static final String USAGE = "help\n"
5868 + "allow_listener COMPONENT [user_id]\n"
5869 + "disallow_listener COMPONENT [user_id]\n"
5870 + "set_assistant COMPONENT\n"
5871 + "remove_assistant COMPONENT\n"
5872 + "allow_dnd PACKAGE\n"
5873 + "disallow_dnd PACKAGE";
5876 public int onCommand(String cmd) {
5878 return handleDefaultCommands(cmd);
5880 final PrintWriter pw = getOutPrintWriter();
5884 getBinderService().setNotificationPolicyAccessGranted(
5885 getNextArgRequired(), true);
5889 case "disallow_dnd": {
5890 getBinderService().setNotificationPolicyAccessGranted(
5891 getNextArgRequired(), false);
5894 case "allow_listener": {
5895 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
5897 pw.println("Invalid listener - must be a ComponentName");
5900 String userId = getNextArg();
5901 if (userId == null) {
5902 getBinderService().setNotificationListenerAccessGranted(cn, true);
5904 getBinderService().setNotificationListenerAccessGrantedForUser(
5905 cn, Integer.parseInt(userId), true);
5909 case "disallow_listener": {
5910 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
5912 pw.println("Invalid listener - must be a ComponentName");
5915 String userId = getNextArg();
5916 if (userId == null) {
5917 getBinderService().setNotificationListenerAccessGranted(cn, false);
5919 getBinderService().setNotificationListenerAccessGrantedForUser(
5920 cn, Integer.parseInt(userId), false);
5924 case "allow_assistant": {
5925 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
5927 pw.println("Invalid assistant - must be a ComponentName");
5930 getBinderService().setNotificationAssistantAccessGranted(cn, true);
5933 case "disallow_assistant": {
5934 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
5936 pw.println("Invalid assistant - must be a ComponentName");
5939 getBinderService().setNotificationAssistantAccessGranted(cn, false);
5944 return handleDefaultCommands(cmd);
5946 } catch (Exception e) {
5947 pw.println("Error occurred. Check logcat for details. " + e.getMessage());
5948 Slog.e(TAG, "Error running shell command", e);
5954 public void onHelp() {
5955 getOutPrintWriter().println(USAGE);