2 * Copyright (C) 2007 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.server.notification;
19 import static android.app.NotificationManager.IMPORTANCE_MIN;
20 import static android.app.NotificationManager.IMPORTANCE_NONE;
21 import static android.content.pm.PackageManager.FEATURE_LEANBACK;
22 import static android.content.pm.PackageManager.FEATURE_TELEVISION;
23 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
24 import static android.service.notification.NotificationListenerService
25 .NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
26 import static android.service.notification.NotificationListenerService
27 .NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
28 import static android.service.notification.NotificationListenerService
29 .NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
30 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
31 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
32 import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
33 import static android.service.notification.NotificationListenerService.REASON_CANCEL;
34 import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
35 import static android.service.notification.NotificationListenerService.REASON_CLICK;
36 import static android.service.notification.NotificationListenerService.REASON_ERROR;
37 import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
38 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL;
39 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL;
40 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED;
41 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED;
42 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED;
43 import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF;
44 import static android.service.notification.NotificationListenerService.REASON_SNOOZED;
45 import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
46 import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
47 import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
48 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
49 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
50 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
51 import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
52 import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
53 import static android.service.notification.NotificationListenerService.TRIM_FULL;
54 import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
56 import static android.view.Display.DEFAULT_DISPLAY;
57 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
58 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
60 import android.Manifest;
61 import android.annotation.NonNull;
62 import android.annotation.Nullable;
63 import android.app.ActivityManager;
64 import android.app.ActivityManagerInternal;
65 import android.app.AlarmManager;
66 import android.app.AppGlobals;
67 import android.app.AppOpsManager;
68 import android.app.AutomaticZenRule;
69 import android.app.NotificationChannelGroup;
70 import android.app.backup.BackupManager;
71 import android.app.IActivityManager;
72 import android.app.INotificationManager;
73 import android.app.ITransientNotification;
74 import android.app.Notification;
75 import android.app.NotificationChannel;
76 import android.app.NotificationManager.Policy;
77 import android.app.NotificationManager;
78 import android.app.PendingIntent;
79 import android.app.StatusBarManager;
80 import android.app.usage.UsageEvents;
81 import android.app.usage.UsageStatsManagerInternal;
82 import android.companion.ICompanionDeviceManager;
83 import android.content.BroadcastReceiver;
84 import android.content.ComponentName;
85 import android.content.ContentResolver;
86 import android.content.Context;
87 import android.content.Intent;
88 import android.content.IntentFilter;
89 import android.content.pm.ApplicationInfo;
90 import android.content.pm.IPackageManager;
91 import android.content.pm.PackageInfo;
92 import android.content.pm.PackageManager;
93 import android.content.pm.PackageManager.NameNotFoundException;
94 import android.content.pm.ParceledListSlice;
95 import android.content.res.Resources;
96 import android.database.ContentObserver;
97 import android.media.AudioManager;
98 import android.media.AudioManagerInternal;
99 import android.media.IRingtonePlayer;
100 import android.media.ToneGenerator;
101 import android.net.Uri;
102 import android.os.Binder;
103 import android.os.Build;
104 import android.os.Bundle;
105 import android.os.Environment;
106 import android.os.Handler;
107 import android.os.HandlerThread;
108 import android.os.IBinder;
109 import android.os.IInterface;
110 import android.os.Looper;
111 import android.os.Message;
112 import android.os.Process;
113 import android.os.RemoteException;
114 import android.os.ServiceManager;
115 import android.os.SystemClock;
116 import android.os.SystemProperties;
117 import android.os.UserHandle;
118 import android.os.Vibrator;
119 import android.os.VibrationEffect;
120 import android.provider.Settings;
121 import android.service.notification.Adjustment;
122 import android.service.notification.Condition;
123 import android.service.notification.IConditionProvider;
124 import android.service.notification.INotificationListener;
125 import android.service.notification.IStatusBarNotificationHolder;
126 import android.service.notification.NotificationAssistantService;
127 import android.service.notification.NotificationListenerService;
128 import android.service.notification.NotificationRankingUpdate;
129 import android.service.notification.NotificationRecordProto;
130 import android.service.notification.NotificationServiceDumpProto;
131 import android.service.notification.NotificationServiceProto;
132 import android.service.notification.SnoozeCriterion;
133 import android.service.notification.StatusBarNotification;
134 import android.service.notification.ZenModeConfig;
135 import android.service.notification.ZenModeProto;
136 import android.telecom.TelecomManager;
137 import android.telephony.PhoneStateListener;
138 import android.telephony.TelephonyManager;
139 import android.text.TextUtils;
140 import android.util.ArrayMap;
141 import android.util.ArraySet;
142 import android.util.AtomicFile;
143 import android.util.Log;
144 import android.util.Slog;
145 import android.util.SparseArray;
146 import android.util.Xml;
147 import android.util.proto.ProtoOutputStream;
148 import android.view.WindowManagerInternal;
149 import android.view.accessibility.AccessibilityEvent;
150 import android.view.accessibility.AccessibilityManager;
151 import android.widget.Toast;
153 import com.android.internal.R;
154 import com.android.internal.annotations.GuardedBy;
155 import com.android.internal.annotations.VisibleForTesting;
156 import com.android.internal.logging.MetricsLogger;
157 import com.android.internal.logging.nano.MetricsProto;
158 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
159 import com.android.internal.statusbar.NotificationVisibility;
160 import com.android.internal.util.ArrayUtils;
161 import com.android.internal.util.DumpUtils;
162 import com.android.internal.util.FastXmlSerializer;
163 import com.android.internal.util.Preconditions;
164 import com.android.server.DeviceIdleController;
165 import com.android.server.EventLogTags;
166 import com.android.server.LocalServices;
167 import com.android.server.SystemService;
168 import com.android.server.lights.Light;
169 import com.android.server.lights.LightsManager;
170 import com.android.server.notification.ManagedServices.ManagedServiceInfo;
171 import com.android.server.policy.PhoneWindowManager;
172 import com.android.server.statusbar.StatusBarManagerInternal;
173 import com.android.server.notification.ManagedServices.UserProfiles;
175 import libcore.io.IoUtils;
177 import org.json.JSONException;
178 import org.json.JSONObject;
179 import org.xmlpull.v1.XmlPullParser;
180 import org.xmlpull.v1.XmlPullParserException;
181 import org.xmlpull.v1.XmlSerializer;
183 import java.io.ByteArrayInputStream;
184 import java.io.ByteArrayOutputStream;
186 import java.io.FileDescriptor;
187 import java.io.FileInputStream;
188 import java.io.FileNotFoundException;
189 import java.io.FileOutputStream;
190 import java.io.IOException;
191 import java.io.InputStream;
192 import java.io.OutputStream;
193 import java.io.PrintWriter;
194 import java.nio.charset.StandardCharsets;
195 import java.util.ArrayDeque;
196 import java.util.ArrayList;
197 import java.util.Arrays;
198 import java.util.Iterator;
199 import java.util.List;
200 import java.util.Map;
201 import java.util.Map.Entry;
202 import java.util.Objects;
203 import java.util.concurrent.TimeUnit;
206 public class NotificationManagerService extends SystemService {
207 static final String TAG = "NotificationService";
208 static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
209 public static final boolean ENABLE_CHILD_NOTIFICATIONS
210 = SystemProperties.getBoolean("debug.child_notifs", true);
212 static final int MAX_PACKAGE_NOTIFICATIONS = 50;
213 static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 5f;
216 static final int MESSAGE_TIMEOUT = 2;
217 static final int MESSAGE_SAVE_POLICY_FILE = 3;
218 static final int MESSAGE_SEND_RANKING_UPDATE = 4;
219 static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
220 static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
222 // ranking thread messages
223 private static final int MESSAGE_RECONSIDER_RANKING = 1000;
224 private static final int MESSAGE_RANKING_SORT = 1001;
226 static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
227 static final int SHORT_DELAY = 2000; // 2 seconds
229 static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
231 static final long SNOOZE_UNTIL_UNSPECIFIED = -1;
233 static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
235 static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
237 static final boolean ENABLE_BLOCKED_TOASTS = true;
239 // When #matchesCallFilter is called from the ringer, wait at most
240 // 3s to resolve the contacts. This timeout is required since
241 // ContactsProvider might take a long time to start up.
243 // Return STARRED_CONTACT when the timeout is hit in order to avoid
244 // missed calls in ZEN mode "Important".
245 static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
246 static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
247 ValidateNotificationPeople.STARRED_CONTACT;
249 /** notification_enqueue status value for a newly enqueued notification. */
250 private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
252 /** notification_enqueue status value for an existing notification. */
253 private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
255 /** notification_enqueue status value for an ignored notification. */
256 private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
257 private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
259 private static final long DELAY_FOR_ASSISTANT_TIME = 100;
261 private static final String ACTION_NOTIFICATION_TIMEOUT =
262 NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
263 private static final int REQUEST_CODE_TIMEOUT = 1;
264 private static final String SCHEME_TIMEOUT = "timeout";
265 private static final String EXTRA_KEY = "key";
267 private IActivityManager mAm;
268 private IPackageManager mPackageManager;
269 private PackageManager mPackageManagerClient;
270 AudioManager mAudioManager;
271 AudioManagerInternal mAudioManagerInternal;
272 @Nullable StatusBarManagerInternal mStatusBar;
274 private WindowManagerInternal mWindowManagerInternal;
275 private AlarmManager mAlarmManager;
276 private ICompanionDeviceManager mCompanionManager;
278 final IBinder mForegroundToken = new Binder();
279 private Handler mHandler;
280 private final HandlerThread mRankingThread = new HandlerThread("ranker",
281 Process.THREAD_PRIORITY_BACKGROUND);
283 private Light mNotificationLight;
284 Light mAttentionLight;
286 private long[] mFallbackVibrationPattern;
287 private boolean mUseAttentionLight;
288 boolean mSystemReady;
290 private boolean mDisableNotificationEffects;
291 private int mCallState;
292 private String mSoundNotificationKey;
293 private String mVibrateNotificationKey;
295 private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
296 new SparseArray<ArraySet<ManagedServiceInfo>>();
297 private List<ComponentName> mEffectsSuppressors = new ArrayList<ComponentName>();
298 private int mListenerHints; // right now, all hints are global
299 private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
301 // for enabling and disabling notification pulse behavior
302 private boolean mScreenOn = true;
303 private boolean mInCall = false;
304 private boolean mNotificationPulseEnabled;
306 // for generating notification tones in-call
307 private ToneGenerator mInCallToneGenerator;
308 private final Object mInCallToneGeneratorLock = new Object();
310 // used as a mutex for access to all active notifications & listeners
311 final Object mNotificationLock = new Object();
312 @GuardedBy("mNotificationLock")
313 final ArrayList<NotificationRecord> mNotificationList =
314 new ArrayList<NotificationRecord>();
315 @GuardedBy("mNotificationLock")
316 final ArrayMap<String, NotificationRecord> mNotificationsByKey =
317 new ArrayMap<String, NotificationRecord>();
318 @GuardedBy("mNotificationLock")
319 final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();
320 @GuardedBy("mNotificationLock")
321 final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
322 final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();
323 final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
324 final PolicyAccess mPolicyAccess = new PolicyAccess();
326 // The last key in this list owns the hardware.
327 ArrayList<String> mLights = new ArrayList<>();
329 private AppOpsManager mAppOps;
330 private UsageStatsManagerInternal mAppUsageStats;
332 private Archive mArchive;
334 // Persistent storage for notification policy
335 private AtomicFile mPolicyFile;
337 private static final int DB_VERSION = 1;
339 private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
340 private static final String ATTR_VERSION = "version";
342 private RankingHelper mRankingHelper;
344 private final UserProfiles mUserProfiles = new UserProfiles();
345 private NotificationListeners mListeners;
346 private NotificationAssistants mNotificationAssistants;
347 private ConditionProviders mConditionProviders;
348 private NotificationUsageStats mUsageStats;
350 private static final int MY_UID = Process.myUid();
351 private static final int MY_PID = Process.myPid();
352 private static final IBinder WHITELIST_TOKEN = new Binder();
353 private RankingHandler mRankingHandler;
354 private long mLastOverRateLogTime;
355 private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
357 private SnoozeHelper mSnoozeHelper;
358 private GroupHelper mGroupHelper;
359 private boolean mIsTelevision;
361 private static class Archive {
362 final int mBufferSize;
363 final ArrayDeque<StatusBarNotification> mBuffer;
365 public Archive(int size) {
367 mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
370 public String toString() {
371 final StringBuilder sb = new StringBuilder();
372 final int N = mBuffer.size();
373 sb.append("Archive (");
375 sb.append(" notification");
376 sb.append((N==1)?")":"s)");
377 return sb.toString();
380 public void record(StatusBarNotification nr) {
381 if (mBuffer.size() == mBufferSize) {
382 mBuffer.removeFirst();
385 // We don't want to store the heavy bits of the notification in the archive,
386 // but other clients in the system process might be using the object, so we
387 // store a (lightened) copy.
388 mBuffer.addLast(nr.cloneLight());
391 public Iterator<StatusBarNotification> descendingIterator() {
392 return mBuffer.descendingIterator();
395 public StatusBarNotification[] getArray(int count) {
396 if (count == 0) count = mBufferSize;
397 final StatusBarNotification[] a
398 = new StatusBarNotification[Math.min(count, mBuffer.size())];
399 Iterator<StatusBarNotification> iter = descendingIterator();
401 while (iter.hasNext() && i < count) {
402 a[i++] = iter.next();
409 private void readPolicyXml(InputStream stream, boolean forRestore)
410 throws XmlPullParserException, NumberFormatException, IOException {
411 final XmlPullParser parser = Xml.newPullParser();
412 parser.setInput(stream, StandardCharsets.UTF_8.name());
414 while (parser.next() != END_DOCUMENT) {
415 mZenModeHelper.readXml(parser, forRestore);
416 mRankingHelper.readXml(parser, forRestore);
420 private void loadPolicyFile() {
421 if (DBG) Slog.d(TAG, "loadPolicyFile");
422 synchronized (mPolicyFile) {
424 FileInputStream infile = null;
426 infile = mPolicyFile.openRead();
427 readPolicyXml(infile, false /*forRestore*/);
428 } catch (FileNotFoundException e) {
430 } catch (IOException e) {
431 Log.wtf(TAG, "Unable to read notification policy", e);
432 } catch (NumberFormatException e) {
433 Log.wtf(TAG, "Unable to parse notification policy", e);
434 } catch (XmlPullParserException e) {
435 Log.wtf(TAG, "Unable to parse notification policy", e);
437 IoUtils.closeQuietly(infile);
442 public void savePolicyFile() {
443 mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
444 mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
447 private void handleSavePolicyFile() {
448 if (DBG) Slog.d(TAG, "handleSavePolicyFile");
449 synchronized (mPolicyFile) {
450 final FileOutputStream stream;
452 stream = mPolicyFile.startWrite();
453 } catch (IOException e) {
454 Slog.w(TAG, "Failed to save policy file", e);
459 writePolicyXml(stream, false /*forBackup*/);
460 mPolicyFile.finishWrite(stream);
461 } catch (IOException e) {
462 Slog.w(TAG, "Failed to save policy file, restoring backup", e);
463 mPolicyFile.failWrite(stream);
466 BackupManager.dataChanged(getContext().getPackageName());
469 private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
470 final XmlSerializer out = new FastXmlSerializer();
471 out.setOutput(stream, StandardCharsets.UTF_8.name());
472 out.startDocument(null, true);
473 out.startTag(null, TAG_NOTIFICATION_POLICY);
474 out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
475 mZenModeHelper.writeXml(out, forBackup);
476 mRankingHelper.writeXml(out, forBackup);
477 out.endTag(null, TAG_NOTIFICATION_POLICY);
481 /** Use this to check if a package can post a notification or toast. */
482 private boolean checkNotificationOp(String pkg, int uid) {
483 return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
484 == AppOpsManager.MODE_ALLOWED && !isPackageSuspendedForUser(pkg, uid);
487 private static final class ToastRecord
491 final ITransientNotification callback;
495 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
499 this.callback = callback;
500 this.duration = duration;
504 void update(int duration) {
505 this.duration = duration;
508 void dump(PrintWriter pw, String prefix, DumpFilter filter) {
509 if (filter != null && !filter.matches(pkg)) return;
510 pw.println(prefix + this);
514 public final String toString()
516 return "ToastRecord{"
517 + Integer.toHexString(System.identityHashCode(this))
519 + " callback=" + callback
520 + " duration=" + duration;
525 final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
528 public void onSetDisabled(int status) {
529 synchronized (mNotificationLock) {
530 mDisableNotificationEffects =
531 (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
532 if (disableNotificationEffects(null) != null) {
533 // cancel whatever's going on
534 long identity = Binder.clearCallingIdentity();
536 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
537 if (player != null) {
540 } catch (RemoteException e) {
542 Binder.restoreCallingIdentity(identity);
545 identity = Binder.clearCallingIdentity();
549 Binder.restoreCallingIdentity(identity);
556 public void onClearAll(int callingUid, int callingPid, int userId) {
557 synchronized (mNotificationLock) {
558 cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null,
559 /*includeCurrentProfiles*/ true);
564 public void onNotificationClick(int callingUid, int callingPid, String key) {
565 synchronized (mNotificationLock) {
566 NotificationRecord r = mNotificationsByKey.get(key);
568 Log.w(TAG, "No notification with key: " + key);
571 final long now = System.currentTimeMillis();
572 MetricsLogger.action(r.getLogMaker(now)
573 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
574 .setType(MetricsEvent.TYPE_ACTION));
575 EventLogTags.writeNotificationClicked(key,
576 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
578 StatusBarNotification sbn = r.sbn;
579 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
580 sbn.getId(), Notification.FLAG_AUTO_CANCEL,
581 Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
587 public void onNotificationActionClick(int callingUid, int callingPid, String key,
589 synchronized (mNotificationLock) {
590 NotificationRecord r = mNotificationsByKey.get(key);
592 Log.w(TAG, "No notification with key: " + key);
595 final long now = System.currentTimeMillis();
596 MetricsLogger.action(r.getLogMaker(now)
597 .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION)
598 .setType(MetricsEvent.TYPE_ACTION)
599 .setSubtype(actionIndex));
600 EventLogTags.writeNotificationActionClicked(key, actionIndex,
601 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
602 // TODO: Log action click via UsageStats.
607 public void onNotificationClear(int callingUid, int callingPid,
608 String pkg, String tag, int id, int userId) {
609 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
610 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
611 true, userId, REASON_CANCEL, null);
615 public void onPanelRevealed(boolean clearEffects, int items) {
616 MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL);
617 MetricsLogger.histogram(getContext(), "note_load", items);
618 EventLogTags.writeNotificationPanelRevealed(items);
625 public void onPanelHidden() {
626 MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL);
627 EventLogTags.writeNotificationPanelHidden();
631 public void clearEffects() {
632 synchronized (mNotificationLock) {
633 if (DBG) Slog.d(TAG, "clearEffects");
635 clearVibrateLocked();
641 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
642 int uid, int initialPid, String message, int userId) {
643 Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
644 + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
645 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
647 long ident = Binder.clearCallingIdentity();
649 ActivityManager.getService().crashApplication(uid, initialPid, pkg, -1,
650 "Bad notification posted from package " + pkg
652 } catch (RemoteException e) {
654 Binder.restoreCallingIdentity(ident);
658 public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
659 NotificationVisibility[] noLongerVisibleKeys) {
660 synchronized (mNotificationLock) {
661 for (NotificationVisibility nv : newlyVisibleKeys) {
662 NotificationRecord r = mNotificationsByKey.get(nv.key);
663 if (r == null) continue;
664 r.setVisibility(true, nv.rank);
667 // Note that we might receive this event after notifications
668 // have already left the system, e.g. after dismissing from the
669 // shade. Hence not finding notifications in
670 // mNotificationsByKey is not an exceptional condition.
671 for (NotificationVisibility nv : noLongerVisibleKeys) {
672 NotificationRecord r = mNotificationsByKey.get(nv.key);
673 if (r == null) continue;
674 r.setVisibility(false, nv.rank);
681 public void onNotificationExpansionChanged(String key,
682 boolean userAction, boolean expanded) {
683 synchronized (mNotificationLock) {
684 NotificationRecord r = mNotificationsByKey.get(key);
686 r.stats.onExpansionChanged(userAction, expanded);
687 final long now = System.currentTimeMillis();
688 MetricsLogger.action(r.getLogMaker(now)
689 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
690 .setType(MetricsEvent.TYPE_DETAIL));
691 EventLogTags.writeNotificationExpansion(key,
692 userAction ? 1 : 0, expanded ? 1 : 0,
693 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
699 @GuardedBy("mNotificationLock")
700 private void clearSoundLocked() {
701 mSoundNotificationKey = null;
702 long identity = Binder.clearCallingIdentity();
704 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
705 if (player != null) {
708 } catch (RemoteException e) {
710 Binder.restoreCallingIdentity(identity);
714 @GuardedBy("mNotificationLock")
715 private void clearVibrateLocked() {
716 mVibrateNotificationKey = null;
717 long identity = Binder.clearCallingIdentity();
721 Binder.restoreCallingIdentity(identity);
725 @GuardedBy("mNotificationLock")
726 private void clearLightsLocked() {
729 updateLightsLocked();
732 private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() {
734 public void onReceive(Context context, Intent intent) {
735 String action = intent.getAction();
736 if (action == null) {
739 if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) {
740 final NotificationRecord record;
741 synchronized (mNotificationLock) {
742 record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
744 if (record != null) {
745 cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(),
746 record.sbn.getPackageName(), record.sbn.getTag(),
747 record.sbn.getId(), 0,
748 Notification.FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
749 REASON_TIMEOUT, null);
755 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
757 public void onReceive(Context context, Intent intent) {
758 String action = intent.getAction();
759 if (action == null) {
763 boolean queryRestart = false;
764 boolean queryRemove = false;
765 boolean packageChanged = false;
766 boolean cancelNotifications = true;
767 int reason = REASON_PACKAGE_CHANGED;
769 if (action.equals(Intent.ACTION_PACKAGE_ADDED)
770 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
771 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
772 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
773 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
774 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
775 || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
776 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
777 UserHandle.USER_ALL);
778 String pkgList[] = null;
779 int uidList[] = null;
780 boolean removingPackage = queryRemove &&
781 !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
782 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
783 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
784 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
785 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
786 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
787 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
788 reason = REASON_PACKAGE_SUSPENDED;
789 } else if (queryRestart) {
790 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
791 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
793 Uri uri = intent.getData();
797 String pkgName = uri.getSchemeSpecificPart();
798 if (pkgName == null) {
801 if (packageChanged) {
802 // We cancel notifications for packages which have just been disabled
804 final int enabled = mPackageManager.getApplicationEnabledSetting(
806 changeUserId != UserHandle.USER_ALL ? changeUserId :
807 UserHandle.USER_SYSTEM);
808 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
809 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
810 cancelNotifications = false;
812 } catch (IllegalArgumentException e) {
813 // Package doesn't exist; probably racing with uninstall.
814 // cancelNotifications is already true, so nothing to do here.
816 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
818 } catch (RemoteException e) {
819 // Failed to talk to PackageManagerService Should never happen!
822 pkgList = new String[]{pkgName};
823 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
825 if (pkgList != null && (pkgList.length > 0)) {
826 for (String pkgName : pkgList) {
827 if (cancelNotifications) {
828 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0,
829 !queryRestart, changeUserId, reason, null);
833 mListeners.onPackagesChanged(removingPackage, pkgList);
834 mNotificationAssistants.onPackagesChanged(removingPackage, pkgList);
835 mConditionProviders.onPackagesChanged(removingPackage, pkgList);
836 mRankingHelper.onPackagesChanged(removingPackage, changeUserId, pkgList, uidList);
842 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
844 public void onReceive(Context context, Intent intent) {
845 String action = intent.getAction();
847 if (action.equals(Intent.ACTION_SCREEN_ON)) {
848 // Keep track of screen on/off state, but do not turn off the notification light
849 // until user passes through the lock screen or views the notification.
851 updateNotificationPulse();
852 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
854 updateNotificationPulse();
855 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
856 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
857 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
858 updateNotificationPulse();
859 synchronized (mInCallToneGeneratorLock) {
861 if (mInCallToneGenerator == null) {
862 int relativeToneVolume = getContext().getResources().getInteger(
863 R.integer.config_inCallNotificationVolumeRelative);
864 if (relativeToneVolume < ToneGenerator.MIN_VOLUME
865 || relativeToneVolume > ToneGenerator.MAX_VOLUME) {
866 relativeToneVolume = ToneGenerator.MAX_VOLUME;
869 mInCallToneGenerator = new ToneGenerator(
870 AudioManager.STREAM_VOICE_CALL, relativeToneVolume);
871 } catch (RuntimeException e) {
872 Log.e(TAG, "Error creating local tone generator: " + e);
873 mInCallToneGenerator = null;
877 if (mInCallToneGenerator != null) {
878 mInCallToneGenerator.release();
879 mInCallToneGenerator = null;
883 } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
884 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
885 if (userHandle >= 0) {
886 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
887 REASON_USER_STOPPED, null);
889 } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
890 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
891 if (userHandle >= 0) {
892 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
893 REASON_PROFILE_TURNED_OFF, null);
895 } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
896 // turn off LED when user passes through lock screen
897 mNotificationLight.turnOff();
898 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
899 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
900 // reload per-user settings
901 mSettingsObserver.update(null);
902 mUserProfiles.updateCache(context);
903 // Refresh managed services
904 mConditionProviders.onUserSwitched(user);
905 mListeners.onUserSwitched(user);
906 mNotificationAssistants.onUserSwitched(user);
907 mZenModeHelper.onUserSwitched(user);
908 } else if (action.equals(Intent.ACTION_USER_ADDED)) {
909 mUserProfiles.updateCache(context);
910 } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
911 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
912 mZenModeHelper.onUserRemoved(user);
913 mRankingHelper.onUserRemoved(user);
915 } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
916 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
917 mConditionProviders.onUserUnlocked(user);
918 mListeners.onUserUnlocked(user);
919 mNotificationAssistants.onUserUnlocked(user);
920 mZenModeHelper.onUserUnlocked(user);
925 private final class SettingsObserver extends ContentObserver {
926 private final Uri NOTIFICATION_BADGING_URI
927 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING);
928 private final Uri NOTIFICATION_LIGHT_PULSE_URI
929 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
930 private final Uri NOTIFICATION_RATE_LIMIT_URI
931 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
933 SettingsObserver(Handler handler) {
938 ContentResolver resolver = getContext().getContentResolver();
939 resolver.registerContentObserver(NOTIFICATION_BADGING_URI,
940 false, this, UserHandle.USER_ALL);
941 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
942 false, this, UserHandle.USER_ALL);
943 resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
944 false, this, UserHandle.USER_ALL);
948 @Override public void onChange(boolean selfChange, Uri uri) {
952 public void update(Uri uri) {
953 ContentResolver resolver = getContext().getContentResolver();
954 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
955 boolean pulseEnabled = Settings.System.getIntForUser(resolver,
956 Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT) != 0;
957 if (mNotificationPulseEnabled != pulseEnabled) {
958 mNotificationPulseEnabled = pulseEnabled;
959 updateNotificationPulse();
962 if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
963 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
964 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
966 if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) {
967 mRankingHelper.updateBadgingEnabled();
972 private SettingsObserver mSettingsObserver;
973 private ZenModeHelper mZenModeHelper;
975 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
976 int[] ar = r.getIntArray(resid);
980 final int len = ar.length > maxlen ? maxlen : ar.length;
981 long[] out = new long[len];
982 for (int i=0; i<len; i++) {
988 public NotificationManagerService(Context context) {
990 Notification.processWhitelistToken = WHITELIST_TOKEN;
993 // TODO - replace these methods with a single VisibleForTesting constructor
995 void setAudioManager(AudioManager audioMananger) {
996 mAudioManager = audioMananger;
1000 void setVibrator(Vibrator vibrator) {
1001 mVibrator = vibrator;
1005 void setLights(Light light) {
1006 mNotificationLight = light;
1007 mAttentionLight = light;
1008 mNotificationPulseEnabled = true;
1012 void setScreenOn(boolean on) {
1017 int getNotificationRecordCount() {
1018 synchronized (mNotificationLock) {
1019 int count = mNotificationList.size() + mNotificationsByKey.size()
1020 + mSummaryByGroupKey.size() + mEnqueuedNotifications.size();
1021 // subtract duplicates
1022 for (NotificationRecord posted : mNotificationList) {
1023 if (mNotificationsByKey.containsKey(posted.getKey())) {
1026 if (posted.sbn.isGroup() && posted.getNotification().isGroupSummary()) {
1036 void addNotification(NotificationRecord r) {
1037 mNotificationList.add(r);
1038 mNotificationsByKey.put(r.sbn.getKey(), r);
1039 if (r.sbn.isGroup()) {
1040 mSummaryByGroupKey.put(r.getGroupKey(), r);
1045 void addEnqueuedNotification(NotificationRecord r) {
1046 mEnqueuedNotifications.add(r);
1050 void setSystemReady(boolean systemReady) {
1051 mSystemReady = systemReady;
1055 void setHandler(Handler handler) {
1060 void setFallbackVibrationPattern(long[] vibrationPattern) {
1061 mFallbackVibrationPattern = vibrationPattern;
1065 void setPackageManager(IPackageManager packageManager) {
1066 mPackageManager = packageManager;
1070 void setRankingHelper(RankingHelper rankingHelper) {
1071 mRankingHelper = rankingHelper;
1075 void setIsTelevision(boolean isTelevision) {
1076 mIsTelevision = isTelevision;
1080 void setUsageStats(NotificationUsageStats us) {
1084 // TODO: All tests should use this init instead of the one-off setters above.
1086 void init(Looper looper, IPackageManager packageManager, PackageManager packageManagerClient,
1087 LightsManager lightsManager, NotificationListeners notificationListeners,
1088 ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
1089 NotificationUsageStats usageStats) {
1090 Resources resources = getContext().getResources();
1091 mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
1092 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
1093 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
1095 mAm = ActivityManager.getService();
1096 mPackageManager = packageManager;
1097 mPackageManagerClient = packageManagerClient;
1098 mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
1099 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
1100 mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
1101 mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
1102 mCompanionManager = companionManager;
1104 mHandler = new WorkerHandler(looper);
1105 mRankingThread.start();
1106 String[] extractorNames;
1108 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
1109 } catch (Resources.NotFoundException e) {
1110 extractorNames = new String[0];
1112 mUsageStats = usageStats;
1113 mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
1114 mRankingHelper = new RankingHelper(getContext(),
1115 getContext().getPackageManager(),
1119 mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles);
1120 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
1121 mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
1123 public void onConfigChanged() {
1128 void onZenModeChanged() {
1129 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
1130 getContext().sendBroadcastAsUser(
1131 new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
1132 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
1133 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
1134 synchronized (mNotificationLock) {
1135 updateInterruptionFilterLocked();
1140 void onPolicyChanged() {
1141 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
1144 mSnoozeHelper = snoozeHelper;
1145 mGroupHelper = new GroupHelper(new GroupHelper.Callback() {
1147 public void addAutoGroup(String key) {
1148 synchronized (mNotificationLock) {
1149 addAutogroupKeyLocked(key);
1151 mRankingHandler.requestSort(false);
1155 public void removeAutoGroup(String key) {
1156 synchronized (mNotificationLock) {
1157 removeAutogroupKeyLocked(key);
1159 mRankingHandler.requestSort(false);
1163 public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) {
1164 createAutoGroupSummary(userId, pkg, triggeringKey);
1168 public void removeAutoGroupSummary(int userId, String pkg) {
1169 synchronized (mNotificationLock) {
1170 clearAutogroupSummaryLocked(userId, pkg);
1175 final File systemDir = new File(Environment.getDataDirectory(), "system");
1176 mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
1180 // This is a ManagedServices object that keeps track of the listeners.
1181 mListeners = notificationListeners;
1183 // This is a MangedServices object that keeps track of the assistant.
1184 mNotificationAssistants = new NotificationAssistants();
1186 mStatusBar = getLocalService(StatusBarManagerInternal.class);
1187 if (mStatusBar != null) {
1188 mStatusBar.setNotificationDelegate(mNotificationDelegate);
1191 mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
1192 mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
1194 mFallbackVibrationPattern = getLongArray(resources,
1195 R.array.config_notificationFallbackVibePattern,
1196 VIBRATE_PATTERN_MAXLEN,
1197 DEFAULT_VIBRATE_PATTERN);
1199 mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
1201 // Don't start allowing notifications until the setup wizard has run once.
1202 // After that, including subsequent boots, init with notifications turned on.
1203 // This works on the first boot because the setup wizard will toggle this
1204 // flag at least once and we'll go back to 0 after that.
1205 if (0 == Settings.Global.getInt(getContext().getContentResolver(),
1206 Settings.Global.DEVICE_PROVISIONED, 0)) {
1207 mDisableNotificationEffects = true;
1209 mZenModeHelper.initZenMode();
1210 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1212 mUserProfiles.updateCache(getContext());
1213 listenForCallState();
1215 mSettingsObserver = new SettingsObserver(mHandler);
1217 mArchive = new Archive(resources.getInteger(
1218 R.integer.config_notificationServiceArchiveSize));
1220 mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
1221 || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
1225 public void onStart() {
1226 SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() {
1228 public void repost(int userId, NotificationRecord r) {
1231 Slog.d(TAG, "Reposting " + r.getKey());
1233 enqueueNotificationInternal(r.sbn.getPackageName(), r.sbn.getOpPkg(),
1234 r.sbn.getUid(), r.sbn.getInitialPid(), r.sbn.getTag(), r.sbn.getId(),
1235 r.sbn.getNotification(), userId);
1236 } catch (Exception e) {
1237 Slog.e(TAG, "Cannot un-snooze notification", e);
1242 init(Looper.myLooper(), AppGlobals.getPackageManager(), getContext().getPackageManager(),
1243 getLocalService(LightsManager.class), new NotificationListeners(),
1244 null, snoozeHelper, new NotificationUsageStats(getContext()));
1246 // register for various Intents
1247 IntentFilter filter = new IntentFilter();
1248 filter.addAction(Intent.ACTION_SCREEN_ON);
1249 filter.addAction(Intent.ACTION_SCREEN_OFF);
1250 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
1251 filter.addAction(Intent.ACTION_USER_PRESENT);
1252 filter.addAction(Intent.ACTION_USER_STOPPED);
1253 filter.addAction(Intent.ACTION_USER_SWITCHED);
1254 filter.addAction(Intent.ACTION_USER_ADDED);
1255 filter.addAction(Intent.ACTION_USER_REMOVED);
1256 filter.addAction(Intent.ACTION_USER_UNLOCKED);
1257 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
1258 getContext().registerReceiver(mIntentReceiver, filter);
1260 IntentFilter pkgFilter = new IntentFilter();
1261 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
1262 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1263 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
1264 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1265 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1266 pkgFilter.addDataScheme("package");
1267 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1270 IntentFilter suspendedPkgFilter = new IntentFilter();
1271 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
1272 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1273 suspendedPkgFilter, null, null);
1275 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
1276 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1279 IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
1280 timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
1281 getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter);
1283 publishBinderService(Context.NOTIFICATION_SERVICE, mService);
1284 publishLocalService(NotificationManagerInternal.class, mInternalService);
1287 private void sendRegisteredOnlyBroadcast(String action) {
1288 getContext().sendBroadcastAsUser(new Intent(action)
1289 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
1293 public void onBootPhase(int phase) {
1294 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1295 // no beeping until we're basically done booting
1296 mSystemReady = true;
1298 // Grab our optional AudioService
1299 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
1300 mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
1301 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
1302 mZenModeHelper.onSystemReady();
1303 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1304 // This observer will force an update when observe is called, causing us to
1305 // bind to listener services.
1306 mSettingsObserver.observe();
1307 mListeners.onBootPhaseAppsCanStart();
1308 mNotificationAssistants.onBootPhaseAppsCanStart();
1309 mConditionProviders.onBootPhaseAppsCanStart();
1313 @GuardedBy("mNotificationLock")
1314 private void updateListenerHintsLocked() {
1315 final int hints = calculateHints();
1316 if (hints == mListenerHints) return;
1317 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
1318 mListenerHints = hints;
1319 scheduleListenerHintsChanged(hints);
1322 @GuardedBy("mNotificationLock")
1323 private void updateEffectsSuppressorLocked() {
1324 final long updatedSuppressedEffects = calculateSuppressedEffects();
1325 if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1326 final List<ComponentName> suppressors = getSuppressors();
1327 ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1328 mEffectsSuppressors = suppressors;
1329 mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
1330 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
1333 private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
1334 boolean fromListener) {
1335 if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
1337 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
1338 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
1341 mRankingHelper.updateNotificationChannel(pkg, uid, channel);
1343 final NotificationChannel modifiedChannel =
1344 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
1346 if (!fromListener) {
1347 mListeners.notifyNotificationChannelChanged(
1348 pkg, UserHandle.getUserHandleForUid(uid),
1349 modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
1352 synchronized (mNotificationLock) {
1353 final int N = mNotificationList.size();
1354 for (int i = N - 1; i >= 0; --i) {
1355 NotificationRecord r = mNotificationList.get(i);
1356 if (r.sbn.getPackageName().equals(pkg)
1357 && r.sbn.getUid() == uid
1358 && channel.getId() != null
1359 && channel.getId().equals(r.getChannel().getId())) {
1360 r.updateNotificationChannel(modifiedChannel);
1364 mRankingHandler.requestSort(true);
1368 private ArrayList<ComponentName> getSuppressors() {
1369 ArrayList<ComponentName> names = new ArrayList<ComponentName>();
1370 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1371 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1373 for (ManagedServiceInfo info : serviceInfoList) {
1374 names.add(info.component);
1381 private boolean removeDisabledHints(ManagedServiceInfo info) {
1382 return removeDisabledHints(info, 0);
1385 private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
1386 boolean removed = false;
1388 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1389 final int hint = mListenersDisablingEffects.keyAt(i);
1390 final ArraySet<ManagedServiceInfo> listeners =
1391 mListenersDisablingEffects.valueAt(i);
1393 if (hints == 0 || (hint & hints) == hint) {
1394 removed = removed || listeners.remove(info);
1401 private void addDisabledHints(ManagedServiceInfo info, int hints) {
1402 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1403 addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
1406 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1407 addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1410 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1411 addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
1415 private void addDisabledHint(ManagedServiceInfo info, int hint) {
1416 if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
1417 mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
1420 ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
1421 hintListeners.add(info);
1424 private int calculateHints() {
1426 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1427 int hint = mListenersDisablingEffects.keyAt(i);
1428 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1430 if (!serviceInfoList.isEmpty()) {
1438 private long calculateSuppressedEffects() {
1439 int hints = calculateHints();
1440 long suppressedEffects = 0;
1442 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1443 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
1446 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1447 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
1450 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1451 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
1454 return suppressedEffects;
1457 @GuardedBy("mNotificationLock")
1458 private void updateInterruptionFilterLocked() {
1459 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1460 if (interruptionFilter == mInterruptionFilter) return;
1461 mInterruptionFilter = interruptionFilter;
1462 scheduleInterruptionFilterChanged(interruptionFilter);
1466 INotificationManager getBinderService() {
1467 return INotificationManager.Stub.asInterface(mService);
1471 NotificationManagerInternal getInternalService() {
1472 return mInternalService;
1475 private final IBinder mService = new INotificationManager.Stub() {
1477 // ============================================================================
1480 public void enqueueToast(String pkg, ITransientNotification callback, int duration)
1483 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1484 + " duration=" + duration);
1487 if (pkg == null || callback == null) {
1488 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1492 final boolean isSystemToast = isCallerSystemOrPhone() || ("android".equals(pkg));
1493 final boolean isPackageSuspended =
1494 isPackageSuspendedForUser(pkg, Binder.getCallingUid());
1496 if (ENABLE_BLOCKED_TOASTS && !isSystemToast &&
1497 (!areNotificationsEnabledForPackage(pkg, Binder.getCallingUid())
1498 || isPackageSuspended)) {
1499 Slog.e(TAG, "Suppressing toast from package " + pkg
1500 + (isPackageSuspended
1501 ? " due to package suspended by administrator."
1502 : " by user request."));
1506 synchronized (mToastQueue) {
1507 int callingPid = Binder.getCallingPid();
1508 long callingId = Binder.clearCallingIdentity();
1511 int index = indexOfToastLocked(pkg, callback);
1512 // If it's already in the queue, we update it in place, we don't
1513 // move it to the end of the queue.
1515 record = mToastQueue.get(index);
1516 record.update(duration);
1518 // Limit the number of toasts that any given package except the android
1519 // package can enqueue. Prevents DOS attacks and deals with leaks.
1520 if (!isSystemToast) {
1522 final int N = mToastQueue.size();
1523 for (int i=0; i<N; i++) {
1524 final ToastRecord r = mToastQueue.get(i);
1525 if (r.pkg.equals(pkg)) {
1527 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
1528 Slog.e(TAG, "Package has already posted " + count
1529 + " toasts. Not showing more. Package=" + pkg);
1536 Binder token = new Binder();
1537 mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, DEFAULT_DISPLAY);
1538 record = new ToastRecord(callingPid, pkg, callback, duration, token);
1539 mToastQueue.add(record);
1540 index = mToastQueue.size() - 1;
1541 keepProcessAliveIfNeededLocked(callingPid);
1543 // If it's at index 0, it's the current toast. It doesn't matter if it's
1544 // new or just been updated. Call back and tell it to show itself.
1545 // If the callback fails, this will remove it from the list, so don't
1546 // assume that it's valid after this.
1548 showNextToastLocked();
1551 Binder.restoreCallingIdentity(callingId);
1557 public void cancelToast(String pkg, ITransientNotification callback) {
1558 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
1560 if (pkg == null || callback == null) {
1561 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
1565 synchronized (mToastQueue) {
1566 long callingId = Binder.clearCallingIdentity();
1568 int index = indexOfToastLocked(pkg, callback);
1570 cancelToastLocked(index);
1572 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
1573 + " callback=" + callback);
1576 Binder.restoreCallingIdentity(callingId);
1582 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
1583 Notification notification, int userId) throws RemoteException {
1584 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
1585 Binder.getCallingPid(), tag, id, notification, userId);
1589 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
1590 checkCallerIsSystemOrSameApp(pkg);
1591 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1592 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
1593 // Don't allow client applications to cancel foreground service notis or autobundled
1595 final int mustNotHaveFlags = isCallingUidSystem() ? 0 :
1596 (Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTOGROUP_SUMMARY);
1597 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
1598 mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null);
1602 public void cancelAllNotifications(String pkg, int userId) {
1603 checkCallerIsSystemOrSameApp(pkg);
1605 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1606 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
1608 // Calling from user space, don't allow the canceling of actively
1609 // running foreground services.
1610 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
1611 pkg, null, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
1612 REASON_APP_CANCEL_ALL, null);
1616 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
1617 checkCallerIsSystem();
1619 mRankingHelper.setEnabled(pkg, uid, enabled);
1620 // Now, cancel any outstanding notifications that are part of a just-disabled app
1622 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
1623 UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
1629 * Use this when you just want to know if notifications are OK for this package.
1632 public boolean areNotificationsEnabled(String pkg) {
1633 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
1637 * Use this when you just want to know if notifications are OK for this package.
1640 public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
1641 checkCallerIsSystemOrSameApp(pkg);
1643 return mRankingHelper.getImportance(pkg, uid) != IMPORTANCE_NONE;
1647 public int getPackageImportance(String pkg) {
1648 checkCallerIsSystemOrSameApp(pkg);
1649 return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
1653 public boolean canShowBadge(String pkg, int uid) {
1654 checkCallerIsSystem();
1655 return mRankingHelper.canShowBadge(pkg, uid);
1659 public void setShowBadge(String pkg, int uid, boolean showBadge) {
1660 checkCallerIsSystem();
1661 mRankingHelper.setShowBadge(pkg, uid, showBadge);
1666 public void createNotificationChannelGroups(String pkg,
1667 ParceledListSlice channelGroupList) throws RemoteException {
1668 checkCallerIsSystemOrSameApp(pkg);
1669 List<NotificationChannelGroup> groups = channelGroupList.getList();
1670 final int groupSize = groups.size();
1671 for (int i = 0; i < groupSize; i++) {
1672 final NotificationChannelGroup group = groups.get(i);
1673 Preconditions.checkNotNull(group, "group in list is null");
1674 mRankingHelper.createNotificationChannelGroup(pkg, Binder.getCallingUid(), group,
1675 true /* fromTargetApp */);
1676 mListeners.notifyNotificationChannelGroupChanged(pkg,
1677 UserHandle.of(UserHandle.getCallingUserId()), group,
1678 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1683 private void createNotificationChannelsImpl(String pkg, int uid,
1684 ParceledListSlice channelsList) {
1685 List<NotificationChannel> channels = channelsList.getList();
1686 final int channelsSize = channels.size();
1687 for (int i = 0; i < channelsSize; i++) {
1688 final NotificationChannel channel = channels.get(i);
1689 Preconditions.checkNotNull(channel, "channel in list is null");
1690 mRankingHelper.createNotificationChannel(pkg, uid, channel,
1691 true /* fromTargetApp */);
1692 mListeners.notifyNotificationChannelChanged(pkg,
1693 UserHandle.getUserHandleForUid(uid),
1694 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false),
1695 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1701 public void createNotificationChannels(String pkg,
1702 ParceledListSlice channelsList) throws RemoteException {
1703 checkCallerIsSystemOrSameApp(pkg);
1704 createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList);
1708 public void createNotificationChannelsForPackage(String pkg, int uid,
1709 ParceledListSlice channelsList) throws RemoteException {
1710 checkCallerIsSystem();
1711 createNotificationChannelsImpl(pkg, uid, channelsList);
1715 public NotificationChannel getNotificationChannel(String pkg, String channelId) {
1716 checkCallerIsSystemOrSameApp(pkg);
1717 return mRankingHelper.getNotificationChannel(
1718 pkg, Binder.getCallingUid(), channelId, false /* includeDeleted */);
1722 public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
1723 String channelId, boolean includeDeleted) {
1724 checkCallerIsSystem();
1725 return mRankingHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted);
1729 public void deleteNotificationChannel(String pkg, String channelId) {
1730 checkCallerIsSystemOrSameApp(pkg);
1731 final int callingUid = Binder.getCallingUid();
1732 if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
1733 throw new IllegalArgumentException("Cannot delete default channel");
1735 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
1736 UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
1737 mRankingHelper.deleteNotificationChannel(pkg, callingUid, channelId);
1738 mListeners.notifyNotificationChannelChanged(pkg,
1739 UserHandle.getUserHandleForUid(callingUid),
1740 mRankingHelper.getNotificationChannel(pkg, callingUid, channelId, true),
1741 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1746 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
1748 checkCallerIsSystemOrSameApp(pkg);
1749 return new ParceledListSlice<>(new ArrayList(
1750 mRankingHelper.getNotificationChannelGroups(pkg, Binder.getCallingUid())));
1754 public void deleteNotificationChannelGroup(String pkg, String groupId) {
1755 checkCallerIsSystemOrSameApp(pkg);
1757 final int callingUid = Binder.getCallingUid();
1758 NotificationChannelGroup groupToDelete =
1759 mRankingHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
1760 if (groupToDelete != null) {
1761 List<NotificationChannel> deletedChannels =
1762 mRankingHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
1763 for (int i = 0; i < deletedChannels.size(); i++) {
1764 final NotificationChannel deletedChannel = deletedChannels.get(i);
1765 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
1767 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
1769 mListeners.notifyNotificationChannelChanged(pkg,
1770 UserHandle.getUserHandleForUid(callingUid),
1772 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1774 mListeners.notifyNotificationChannelGroupChanged(
1775 pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete,
1776 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1782 public void updateNotificationChannelForPackage(String pkg, int uid,
1783 NotificationChannel channel) {
1784 enforceSystemOrSystemUI("Caller not system or systemui");
1785 Preconditions.checkNotNull(channel);
1786 updateNotificationChannelInt(pkg, uid, channel, false);
1790 public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
1791 int uid, boolean includeDeleted) {
1792 enforceSystemOrSystemUI("getNotificationChannelsForPackage");
1793 return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted);
1797 public int getNumNotificationChannelsForPackage(String pkg, int uid,
1798 boolean includeDeleted) {
1799 enforceSystemOrSystemUI("getNumNotificationChannelsForPackage");
1800 return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted)
1805 public boolean onlyHasDefaultChannel(String pkg, int uid) {
1806 enforceSystemOrSystemUI("onlyHasDefaultChannel");
1807 return mRankingHelper.onlyHasDefaultChannel(pkg, uid);
1811 public int getDeletedChannelCount(String pkg, int uid) {
1812 enforceSystemOrSystemUI("getDeletedChannelCount");
1813 return mRankingHelper.getDeletedChannelCount(pkg, uid);
1817 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
1818 String pkg, int uid, boolean includeDeleted) {
1819 checkCallerIsSystem();
1820 return mRankingHelper.getNotificationChannelGroups(pkg, uid, includeDeleted);
1824 public NotificationChannelGroup getNotificationChannelGroupForPackage(
1825 String groupId, String pkg, int uid) {
1826 enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
1827 return mRankingHelper.getNotificationChannelGroup(groupId, pkg, uid);
1831 public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
1832 checkCallerIsSystemOrSameApp(pkg);
1833 return mRankingHelper.getNotificationChannels(
1834 pkg, Binder.getCallingUid(), false /* includeDeleted */);
1838 public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
1839 checkCallerIsSystem();
1841 // Cancel posted notifications
1842 cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true,
1843 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
1845 // Listener & assistant
1846 mListeners.onPackagesChanged(true, new String[] {packageName});
1847 mNotificationAssistants.onPackagesChanged(true, new String[] {packageName});
1850 mConditionProviders.onPackagesChanged(true, new String[] {packageName});
1852 // Reset notification preferences
1854 mRankingHelper.onPackagesChanged(true, UserHandle.getCallingUserId(),
1855 new String[]{packageName}, new int[]{uid});
1863 * System-only API for getting a list of current (i.e. not cleared) notifications.
1865 * Requires ACCESS_NOTIFICATIONS which is signature|system.
1866 * @returns A list of all the notifications, in natural order.
1869 public StatusBarNotification[] getActiveNotifications(String callingPkg) {
1870 // enforce() will ensure the calling uid has the correct permission
1871 getContext().enforceCallingOrSelfPermission(
1872 android.Manifest.permission.ACCESS_NOTIFICATIONS,
1873 "NotificationManagerService.getActiveNotifications");
1875 StatusBarNotification[] tmp = null;
1876 int uid = Binder.getCallingUid();
1878 // noteOp will check to make sure the callingPkg matches the uid
1879 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1880 == AppOpsManager.MODE_ALLOWED) {
1881 synchronized (mNotificationLock) {
1882 tmp = new StatusBarNotification[mNotificationList.size()];
1883 final int N = mNotificationList.size();
1884 for (int i=0; i<N; i++) {
1885 tmp[i] = mNotificationList.get(i).sbn;
1893 * Public API for getting a list of current notifications for the calling package/uid.
1895 * Note that since notification posting is done asynchronously, this will not return
1896 * notifications that are in the process of being posted.
1898 * @returns A list of all the package's notifications, in natural order.
1901 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
1902 int incomingUserId) {
1903 checkCallerIsSystemOrSameApp(pkg);
1904 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1905 Binder.getCallingUid(), incomingUserId, true, false,
1906 "getAppActiveNotifications", pkg);
1907 synchronized (mNotificationLock) {
1908 final ArrayMap<String, StatusBarNotification> map
1909 = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
1910 final int N = mNotificationList.size();
1911 for (int i = 0; i < N; i++) {
1912 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
1913 mNotificationList.get(i).sbn);
1915 map.put(sbn.getKey(), sbn);
1918 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
1919 StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn);
1921 map.put(sbn.getKey(), sbn);
1924 final int M = mEnqueuedNotifications.size();
1925 for (int i = 0; i < M; i++) {
1926 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
1927 mEnqueuedNotifications.get(i).sbn);
1929 map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
1932 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
1933 list.addAll(map.values());
1934 return new ParceledListSlice<StatusBarNotification>(list);
1938 private StatusBarNotification sanitizeSbn(String pkg, int userId,
1939 StatusBarNotification sbn) {
1940 if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId
1941 && (sbn.getNotification().flags
1942 & Notification.FLAG_AUTOGROUP_SUMMARY) == 0) {
1943 // We could pass back a cloneLight() but clients might get confused and
1944 // try to send this thing back to notify() again, which would not work
1946 return new StatusBarNotification(
1947 sbn.getPackageName(),
1949 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
1950 sbn.getNotification().clone(),
1951 sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
1957 * System-only API for getting a list of recent (cleared, no longer shown) notifications.
1959 * Requires ACCESS_NOTIFICATIONS which is signature|system.
1962 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
1963 // enforce() will ensure the calling uid has the correct permission
1964 getContext().enforceCallingOrSelfPermission(
1965 android.Manifest.permission.ACCESS_NOTIFICATIONS,
1966 "NotificationManagerService.getHistoricalNotifications");
1968 StatusBarNotification[] tmp = null;
1969 int uid = Binder.getCallingUid();
1971 // noteOp will check to make sure the callingPkg matches the uid
1972 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1973 == AppOpsManager.MODE_ALLOWED) {
1974 synchronized (mArchive) {
1975 tmp = mArchive.getArray(count);
1982 * Register a listener binder directly with the notification manager.
1984 * Only works with system callers. Apps should extend
1985 * {@link android.service.notification.NotificationListenerService}.
1988 public void registerListener(final INotificationListener listener,
1989 final ComponentName component, final int userid) {
1990 enforceSystemOrSystemUI("INotificationManager.registerListener");
1991 mListeners.registerService(listener, component, userid);
1995 * Remove a listener binder directly
1998 public void unregisterListener(INotificationListener token, int userid) {
1999 mListeners.unregisterService(token, userid);
2003 * Allow an INotificationListener to simulate a "clear all" operation.
2005 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
2007 * @param token The binder for the listener, to check that the caller is allowed
2010 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
2011 final int callingUid = Binder.getCallingUid();
2012 final int callingPid = Binder.getCallingPid();
2013 long identity = Binder.clearCallingIdentity();
2015 synchronized (mNotificationLock) {
2016 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2018 final int N = keys.length;
2019 for (int i = 0; i < N; i++) {
2020 NotificationRecord r = mNotificationsByKey.get(keys[i]);
2021 if (r == null) continue;
2022 final int userId = r.sbn.getUserId();
2023 if (userId != info.userid && userId != UserHandle.USER_ALL &&
2024 !mUserProfiles.isCurrentProfile(userId)) {
2025 throw new SecurityException("Disallowed call from listener: "
2028 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2029 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
2033 cancelAllLocked(callingUid, callingPid, info.userid,
2034 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
2038 Binder.restoreCallingIdentity(identity);
2043 * Handle request from an approved listener to re-enable itself.
2045 * @param component The componenet to be re-enabled, caller must match package.
2048 public void requestBindListener(ComponentName component) {
2049 checkCallerIsSystemOrSameApp(component.getPackageName());
2050 long identity = Binder.clearCallingIdentity();
2052 ManagedServices manager =
2053 mNotificationAssistants.isComponentEnabledForCurrentProfiles(component)
2054 ? mNotificationAssistants
2056 manager.setComponentState(component, true);
2058 Binder.restoreCallingIdentity(identity);
2063 public void requestUnbindListener(INotificationListener token) {
2064 long identity = Binder.clearCallingIdentity();
2066 // allow bound services to disable themselves
2067 synchronized (mNotificationLock) {
2068 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2069 info.getOwner().setComponentState(info.component, false);
2072 Binder.restoreCallingIdentity(identity);
2077 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
2078 long identity = Binder.clearCallingIdentity();
2080 synchronized (mNotificationLock) {
2081 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2083 final int N = keys.length;
2084 for (int i = 0; i < N; i++) {
2085 NotificationRecord r = mNotificationsByKey.get(keys[i]);
2086 if (r == null) continue;
2087 final int userId = r.sbn.getUserId();
2088 if (userId != info.userid && userId != UserHandle.USER_ALL &&
2089 !mUserProfiles.isCurrentProfile(userId)) {
2090 throw new SecurityException("Disallowed call from listener: "
2094 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
2095 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
2096 userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM
2098 UsageEvents.Event.USER_INTERACTION);
2105 Binder.restoreCallingIdentity(identity);
2110 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2112 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2114 * @param info The binder for the listener, to check that the caller is allowed
2116 @GuardedBy("mNotificationLock")
2117 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
2118 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
2119 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
2120 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
2122 userId, REASON_LISTENER_CANCEL, info);
2126 * Allow an INotificationListener to snooze a single notification until a context.
2128 * @param token The binder for the listener, to check that the caller is allowed
2131 public void snoozeNotificationUntilContextFromListener(INotificationListener token,
2132 String key, String snoozeCriterionId) {
2133 long identity = Binder.clearCallingIdentity();
2135 synchronized (mNotificationLock) {
2136 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2137 snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info);
2140 Binder.restoreCallingIdentity(identity);
2145 * Allow an INotificationListener to snooze a single notification until a time.
2147 * @param token The binder for the listener, to check that the caller is allowed
2150 public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
2152 long identity = Binder.clearCallingIdentity();
2154 synchronized (mNotificationLock) {
2155 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2156 snoozeNotificationInt(key, duration, null, info);
2159 Binder.restoreCallingIdentity(identity);
2164 * Allows the notification assistant to un-snooze a single notification.
2166 * @param token The binder for the assistant, to check that the caller is allowed
2169 public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
2170 long identity = Binder.clearCallingIdentity();
2172 synchronized (mNotificationLock) {
2173 final ManagedServiceInfo info =
2174 mNotificationAssistants.checkServiceTokenLocked(token);
2175 unsnoozeNotificationInt(key, info);
2178 Binder.restoreCallingIdentity(identity);
2183 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2185 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2187 * @param token The binder for the listener, to check that the caller is allowed
2190 public void cancelNotificationFromListener(INotificationListener token, String pkg,
2191 String tag, int id) {
2192 final int callingUid = Binder.getCallingUid();
2193 final int callingPid = Binder.getCallingPid();
2194 long identity = Binder.clearCallingIdentity();
2196 synchronized (mNotificationLock) {
2197 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2198 if (info.supportsProfiles()) {
2199 Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
2200 + "from " + info.component
2201 + " use cancelNotification(key) instead.");
2203 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2204 pkg, tag, id, info.userid);
2208 Binder.restoreCallingIdentity(identity);
2213 * Allow an INotificationListener to request the list of outstanding notifications seen by
2214 * the current user. Useful when starting up, after which point the listener callbacks
2217 * @param token The binder for the listener, to check that the caller is allowed
2218 * @param keys An array of notification keys to fetch, or null to fetch everything
2219 * @returns The return value will contain the notifications specified in keys, in that
2220 * order, or if keys is null, all the notifications, in natural order.
2223 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
2224 INotificationListener token, String[] keys, int trim) {
2225 synchronized (mNotificationLock) {
2226 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2227 final boolean getKeys = keys != null;
2228 final int N = getKeys ? keys.length : mNotificationList.size();
2229 final ArrayList<StatusBarNotification> list
2230 = new ArrayList<StatusBarNotification>(N);
2231 for (int i=0; i<N; i++) {
2232 final NotificationRecord r = getKeys
2233 ? mNotificationsByKey.get(keys[i])
2234 : mNotificationList.get(i);
2235 if (r == null) continue;
2236 StatusBarNotification sbn = r.sbn;
2237 if (!isVisibleToListener(sbn, info)) continue;
2238 StatusBarNotification sbnToSend =
2239 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2240 list.add(sbnToSend);
2242 return new ParceledListSlice<StatusBarNotification>(list);
2247 * Allow an INotificationListener to request the list of outstanding snoozed notifications
2248 * seen by the current user. Useful when starting up, after which point the listener
2249 * callbacks should be used.
2251 * @param token The binder for the listener, to check that the caller is allowed
2252 * @returns The return value will contain the notifications specified in keys, in that
2253 * order, or if keys is null, all the notifications, in natural order.
2256 public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
2257 INotificationListener token, int trim) {
2258 synchronized (mNotificationLock) {
2259 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2260 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
2261 final int N = snoozedRecords.size();
2262 final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
2263 for (int i=0; i < N; i++) {
2264 final NotificationRecord r = snoozedRecords.get(i);
2265 if (r == null) continue;
2266 StatusBarNotification sbn = r.sbn;
2267 if (!isVisibleToListener(sbn, info)) continue;
2268 StatusBarNotification sbnToSend =
2269 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2270 list.add(sbnToSend);
2272 return new ParceledListSlice<>(list);
2277 public void requestHintsFromListener(INotificationListener token, int hints) {
2278 final long identity = Binder.clearCallingIdentity();
2280 synchronized (mNotificationLock) {
2281 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2282 final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
2283 | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
2284 | HINT_HOST_DISABLE_CALL_EFFECTS;
2285 final boolean disableEffects = (hints & disableEffectsMask) != 0;
2286 if (disableEffects) {
2287 addDisabledHints(info, hints);
2289 removeDisabledHints(info, hints);
2291 updateListenerHintsLocked();
2292 updateEffectsSuppressorLocked();
2295 Binder.restoreCallingIdentity(identity);
2300 public int getHintsFromListener(INotificationListener token) {
2301 synchronized (mNotificationLock) {
2302 return mListenerHints;
2307 public void requestInterruptionFilterFromListener(INotificationListener token,
2308 int interruptionFilter) throws RemoteException {
2309 final long identity = Binder.clearCallingIdentity();
2311 synchronized (mNotificationLock) {
2312 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2313 mZenModeHelper.requestFromListener(info.component, interruptionFilter);
2314 updateInterruptionFilterLocked();
2317 Binder.restoreCallingIdentity(identity);
2322 public int getInterruptionFilterFromListener(INotificationListener token)
2323 throws RemoteException {
2324 synchronized (mNotificationLight) {
2325 return mInterruptionFilter;
2330 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
2331 throws RemoteException {
2332 synchronized (mNotificationLock) {
2333 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2334 if (info == null) return;
2335 mListeners.setOnNotificationPostedTrimLocked(info, trim);
2340 public int getZenMode() {
2341 return mZenModeHelper.getZenMode();
2345 public ZenModeConfig getZenModeConfig() {
2346 enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
2347 return mZenModeHelper.getConfig();
2351 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
2352 enforceSystemOrSystemUI("INotificationManager.setZenMode");
2353 final long identity = Binder.clearCallingIdentity();
2355 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
2357 Binder.restoreCallingIdentity(identity);
2362 public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
2363 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
2364 return mZenModeHelper.getZenRules();
2368 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
2369 Preconditions.checkNotNull(id, "Id is null");
2370 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
2371 return mZenModeHelper.getAutomaticZenRule(id);
2375 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
2376 throws RemoteException {
2377 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2378 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2379 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2380 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2381 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
2383 return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
2384 "addAutomaticZenRule");
2388 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
2389 throws RemoteException {
2390 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2391 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2392 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2393 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2394 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
2396 return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
2397 "updateAutomaticZenRule");
2401 public boolean removeAutomaticZenRule(String id) throws RemoteException {
2402 Preconditions.checkNotNull(id, "Id is null");
2403 // Verify that they can modify zen rules.
2404 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
2406 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
2410 public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
2411 Preconditions.checkNotNull(packageName, "Package name is null");
2412 enforceSystemOrSystemUI("removeAutomaticZenRules");
2414 return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
2418 public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
2419 Preconditions.checkNotNull(owner, "Owner is null");
2420 enforceSystemOrSystemUI("getRuleInstanceCount");
2422 return mZenModeHelper.getCurrentInstanceCount(owner);
2426 public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
2427 enforcePolicyAccess(pkg, "setInterruptionFilter");
2428 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
2429 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
2430 final long identity = Binder.clearCallingIdentity();
2432 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
2434 Binder.restoreCallingIdentity(identity);
2439 public void notifyConditions(final String pkg, IConditionProvider provider,
2440 final Condition[] conditions) {
2441 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2442 checkCallerIsSystemOrSameApp(pkg);
2443 mHandler.post(new Runnable() {
2446 mConditionProviders.notifyConditions(pkg, info, conditions);
2452 public void requestUnbindProvider(IConditionProvider provider) {
2453 long identity = Binder.clearCallingIdentity();
2455 // allow bound services to disable themselves
2456 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2457 info.getOwner().setComponentState(info.component, false);
2459 Binder.restoreCallingIdentity(identity);
2464 public void requestBindProvider(ComponentName component) {
2465 checkCallerIsSystemOrSameApp(component.getPackageName());
2466 long identity = Binder.clearCallingIdentity();
2468 mConditionProviders.setComponentState(component, true);
2470 Binder.restoreCallingIdentity(identity);
2474 private void enforceSystemOrSystemUI(String message) {
2475 if (isCallerSystemOrPhone()) return;
2476 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
2480 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
2482 checkCallerIsSystemOrSameApp(pkg);
2483 } catch (SecurityException e) {
2484 getContext().enforceCallingPermission(
2485 android.Manifest.permission.STATUS_BAR_SERVICE,
2490 private void enforcePolicyAccess(int uid, String method) {
2491 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2492 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2495 boolean accessAllowed = false;
2496 String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
2497 final int packageCount = packages.length;
2498 for (int i = 0; i < packageCount; i++) {
2499 if (checkPolicyAccess(packages[i])) {
2500 accessAllowed = true;
2503 if (!accessAllowed) {
2504 Slog.w(TAG, "Notification policy access denied calling " + method);
2505 throw new SecurityException("Notification policy access denied");
2509 private void enforcePolicyAccess(String pkg, String method) {
2510 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2511 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2514 checkCallerIsSameApp(pkg);
2515 if (!checkPolicyAccess(pkg)) {
2516 Slog.w(TAG, "Notification policy access denied calling " + method);
2517 throw new SecurityException("Notification policy access denied");
2521 private boolean checkPackagePolicyAccess(String pkg) {
2522 return mPolicyAccess.isPackageGranted(pkg);
2525 private boolean checkPolicyAccess(String pkg) {
2527 int uid = getContext().getPackageManager().getPackageUidAsUser(
2528 pkg, UserHandle.getCallingUserId());
2529 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
2530 android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
2534 } catch (NameNotFoundException e) {
2537 return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
2541 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2542 if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
2543 final DumpFilter filter = DumpFilter.parseFromArguments(args);
2544 if (filter != null && filter.stats) {
2545 dumpJson(pw, filter);
2546 } else if (filter != null && filter.proto) {
2547 dumpProto(fd, filter);
2549 dumpImpl(pw, filter);
2554 public ComponentName getEffectsSuppressor() {
2555 return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
2559 public boolean matchesCallFilter(Bundle extras) {
2560 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
2561 return mZenModeHelper.matchesCallFilter(
2562 Binder.getCallingUserHandle(),
2564 mRankingHelper.findExtractor(ValidateNotificationPeople.class),
2565 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
2566 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
2570 public boolean isSystemConditionProviderEnabled(String path) {
2571 enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
2572 return mConditionProviders.isSystemProviderEnabled(path);
2575 // Backup/restore interface
2577 public byte[] getBackupPayload(int user) {
2578 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
2579 //TODO: http://b/22388012
2580 if (user != UserHandle.USER_SYSTEM) {
2581 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
2584 synchronized(mPolicyFile) {
2585 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
2587 writePolicyXml(baos, true /*forBackup*/);
2588 return baos.toByteArray();
2589 } catch (IOException e) {
2590 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
2597 public void applyRestore(byte[] payload, int user) {
2598 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
2599 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
2600 if (payload == null) {
2601 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
2604 //TODO: http://b/22388012
2605 if (user != UserHandle.USER_SYSTEM) {
2606 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
2609 synchronized(mPolicyFile) {
2610 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
2612 readPolicyXml(bais, true /*forRestore*/);
2614 } catch (NumberFormatException | XmlPullParserException | IOException e) {
2615 Slog.w(TAG, "applyRestore: error reading payload", e);
2621 public boolean isNotificationPolicyAccessGranted(String pkg) {
2622 return checkPolicyAccess(pkg);
2626 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
2627 enforceSystemOrSystemUIOrSamePackage(pkg,
2628 "request policy access status for another package");
2629 return checkPolicyAccess(pkg);
2633 public String[] getPackagesRequestingNotificationPolicyAccess()
2634 throws RemoteException {
2635 enforceSystemOrSystemUI("request policy access packages");
2636 final long identity = Binder.clearCallingIdentity();
2638 return mPolicyAccess.getRequestingPackages();
2640 Binder.restoreCallingIdentity(identity);
2645 public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
2646 throws RemoteException {
2647 enforceSystemOrSystemUI("grant notification policy access");
2648 final long identity = Binder.clearCallingIdentity();
2650 synchronized (mNotificationLock) {
2651 mPolicyAccess.put(pkg, granted);
2654 Binder.restoreCallingIdentity(identity);
2659 public Policy getNotificationPolicy(String pkg) {
2660 enforcePolicyAccess(pkg, "getNotificationPolicy");
2661 final long identity = Binder.clearCallingIdentity();
2663 return mZenModeHelper.getNotificationPolicy();
2665 Binder.restoreCallingIdentity(identity);
2670 public void setNotificationPolicy(String pkg, Policy policy) {
2671 enforcePolicyAccess(pkg, "setNotificationPolicy");
2672 final long identity = Binder.clearCallingIdentity();
2674 mZenModeHelper.setNotificationPolicy(policy);
2676 Binder.restoreCallingIdentity(identity);
2681 public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
2682 Adjustment adjustment) throws RemoteException {
2683 final long identity = Binder.clearCallingIdentity();
2685 synchronized (mNotificationLock) {
2686 mNotificationAssistants.checkServiceTokenLocked(token);
2687 int N = mEnqueuedNotifications.size();
2688 for (int i = 0; i < N; i++) {
2689 final NotificationRecord n = mEnqueuedNotifications.get(i);
2690 if (Objects.equals(adjustment.getKey(), n.getKey())
2691 && Objects.equals(adjustment.getUser(), n.getUserId())) {
2692 applyAdjustment(n, adjustment);
2698 Binder.restoreCallingIdentity(identity);
2703 public void applyAdjustmentFromAssistant(INotificationListener token,
2704 Adjustment adjustment) throws RemoteException {
2705 final long identity = Binder.clearCallingIdentity();
2707 synchronized (mNotificationLock) {
2708 mNotificationAssistants.checkServiceTokenLocked(token);
2709 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2710 applyAdjustment(n, adjustment);
2712 mRankingHandler.requestSort(true);
2714 Binder.restoreCallingIdentity(identity);
2719 public void applyAdjustmentsFromAssistant(INotificationListener token,
2720 List<Adjustment> adjustments) throws RemoteException {
2722 final long identity = Binder.clearCallingIdentity();
2724 synchronized (mNotificationLock) {
2725 mNotificationAssistants.checkServiceTokenLocked(token);
2726 for (Adjustment adjustment : adjustments) {
2727 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2728 applyAdjustment(n, adjustment);
2731 mRankingHandler.requestSort(true);
2733 Binder.restoreCallingIdentity(identity);
2738 public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
2739 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
2740 Preconditions.checkNotNull(channel);
2741 Preconditions.checkNotNull(pkg);
2742 Preconditions.checkNotNull(user);
2744 verifyPrivilegedListener(token, user);
2745 updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
2749 public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
2750 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
2751 Preconditions.checkNotNull(pkg);
2752 Preconditions.checkNotNull(user);
2753 verifyPrivilegedListener(token, user);
2755 return mRankingHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user),
2756 false /* includeDeleted */);
2760 public ParceledListSlice<NotificationChannelGroup>
2761 getNotificationChannelGroupsFromPrivilegedListener(
2762 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
2763 Preconditions.checkNotNull(pkg);
2764 Preconditions.checkNotNull(user);
2765 verifyPrivilegedListener(token, user);
2767 List<NotificationChannelGroup> groups = new ArrayList<>();
2768 groups.addAll(mRankingHelper.getNotificationChannelGroups(
2769 pkg, getUidForPackageAndUser(pkg, user)));
2770 return new ParceledListSlice<>(groups);
2773 private void verifyPrivilegedListener(INotificationListener token, UserHandle user) {
2774 ManagedServiceInfo info;
2775 synchronized (mNotificationLock) {
2776 info = mListeners.checkServiceTokenLocked(token);
2778 if (!hasCompanionDevice(info)) {
2779 throw new SecurityException(info + " does not have access");
2781 if (!info.enabledAndUserMatches(user.getIdentifier())) {
2782 throw new SecurityException(info + " does not have access");
2786 private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
2788 long identity = Binder.clearCallingIdentity();
2790 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
2792 Binder.restoreCallingIdentity(identity);
2798 private void applyAdjustment(NotificationRecord n, Adjustment adjustment) {
2802 if (adjustment.getSignals() != null) {
2803 Bundle.setDefusable(adjustment.getSignals(), true);
2804 final ArrayList<String> people =
2805 adjustment.getSignals().getStringArrayList(Adjustment.KEY_PEOPLE);
2806 final ArrayList<SnoozeCriterion> snoozeCriterionList =
2807 adjustment.getSignals().getParcelableArrayList(Adjustment.KEY_SNOOZE_CRITERIA);
2808 n.setPeopleOverride(people);
2809 n.setSnoozeCriteria(snoozeCriterionList);
2813 @GuardedBy("mNotificationLock")
2814 private void addAutogroupKeyLocked(String key) {
2815 NotificationRecord n = mNotificationsByKey.get(key);
2819 n.setOverrideGroupKey(GroupHelper.AUTOGROUP_KEY);
2820 EventLogTags.writeNotificationAutogrouped(key);
2823 @GuardedBy("mNotificationLock")
2824 private void removeAutogroupKeyLocked(String key) {
2825 NotificationRecord n = mNotificationsByKey.get(key);
2829 n.setOverrideGroupKey(null);
2830 EventLogTags.writeNotificationUnautogrouped(key);
2833 // Clears the 'fake' auto-group summary.
2834 @GuardedBy("mNotificationLock")
2835 private void clearAutogroupSummaryLocked(int userId, String pkg) {
2836 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
2837 if (summaries != null && summaries.containsKey(pkg)) {
2839 final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
2840 if (removed != null) {
2841 boolean wasPosted = removeFromNotificationListsLocked(removed);
2842 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED, wasPosted);
2847 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
2848 private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
2849 NotificationRecord summaryRecord = null;
2850 synchronized (mNotificationLock) {
2851 NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
2852 if (notificationRecord == null) {
2853 // The notification could have been cancelled again already. A successive
2854 // adjustment will post a summary if needed.
2857 final StatusBarNotification adjustedSbn = notificationRecord.sbn;
2858 userId = adjustedSbn.getUser().getIdentifier();
2859 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
2860 if (summaries == null) {
2861 summaries = new ArrayMap<>();
2863 mAutobundledSummaries.put(userId, summaries);
2864 if (!summaries.containsKey(pkg)) {
2866 final ApplicationInfo appInfo =
2867 adjustedSbn.getNotification().extras.getParcelable(
2868 Notification.EXTRA_BUILDER_APPLICATION_INFO);
2869 final Bundle extras = new Bundle();
2870 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
2871 final String channelId = notificationRecord.getChannel().getId();
2872 final Notification summaryNotification =
2873 new Notification.Builder(getContext(), channelId)
2874 .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
2875 .setGroupSummary(true)
2876 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN)
2877 .setGroup(GroupHelper.AUTOGROUP_KEY)
2878 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
2879 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
2880 .setColor(adjustedSbn.getNotification().color)
2883 summaryNotification.extras.putAll(extras);
2884 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
2885 if (appIntent != null) {
2886 summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
2887 getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
2889 final StatusBarNotification summarySbn =
2890 new StatusBarNotification(adjustedSbn.getPackageName(),
2891 adjustedSbn.getOpPkg(),
2893 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
2894 adjustedSbn.getInitialPid(), summaryNotification,
2895 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
2896 System.currentTimeMillis());
2897 summaryRecord = new NotificationRecord(getContext(), summarySbn,
2898 notificationRecord.getChannel());
2899 summaries.put(pkg, summarySbn.getKey());
2902 if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
2903 summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord)) {
2904 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
2908 private String disableNotificationEffects(NotificationRecord record) {
2909 if (mDisableNotificationEffects) {
2910 return "booleanState";
2912 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
2913 return "listenerHints";
2915 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
2921 private void dumpJson(PrintWriter pw, DumpFilter filter) {
2922 JSONObject dump = new JSONObject();
2924 dump.put("service", "Notification Manager");
2925 dump.put("bans", mRankingHelper.dumpBansJson(filter));
2926 dump.put("ranking", mRankingHelper.dumpJson(filter));
2927 dump.put("stats", mUsageStats.dumpJson(filter));
2928 dump.put("channels", mRankingHelper.dumpChannelsJson(filter));
2929 } catch (JSONException e) {
2930 e.printStackTrace();
2935 private void dumpProto(FileDescriptor fd, DumpFilter filter) {
2936 final ProtoOutputStream proto = new ProtoOutputStream(fd);
2937 synchronized (mNotificationLock) {
2938 long records = proto.start(NotificationServiceDumpProto.RECORDS);
2939 int N = mNotificationList.size();
2941 for (int i = 0; i < N; i++) {
2942 final NotificationRecord nr = mNotificationList.get(i);
2943 if (filter.filtered && !filter.matches(nr.sbn)) continue;
2944 nr.dump(proto, filter.redact);
2945 proto.write(NotificationRecordProto.STATE, NotificationServiceProto.POSTED);
2948 N = mEnqueuedNotifications.size();
2950 for (int i = 0; i < N; i++) {
2951 final NotificationRecord nr = mEnqueuedNotifications.get(i);
2952 if (filter.filtered && !filter.matches(nr.sbn)) continue;
2953 nr.dump(proto, filter.redact);
2954 proto.write(NotificationRecordProto.STATE, NotificationServiceProto.ENQUEUED);
2957 List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
2960 for (int i = 0; i < N; i++) {
2961 final NotificationRecord nr = snoozed.get(i);
2962 if (filter.filtered && !filter.matches(nr.sbn)) continue;
2963 nr.dump(proto, filter.redact);
2964 proto.write(NotificationRecordProto.STATE, NotificationServiceProto.SNOOZED);
2970 long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
2971 mZenModeHelper.dump(proto);
2972 for (ComponentName suppressor : mEffectsSuppressors) {
2973 proto.write(ZenModeProto.SUPPRESSORS, suppressor.toString());
2980 void dumpImpl(PrintWriter pw, DumpFilter filter) {
2981 pw.print("Current Notification Manager state");
2982 if (filter.filtered) {
2983 pw.print(" (filtered to "); pw.print(filter); pw.print(")");
2987 final boolean zenOnly = filter.filtered && filter.zen;
2990 synchronized (mToastQueue) {
2991 N = mToastQueue.size();
2993 pw.println(" Toast Queue:");
2994 for (int i=0; i<N; i++) {
2995 mToastQueue.get(i).dump(pw, " ", filter);
3002 synchronized (mNotificationLock) {
3004 N = mNotificationList.size();
3006 pw.println(" Notification List:");
3007 for (int i=0; i<N; i++) {
3008 final NotificationRecord nr = mNotificationList.get(i);
3009 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3010 nr.dump(pw, " ", getContext(), filter.redact);
3015 if (!filter.filtered) {
3018 pw.println(" Lights List:");
3019 for (int i=0; i<N; i++) {
3025 pw.println(mLights.get(i));
3029 pw.println(" mUseAttentionLight=" + mUseAttentionLight);
3030 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled);
3031 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey);
3032 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey);
3033 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects);
3034 pw.println(" mCallState=" + callStateToString(mCallState));
3035 pw.println(" mSystemReady=" + mSystemReady);
3036 pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
3038 pw.println(" mArchive=" + mArchive.toString());
3039 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
3041 while (iter.hasNext()) {
3042 final StatusBarNotification sbn = iter.next();
3043 if (filter != null && !filter.matches(sbn)) continue;
3044 pw.println(" " + sbn);
3046 if (iter.hasNext()) pw.println(" ...");
3052 N = mEnqueuedNotifications.size();
3054 pw.println(" Enqueued Notification List:");
3055 for (int i = 0; i < N; i++) {
3056 final NotificationRecord nr = mEnqueuedNotifications.get(i);
3057 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3058 nr.dump(pw, " ", getContext(), filter.redact);
3063 mSnoozeHelper.dump(pw, filter);
3068 pw.println("\n Ranking Config:");
3069 mRankingHelper.dump(pw, " ", filter);
3071 pw.println("\n Notification listeners:");
3072 mListeners.dump(pw, filter);
3073 pw.print(" mListenerHints: "); pw.println(mListenerHints);
3074 pw.print(" mListenersDisablingEffects: (");
3075 N = mListenersDisablingEffects.size();
3076 for (int i = 0; i < N; i++) {
3077 final int hint = mListenersDisablingEffects.keyAt(i);
3078 if (i > 0) pw.print(';');
3079 pw.print("hint[" + hint + "]:");
3081 final ArraySet<ManagedServiceInfo> listeners =
3082 mListenersDisablingEffects.valueAt(i);
3083 final int listenerSize = listeners.size();
3085 for (int j = 0; j < listenerSize; j++) {
3086 if (i > 0) pw.print(',');
3087 final ManagedServiceInfo listener = listeners.valueAt(i);
3088 pw.print(listener.component);
3092 pw.println("\n Notification assistant services:");
3093 mNotificationAssistants.dump(pw, filter);
3096 if (!filter.filtered || zenOnly) {
3097 pw.println("\n Zen Mode:");
3098 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter);
3099 mZenModeHelper.dump(pw, " ");
3101 pw.println("\n Zen Log:");
3102 ZenLog.dump(pw, " ");
3105 pw.println("\n Policy access:");
3106 pw.print(" mPolicyAccess: "); pw.println(mPolicyAccess);
3108 pw.println("\n Condition providers:");
3109 mConditionProviders.dump(pw, filter);
3111 pw.println("\n Group summaries:");
3112 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
3113 NotificationRecord r = entry.getValue();
3114 pw.println(" " + entry.getKey() + " -> " + r.getKey());
3115 if (mNotificationsByKey.get(r.getKey()) != r) {
3116 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
3117 r.dump(pw, " ", getContext(), filter.redact);
3122 pw.println("\n Usage Stats:");
3123 mUsageStats.dump(pw, " ", filter);
3129 * The private API only accessible to the system process.
3131 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
3133 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
3134 String tag, int id, Notification notification, int userId) {
3135 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
3140 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
3142 checkCallerIsSystem();
3143 mHandler.post(new Runnable() {
3146 synchronized (mNotificationLock) {
3147 removeForegroundServiceFlagByListLocked(
3148 mEnqueuedNotifications, pkg, notificationId, userId);
3149 removeForegroundServiceFlagByListLocked(
3150 mNotificationList, pkg, notificationId, userId);
3156 @GuardedBy("mNotificationLock")
3157 private void removeForegroundServiceFlagByListLocked(
3158 ArrayList<NotificationRecord> notificationList, String pkg, int notificationId,
3160 NotificationRecord r = findNotificationByListLocked(
3161 notificationList, pkg, null, notificationId, userId);
3165 StatusBarNotification sbn = r.sbn;
3166 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
3167 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
3168 // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
3169 // initially *and* force remove FLAG_FOREGROUND_SERVICE.
3170 sbn.getNotification().flags =
3171 (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
3172 mRankingHelper.sort(mNotificationList);
3173 mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
3174 mGroupHelper.onNotificationPosted(sbn);
3178 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
3179 final int callingPid, final String tag, final int id, final Notification notification,
3180 int incomingUserId) {
3182 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
3183 + " notification=" + notification);
3185 checkCallerIsSystemOrSameApp(pkg);
3187 final int userId = ActivityManager.handleIncomingUser(callingPid,
3188 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
3189 final UserHandle user = new UserHandle(userId);
3191 if (pkg == null || notification == null) {
3192 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
3193 + " id=" + id + " notification=" + notification);
3196 // The system can post notifications for any package, let us resolve that.
3197 final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);
3199 // Fix the notification as best we can.
3201 final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
3202 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
3203 (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
3204 Notification.addFieldsFromContext(ai, notification);
3206 boolean canColorize = PERMISSION_GRANTED == mPackageManagerClient.checkPermission(
3207 "com.android.permission.USE_COLORIZED_NOTIFICATIONS", pkg);
3209 notification.flags |= Notification.FLAG_CAN_COLORIZE;
3211 notification.flags &= ~Notification.FLAG_CAN_COLORIZE;
3214 } catch (NameNotFoundException e) {
3215 Slog.e(TAG, "Cannot create a context for sending app", e);
3219 mUsageStats.registerEnqueuedByApp(pkg);
3221 // setup local book-keeping
3222 String channelId = notification.getChannelId();
3223 if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
3224 channelId = (new Notification.TvExtender(notification)).getChannelId();
3226 final NotificationChannel channel = mRankingHelper.getNotificationChannel(pkg,
3227 notificationUid, channelId, false /* includeDeleted */);
3228 if (channel == null) {
3229 final String noChannelStr = "No Channel found for "
3231 + ", channelId=" + channelId
3234 + ", opPkg=" + opPkg
3235 + ", callingUid=" + callingUid
3236 + ", userId=" + userId
3237 + ", incomingUserId=" + incomingUserId
3238 + ", notificationUid=" + notificationUid
3239 + ", notification=" + notification;
3240 Log.e(TAG, noChannelStr);
3241 doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
3242 "Failed to post notification on channel \"" + channelId + "\"\n" +
3243 "See log for more details");
3247 final StatusBarNotification n = new StatusBarNotification(
3248 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
3249 user, null, System.currentTimeMillis());
3250 final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
3252 if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r)) {
3256 // Whitelist pending intents.
3257 if (notification.allPendingIntents != null) {
3258 final int intentCount = notification.allPendingIntents.size();
3259 if (intentCount > 0) {
3260 final ActivityManagerInternal am = LocalServices
3261 .getService(ActivityManagerInternal.class);
3262 final long duration = LocalServices.getService(
3263 DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
3264 for (int i = 0; i < intentCount; i++) {
3265 PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
3266 if (pendingIntent != null) {
3267 am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
3268 WHITELIST_TOKEN, duration);
3274 mHandler.post(new EnqueueNotificationRunnable(userId, r));
3277 private void doChannelWarningToast(CharSequence toastText) {
3278 final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
3279 final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
3280 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
3281 if (warningEnabled) {
3282 Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
3283 Toast.LENGTH_SHORT);
3288 private int resolveNotificationUid(String opPackageName, int callingUid, int userId) {
3289 // The system can post notifications on behalf of any package it wants
3290 if (isCallerSystemOrPhone() && opPackageName != null && !"android".equals(opPackageName)) {
3292 return getContext().getPackageManager()
3293 .getPackageUidAsUser(opPackageName, userId);
3294 } catch (NameNotFoundException e) {
3302 * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
3306 private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag,
3307 NotificationRecord r) {
3308 final String pkg = r.sbn.getPackageName();
3309 final String dialerPackage =
3310 getContext().getSystemService(TelecomManager.class).getSystemDialerPackage();
3311 final boolean isSystemNotification =
3312 isUidSystemOrPhone(callingUid) || ("android".equals(pkg))
3313 || TextUtils.equals(pkg, dialerPackage);
3314 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
3316 // Limit the number of notifications that any given package except the android
3317 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
3318 if (!isSystemNotification && !isNotificationFromListener) {
3319 synchronized (mNotificationLock) {
3320 if (mNotificationsByKey.get(r.sbn.getKey()) == null && isCallerInstantApp(pkg)) {
3321 // Ephemeral apps have some special constraints for notifications.
3322 // They are not allowed to create new notifications however they are allowed to
3323 // update notifications created by the system (e.g. a foreground service
3325 throw new SecurityException("Instant app " + pkg
3326 + " cannot create notifications");
3329 // rate limit updates that aren't completed progress notifications
3330 if (mNotificationsByKey.get(r.sbn.getKey()) != null
3331 && !r.getNotification().hasCompletedProgress()) {
3333 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
3334 if (appEnqueueRate > mMaxPackageEnqueueRate) {
3335 mUsageStats.registerOverRateQuota(pkg);
3336 final long now = SystemClock.elapsedRealtime();
3337 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
3338 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
3339 + ". Shedding events. package=" + pkg);
3340 mLastOverRateLogTime = now;
3346 // limit the number of outstanding notificationrecords an app can have
3347 int count = getNotificationCountLocked(pkg, userId, id, tag);
3348 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
3349 mUsageStats.registerOverCountQuota(pkg);
3350 Slog.e(TAG, "Package has already posted or enqueued " + count
3351 + " notifications. Not showing more. package=" + pkg);
3358 if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
3359 MetricsLogger.action(r.getLogMaker()
3360 .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
3361 .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
3363 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
3365 mSnoozeHelper.update(userId, r);
3372 if (isBlocked(r, mUsageStats)) {
3379 protected int getNotificationCountLocked(String pkg, int userId, int excludedId,
3380 String excludedTag) {
3382 final int N = mNotificationList.size();
3383 for (int i = 0; i < N; i++) {
3384 final NotificationRecord existing = mNotificationList.get(i);
3385 if (existing.sbn.getPackageName().equals(pkg)
3386 && existing.sbn.getUserId() == userId) {
3387 if (existing.sbn.getId() == excludedId
3388 && TextUtils.equals(existing.sbn.getTag(), excludedTag)) {
3394 final int M = mEnqueuedNotifications.size();
3395 for (int i = 0; i < M; i++) {
3396 final NotificationRecord existing = mEnqueuedNotifications.get(i);
3397 if (existing.sbn.getPackageName().equals(pkg)
3398 && existing.sbn.getUserId() == userId) {
3405 protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
3406 final String pkg = r.sbn.getPackageName();
3407 final int callingUid = r.sbn.getUid();
3409 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
3410 if (isPackageSuspended) {
3411 Slog.e(TAG, "Suppressing notification from package due to package "
3412 + "suspended by administrator.");
3413 usageStats.registerSuspendedByAdmin(r);
3414 return isPackageSuspended;
3417 final boolean isBlocked =
3418 mRankingHelper.getImportance(pkg, callingUid) == NotificationManager.IMPORTANCE_NONE
3419 || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE;
3421 Slog.e(TAG, "Suppressing notification from package by user request.");
3422 usageStats.registerBlocked(r);
3427 protected class SnoozeNotificationRunnable implements Runnable {
3428 private final String mKey;
3429 private final long mDuration;
3430 private final String mSnoozeCriterionId;
3432 SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) {
3434 mDuration = duration;
3435 mSnoozeCriterionId = snoozeCriterionId;
3440 synchronized (mNotificationLock) {
3441 final NotificationRecord r = findNotificationByKeyLocked(mKey);
3448 @GuardedBy("mNotificationLock")
3449 void snoozeLocked(NotificationRecord r) {
3450 if (r.sbn.isGroup()) {
3451 final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked(
3452 r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId());
3453 if (r.getNotification().isGroupSummary()) {
3454 // snooze summary and all children
3455 for (int i = 0; i < groupNotifications.size(); i++) {
3456 snoozeNotificationLocked(groupNotifications.get(i));
3459 // if there is a valid summary for this group, and we are snoozing the only
3460 // child, also snooze the summary
3461 if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) {
3462 if (groupNotifications.size() != 2) {
3463 snoozeNotificationLocked(r);
3465 // snooze summary and the one child
3466 for (int i = 0; i < groupNotifications.size(); i++) {
3467 snoozeNotificationLocked(groupNotifications.get(i));
3471 snoozeNotificationLocked(r);
3475 // just snooze the one notification
3476 snoozeNotificationLocked(r);
3480 @GuardedBy("mNotificationLock")
3481 void snoozeNotificationLocked(NotificationRecord r) {
3482 MetricsLogger.action(r.getLogMaker()
3483 .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
3484 .setType(MetricsEvent.TYPE_CLOSE)
3485 .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
3486 mSnoozeCriterionId == null ? 0 : 1));
3487 boolean wasPosted = removeFromNotificationListsLocked(r);
3488 cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted);
3489 updateLightsLocked();
3490 if (mSnoozeCriterionId != null) {
3491 mNotificationAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
3492 mSnoozeHelper.snooze(r);
3494 mSnoozeHelper.snooze(r, mDuration);
3500 protected class EnqueueNotificationRunnable implements Runnable {
3501 private final NotificationRecord r;
3502 private final int userId;
3504 EnqueueNotificationRunnable(int userId, NotificationRecord r) {
3505 this.userId = userId;
3511 synchronized (mNotificationLock) {
3512 mEnqueuedNotifications.add(r);
3513 scheduleTimeoutLocked(r);
3515 final StatusBarNotification n = r.sbn;
3516 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
3517 NotificationRecord old = mNotificationsByKey.get(n.getKey());
3519 // Retain ranking information from previous record
3520 r.copyRankingInformation(old);
3523 final int callingUid = n.getUid();
3524 final int callingPid = n.getInitialPid();
3525 final Notification notification = n.getNotification();
3526 final String pkg = n.getPackageName();
3527 final int id = n.getId();
3528 final String tag = n.getTag();
3530 // Handle grouped notifications and bail out early if we
3531 // can to avoid extracting signals.
3532 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
3534 // if this is a group child, unsnooze parent summary
3535 if (n.isGroup() && notification.isGroupChild()) {
3536 mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
3539 // This conditional is a dirty hack to limit the logging done on
3540 // behalf of the download manager without affecting other apps.
3541 if (!pkg.equals("com.android.providers.downloads")
3542 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
3543 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
3545 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
3547 EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
3548 pkg, id, tag, userId, notification.toString(),
3552 mRankingHelper.extractSignals(r);
3554 // tell the assistant service about the notification
3555 if (mNotificationAssistants.isEnabled()) {
3556 mNotificationAssistants.onNotificationEnqueued(r);
3557 mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
3558 DELAY_FOR_ASSISTANT_TIME);
3560 mHandler.post(new PostNotificationRunnable(r.getKey()));
3566 protected class PostNotificationRunnable implements Runnable {
3567 private final String key;
3569 PostNotificationRunnable(String key) {
3575 synchronized (mNotificationLock) {
3577 NotificationRecord r = null;
3578 int N = mEnqueuedNotifications.size();
3579 for (int i = 0; i < N; i++) {
3580 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
3581 if (Objects.equals(key, enqueued.getKey())) {
3587 Slog.i(TAG, "Cannot find enqueued record for key: " + key);
3590 NotificationRecord old = mNotificationsByKey.get(key);
3591 final StatusBarNotification n = r.sbn;
3592 final Notification notification = n.getNotification();
3593 int index = indexOfNotificationLocked(n.getKey());
3595 mNotificationList.add(r);
3596 mUsageStats.registerPostedByApp(r);
3598 old = mNotificationList.get(index);
3599 mNotificationList.set(index, r);
3600 mUsageStats.registerUpdatedByApp(r, old);
3601 // Make sure we don't lose the foreground service state.
3602 notification.flags |=
3603 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
3607 mNotificationsByKey.put(n.getKey(), r);
3609 // Ensure if this is a foreground service that the proper additional
3611 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
3612 notification.flags |= Notification.FLAG_ONGOING_EVENT
3613 | Notification.FLAG_NO_CLEAR;
3616 applyZenModeLocked(r);
3617 mRankingHelper.sort(mNotificationList);
3619 if (notification.getSmallIcon() != null) {
3620 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
3621 mListeners.notifyPostedLocked(n, oldSbn);
3622 mHandler.post(new Runnable() {
3625 mGroupHelper.onNotificationPosted(n);
3629 Slog.e(TAG, "Not posting notification without small icon: " + notification);
3630 if (old != null && !old.isCanceled) {
3631 mListeners.notifyRemovedLocked(n,
3632 NotificationListenerService.REASON_ERROR);
3633 mHandler.post(new Runnable() {
3636 mGroupHelper.onNotificationRemoved(n);
3640 // ATTENTION: in a future release we will bail out here
3641 // so that we do not play sounds, show lights, etc. for invalid
3643 Slog.e(TAG, "WARNING: In a future release this will crash the app: "
3644 + n.getPackageName());
3647 buzzBeepBlinkLocked(r);
3649 int N = mEnqueuedNotifications.size();
3650 for (int i = 0; i < N; i++) {
3651 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
3652 if (Objects.equals(key, enqueued.getKey())) {
3653 mEnqueuedNotifications.remove(i);
3663 * Ensures that grouped notification receive their special treatment.
3665 * <p>Cancels group children if the new notification causes a group to lose
3668 * <p>Updates mSummaryByGroupKey.</p>
3670 @GuardedBy("mNotificationLock")
3671 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
3672 int callingUid, int callingPid) {
3673 StatusBarNotification sbn = r.sbn;
3674 Notification n = sbn.getNotification();
3675 if (n.isGroupSummary() && !sbn.isAppGroup()) {
3676 // notifications without a group shouldn't be a summary, otherwise autobundling can
3678 n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
3681 String group = sbn.getGroupKey();
3682 boolean isSummary = n.isGroupSummary();
3684 Notification oldN = old != null ? old.sbn.getNotification() : null;
3685 String oldGroup = old != null ? old.sbn.getGroupKey() : null;
3686 boolean oldIsSummary = old != null && oldN.isGroupSummary();
3689 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
3690 if (removedSummary != old) {
3692 removedSummary != null ? removedSummary.getKey() : "<null>";
3693 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
3694 ", removed=" + removedKey);
3698 mSummaryByGroupKey.put(group, r);
3701 // Clear out group children of the old notification if the update
3702 // causes the group summary to go away. This happens when the old
3703 // notification was a summary and the new one isn't, or when the old
3704 // notification was a summary and its group key changed.
3705 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
3706 cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */);
3711 @GuardedBy("mNotificationLock")
3712 void scheduleTimeoutLocked(NotificationRecord record) {
3713 if (record.getNotification().getTimeoutAfter() > 0) {
3714 final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
3715 REQUEST_CODE_TIMEOUT,
3716 new Intent(ACTION_NOTIFICATION_TIMEOUT)
3717 .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
3718 .appendPath(record.getKey()).build())
3719 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
3720 .putExtra(EXTRA_KEY, record.getKey()),
3721 PendingIntent.FLAG_UPDATE_CURRENT);
3722 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
3723 SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
3728 @GuardedBy("mNotificationLock")
3729 void buzzBeepBlinkLocked(NotificationRecord record) {
3730 boolean buzz = false;
3731 boolean beep = false;
3732 boolean blink = false;
3734 final Notification notification = record.sbn.getNotification();
3735 final String key = record.getKey();
3737 // Should this notification make noise, vibe, or use the LED?
3738 final boolean aboveThreshold =
3739 record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
3741 // Remember if this notification already owns the notification channels.
3742 boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
3743 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
3744 // These are set inside the conditional if the notification is allowed to make noise.
3745 boolean hasValidVibrate = false;
3746 boolean hasValidSound = false;
3748 if (isNotificationForCurrentUser(record)) {
3749 // If the notification icon will appear in the status bar, AND it hasn't been blocked
3750 // by do-not-disturb, it should generate an accessibility event
3751 if (!record.isUpdate
3752 && !record.isIntercepted()
3753 && record.getImportance() > IMPORTANCE_MIN) {
3754 sendAccessibilityEvent(notification, record.sbn.getPackageName());
3756 if (aboveThreshold && mSystemReady && mAudioManager != null) {
3757 // this notification wants to make noise & is allowed to make noise
3758 Uri soundUri = record.getSound();
3759 hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
3761 long[] vibration = record.getVibration();
3762 // Demote sound to vibration if vibration missing & phone in vibration mode.
3763 if (vibration == null
3765 && (mAudioManager.getRingerModeInternal()
3766 == AudioManager.RINGER_MODE_VIBRATE)) {
3767 vibration = mFallbackVibrationPattern;
3769 hasValidVibrate = vibration != null;
3771 boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
3773 if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
3774 if (DBG) Slog.v(TAG, "Interrupting!");
3775 if (hasValidSound) {
3776 mSoundNotificationKey = key;
3778 playInCallNotification();
3781 beep = playSound(record, soundUri);
3785 final boolean ringerModeSilent =
3786 mAudioManager.getRingerModeInternal()
3787 == AudioManager.RINGER_MODE_SILENT;
3788 if (!mInCall && hasValidVibrate && !ringerModeSilent) {
3789 mVibrateNotificationKey = key;
3791 buzz = playVibration(record, vibration, hasValidSound);
3796 // If a notification is updated to remove the actively playing sound or vibrate,
3797 // cancel that feedback now
3798 if (wasBeep && !hasValidSound) {
3801 if (wasBuzz && !hasValidVibrate) {
3802 clearVibrateLocked();
3806 // release the light
3807 boolean wasShowLights = mLights.remove(key);
3808 if (record.getLight() != null && aboveThreshold
3809 && ((record.getSuppressedVisualEffects()
3810 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
3812 updateLightsLocked();
3813 if (mUseAttentionLight) {
3814 mAttentionLight.pulse();
3817 } else if (wasShowLights) {
3818 updateLightsLocked();
3820 if (buzz || beep || blink) {
3821 MetricsLogger.action(record.getLogMaker()
3822 .setCategory(MetricsEvent.NOTIFICATION_ALERT)
3823 .setType(MetricsEvent.TYPE_OPEN)
3824 .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
3825 EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
3829 @GuardedBy("mNotificationLock")
3830 boolean shouldMuteNotificationLocked(final NotificationRecord record) {
3831 // Suppressed because it's a silent update
3832 final Notification notification = record.getNotification();
3834 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
3838 // muted by listener
3839 final String disableEffects = disableNotificationEffects(record);
3840 if (disableEffects != null) {
3841 ZenLog.traceDisableEffects(record, disableEffects);
3845 // suppressed due to DND
3846 if (record.isIntercepted()) {
3850 // Suppressed because another notification in its group handles alerting
3851 if (record.sbn.isGroup()) {
3852 return notification.suppressAlertingDueToGrouping();
3855 // Suppressed for being too recently noisy
3856 final String pkg = record.sbn.getPackageName();
3857 if (mUsageStats.isAlertRateLimited(pkg)) {
3858 Slog.e(TAG, "Muting recently noisy " + record.getKey());
3865 private boolean playSound(final NotificationRecord record, Uri soundUri) {
3866 boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
3867 // do not play notifications if there is a user of exclusive audio focus
3868 // or the device is in vibrate mode
3869 if (!mAudioManager.isAudioFocusExclusive() && mAudioManager.getRingerModeInternal()
3870 != AudioManager.RINGER_MODE_VIBRATE) {
3871 final long identity = Binder.clearCallingIdentity();
3873 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
3874 if (player != null) {
3875 if (DBG) Slog.v(TAG, "Playing sound " + soundUri
3876 + " with attributes " + record.getAudioAttributes());
3877 player.playAsync(soundUri, record.sbn.getUser(), looping,
3878 record.getAudioAttributes());
3881 } catch (RemoteException e) {
3883 Binder.restoreCallingIdentity(identity);
3889 private boolean playVibration(final NotificationRecord record, long[] vibration,
3890 boolean delayVibForSound) {
3891 // Escalate privileges so we can use the vibrator even if the
3892 // notifying app does not have the VIBRATE permission.
3893 long identity = Binder.clearCallingIdentity();
3895 final VibrationEffect effect;
3897 final boolean insistent =
3898 (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
3899 effect = VibrationEffect.createWaveform(
3900 vibration, insistent ? 0 : -1 /*repeatIndex*/);
3901 } catch (IllegalArgumentException e) {
3902 Slog.e(TAG, "Error creating vibration waveform with pattern: " +
3903 Arrays.toString(vibration));
3906 if (delayVibForSound) {
3908 // delay the vibration by the same amount as the notification sound
3909 final int waitMs = mAudioManager.getFocusRampTimeMs(
3910 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
3911 record.getAudioAttributes());
3912 if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms");
3914 Thread.sleep(waitMs);
3915 } catch (InterruptedException e) { }
3916 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
3917 effect, record.getAudioAttributes());
3920 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
3921 effect, record.getAudioAttributes());
3925 Binder.restoreCallingIdentity(identity);
3929 private boolean isNotificationForCurrentUser(NotificationRecord record) {
3930 final int currentUser;
3931 final long token = Binder.clearCallingIdentity();
3933 currentUser = ActivityManager.getCurrentUser();
3935 Binder.restoreCallingIdentity(token);
3937 return (record.getUserId() == UserHandle.USER_ALL ||
3938 record.getUserId() == currentUser ||
3939 mUserProfiles.isCurrentProfile(record.getUserId()));
3942 private void playInCallNotification() {
3946 // If toneGenerator creation fails, just continue the call
3947 // without playing the notification sound.
3949 synchronized (mInCallToneGeneratorLock) {
3950 if (mInCallToneGenerator != null) {
3951 // limit this tone to 1 second; BEEP2 should in fact be much shorter
3952 mInCallToneGenerator.startTone(ToneGenerator.TONE_PROP_BEEP2, 1000);
3955 } catch (RuntimeException e) {
3956 Log.w(TAG, "Exception from ToneGenerator: " + e);
3962 @GuardedBy("mToastQueue")
3963 void showNextToastLocked() {
3964 ToastRecord record = mToastQueue.get(0);
3965 while (record != null) {
3966 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
3968 record.callback.show(record.token);
3969 scheduleTimeoutLocked(record);
3971 } catch (RemoteException e) {
3972 Slog.w(TAG, "Object died trying to show notification " + record.callback
3973 + " in package " + record.pkg);
3974 // remove it from the list and let the process die
3975 int index = mToastQueue.indexOf(record);
3977 mToastQueue.remove(index);
3979 keepProcessAliveIfNeededLocked(record.pid);
3980 if (mToastQueue.size() > 0) {
3981 record = mToastQueue.get(0);
3989 @GuardedBy("mToastQueue")
3990 void cancelToastLocked(int index) {
3991 ToastRecord record = mToastQueue.get(index);
3993 record.callback.hide();
3994 } catch (RemoteException e) {
3995 Slog.w(TAG, "Object died trying to hide notification " + record.callback
3996 + " in package " + record.pkg);
3997 // don't worry about this, we're about to remove it from
4001 ToastRecord lastToast = mToastQueue.remove(index);
4002 mWindowManagerInternal.removeWindowToken(lastToast.token, true, DEFAULT_DISPLAY);
4004 keepProcessAliveIfNeededLocked(record.pid);
4005 if (mToastQueue.size() > 0) {
4006 // Show the next one. If the callback fails, this will remove
4007 // it from the list, so don't assume that the list hasn't changed
4008 // after this point.
4009 showNextToastLocked();
4013 @GuardedBy("mToastQueue")
4014 private void scheduleTimeoutLocked(ToastRecord r)
4016 mHandler.removeCallbacksAndMessages(r);
4017 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
4018 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
4019 mHandler.sendMessageDelayed(m, delay);
4022 private void handleTimeout(ToastRecord record)
4024 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
4025 synchronized (mToastQueue) {
4026 int index = indexOfToastLocked(record.pkg, record.callback);
4028 cancelToastLocked(index);
4033 @GuardedBy("mToastQueue")
4034 int indexOfToastLocked(String pkg, ITransientNotification callback)
4036 IBinder cbak = callback.asBinder();
4037 ArrayList<ToastRecord> list = mToastQueue;
4038 int len = list.size();
4039 for (int i=0; i<len; i++) {
4040 ToastRecord r = list.get(i);
4041 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
4048 @GuardedBy("mToastQueue")
4049 void keepProcessAliveIfNeededLocked(int pid)
4051 int toastCount = 0; // toasts from this pid
4052 ArrayList<ToastRecord> list = mToastQueue;
4053 int N = list.size();
4054 for (int i=0; i<N; i++) {
4055 ToastRecord r = list.get(i);
4061 mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
4062 } catch (RemoteException e) {
4063 // Shouldn't happen.
4067 private void handleRankingReconsideration(Message message) {
4068 if (!(message.obj instanceof RankingReconsideration)) return;
4069 RankingReconsideration recon = (RankingReconsideration) message.obj;
4072 synchronized (mNotificationLock) {
4073 final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
4074 if (record == null) {
4077 int indexBefore = findNotificationRecordIndexLocked(record);
4078 boolean interceptBefore = record.isIntercepted();
4079 float contactAffinityBefore = record.getContactAffinity();
4080 int visibilityBefore = record.getPackageVisibilityOverride();
4081 recon.applyChangesLocked(record);
4082 applyZenModeLocked(record);
4083 mRankingHelper.sort(mNotificationList);
4084 int indexAfter = findNotificationRecordIndexLocked(record);
4085 boolean interceptAfter = record.isIntercepted();
4086 float contactAffinityAfter = record.getContactAffinity();
4087 int visibilityAfter = record.getPackageVisibilityOverride();
4088 changed = indexBefore != indexAfter || interceptBefore != interceptAfter
4089 || visibilityBefore != visibilityAfter;
4090 if (interceptBefore && !interceptAfter
4091 && Float.compare(contactAffinityBefore, contactAffinityAfter) != 0) {
4092 buzzBeepBlinkLocked(record);
4096 scheduleSendRankingUpdate();
4100 private void handleRankingSort(Message msg) {
4101 if (!(msg.obj instanceof Boolean)) return;
4102 if (mRankingHelper == null) return;
4103 boolean forceUpdate = ((Boolean) msg.obj == null) ? false : (boolean) msg.obj;
4104 synchronized (mNotificationLock) {
4105 final int N = mNotificationList.size();
4106 // Any field that can change via one of the extractors or by the assistant
4107 // needs to be added here.
4108 ArrayList<String> orderBefore = new ArrayList<String>(N);
4109 ArrayList<String> groupOverrideBefore = new ArrayList<>(N);
4110 int[] visibilities = new int[N];
4111 boolean[] showBadges = new boolean[N];
4112 for (int i = 0; i < N; i++) {
4113 final NotificationRecord r = mNotificationList.get(i);
4114 orderBefore.add(r.getKey());
4115 groupOverrideBefore.add(r.sbn.getGroupKey());
4116 visibilities[i] = r.getPackageVisibilityOverride();
4117 showBadges[i] = r.canShowBadge();
4118 mRankingHelper.extractSignals(r);
4120 mRankingHelper.sort(mNotificationList);
4121 for (int i = 0; i < N; i++) {
4122 final NotificationRecord r = mNotificationList.get(i);
4124 || !orderBefore.get(i).equals(r.getKey())
4125 || visibilities[i] != r.getPackageVisibilityOverride()
4126 || !groupOverrideBefore.get(i).equals(r.sbn.getGroupKey())
4127 || showBadges[i] != r.canShowBadge()) {
4128 scheduleSendRankingUpdate();
4135 @GuardedBy("mNotificationLock")
4136 private void recordCallerLocked(NotificationRecord record) {
4137 if (mZenModeHelper.isCall(record)) {
4138 mZenModeHelper.recordCaller(record);
4142 // let zen mode evaluate this record
4143 @GuardedBy("mNotificationLock")
4144 private void applyZenModeLocked(NotificationRecord record) {
4145 record.setIntercepted(mZenModeHelper.shouldIntercept(record));
4146 if (record.isIntercepted()) {
4147 int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
4148 ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
4149 | (mZenModeHelper.shouldSuppressWhenScreenOn()
4150 ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
4151 record.setSuppressedVisualEffects(suppressed);
4153 record.setSuppressedVisualEffects(0);
4157 @GuardedBy("mNotificationLock")
4158 private int findNotificationRecordIndexLocked(NotificationRecord target) {
4159 return mRankingHelper.indexOf(mNotificationList, target);
4162 private void scheduleSendRankingUpdate() {
4163 if (!mHandler.hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
4164 Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE);
4165 mHandler.sendMessage(m);
4169 private void handleSendRankingUpdate() {
4170 synchronized (mNotificationLock) {
4171 mListeners.notifyRankingUpdateLocked();
4175 private void scheduleListenerHintsChanged(int state) {
4176 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
4177 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
4180 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
4181 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
4182 mHandler.obtainMessage(
4183 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
4184 listenerInterruptionFilter,
4188 private void handleListenerHintsChanged(int hints) {
4189 synchronized (mNotificationLock) {
4190 mListeners.notifyListenerHintsChangedLocked(hints);
4194 private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
4195 synchronized (mNotificationLock) {
4196 mListeners.notifyInterruptionFilterChanged(interruptionFilter);
4200 private final class WorkerHandler extends Handler
4202 public WorkerHandler(Looper looper) {
4207 public void handleMessage(Message msg)
4211 case MESSAGE_TIMEOUT:
4212 handleTimeout((ToastRecord)msg.obj);
4214 case MESSAGE_SAVE_POLICY_FILE:
4215 handleSavePolicyFile();
4217 case MESSAGE_SEND_RANKING_UPDATE:
4218 handleSendRankingUpdate();
4220 case MESSAGE_LISTENER_HINTS_CHANGED:
4221 handleListenerHintsChanged(msg.arg1);
4223 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
4224 handleListenerInterruptionFilterChanged(msg.arg1);
4231 private final class RankingHandlerWorker extends Handler implements RankingHandler
4233 public RankingHandlerWorker(Looper looper) {
4238 public void handleMessage(Message msg) {
4240 case MESSAGE_RECONSIDER_RANKING:
4241 handleRankingReconsideration(msg);
4243 case MESSAGE_RANKING_SORT:
4244 handleRankingSort(msg);
4249 public void requestSort(boolean forceUpdate) {
4250 removeMessages(MESSAGE_RANKING_SORT);
4251 Message msg = Message.obtain();
4252 msg.what = MESSAGE_RANKING_SORT;
4253 msg.obj = forceUpdate;
4257 public void requestReconsideration(RankingReconsideration recon) {
4258 Message m = Message.obtain(this,
4259 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
4260 long delay = recon.getDelay(TimeUnit.MILLISECONDS);
4261 sendMessageDelayed(m, delay);
4266 // ============================================================================
4267 static int clamp(int x, int low, int high) {
4268 return (x < low) ? low : ((x > high) ? high : x);
4272 void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
4273 final AccessibilityManager accessibilityManager
4274 = AccessibilityManager.getInstance(getContext());
4275 if (accessibilityManager == null || !accessibilityManager.isEnabled()) {
4279 AccessibilityEvent event =
4280 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
4281 event.setPackageName(packageName);
4282 event.setClassName(Notification.class.getName());
4283 event.setParcelableData(notification);
4284 CharSequence tickerText = notification.tickerText;
4285 if (!TextUtils.isEmpty(tickerText)) {
4286 event.getText().add(tickerText);
4289 accessibilityManager.sendAccessibilityEvent(event);
4293 * Removes all NotificationsRecords with the same key as the given notification record
4294 * from both lists. Do not call this method while iterating over either list.
4296 @GuardedBy("mNotificationLock")
4297 private boolean removeFromNotificationListsLocked(NotificationRecord r) {
4298 // Remove from both lists, either list could have a separate Record for what is
4299 // effectively the same notification.
4300 boolean wasPosted = false;
4301 NotificationRecord recordInList = null;
4302 if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))
4304 mNotificationList.remove(recordInList);
4305 mNotificationsByKey.remove(recordInList.sbn.getKey());
4308 while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
4310 mEnqueuedNotifications.remove(recordInList);
4315 @GuardedBy("mNotificationLock")
4316 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
4317 boolean wasPosted) {
4318 final String canceledKey = r.getKey();
4321 recordCallerLocked(r);
4325 if (r.getNotification().deleteIntent != null) {
4327 r.getNotification().deleteIntent.send();
4328 } catch (PendingIntent.CanceledException ex) {
4329 // do nothing - there's no relevant way to recover, and
4330 // no reason to let this propagate
4331 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
4336 // Only cancel these if this notification actually got to be posted.
4339 if (r.getNotification().getSmallIcon() != null) {
4340 if (reason != REASON_SNOOZED) {
4341 r.isCanceled = true;
4343 mListeners.notifyRemovedLocked(r.sbn, reason);
4344 mHandler.post(new Runnable() {
4347 mGroupHelper.onNotificationRemoved(r.sbn);
4353 if (canceledKey.equals(mSoundNotificationKey)) {
4354 mSoundNotificationKey = null;
4355 final long identity = Binder.clearCallingIdentity();
4357 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4358 if (player != null) {
4361 } catch (RemoteException e) {
4363 Binder.restoreCallingIdentity(identity);
4368 if (canceledKey.equals(mVibrateNotificationKey)) {
4369 mVibrateNotificationKey = null;
4370 long identity = Binder.clearCallingIdentity();
4375 Binder.restoreCallingIdentity(identity);
4380 mLights.remove(canceledKey);
4383 // Record usage stats
4384 // TODO: add unbundling stats?
4387 case REASON_CANCEL_ALL:
4388 case REASON_LISTENER_CANCEL:
4389 case REASON_LISTENER_CANCEL_ALL:
4390 mUsageStats.registerDismissedByUser(r);
4392 case REASON_APP_CANCEL:
4393 case REASON_APP_CANCEL_ALL:
4394 mUsageStats.registerRemovedByApp(r);
4398 String groupKey = r.getGroupKey();
4399 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
4400 if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
4401 mSummaryByGroupKey.remove(groupKey);
4403 final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
4404 if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
4405 summaries.remove(r.sbn.getPackageName());
4408 // Save it for users of getHistoricalNotifications()
4409 mArchive.record(r.sbn);
4411 final long now = System.currentTimeMillis();
4412 MetricsLogger.action(r.getLogMaker(now)
4413 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
4414 .setType(MetricsEvent.TYPE_DISMISS)
4415 .setSubtype(reason));
4416 EventLogTags.writeNotificationCanceled(canceledKey, reason,
4417 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
4421 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
4422 * and none of the {@code mustNotHaveFlags}.
4424 void cancelNotification(final int callingUid, final int callingPid,
4425 final String pkg, final String tag, final int id,
4426 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
4427 final int userId, final int reason, final ManagedServiceInfo listener) {
4428 // In enqueueNotificationInternal notifications are added by scheduling the
4429 // work on the worker handler. Hence, we also schedule the cancel on this
4430 // handler to avoid a scenario where an add notification call followed by a
4431 // remove notification call ends up in not removing the notification.
4432 mHandler.post(new Runnable() {
4435 String listenerName = listener == null ? null : listener.component.toShortString();
4436 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
4437 userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
4439 synchronized (mNotificationLock) {
4440 // Look for the notification, searching both the posted and enqueued lists.
4441 NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
4443 // The notification was found, check if it should be removed.
4445 // Ideally we'd do this in the caller of this method. However, that would
4446 // require the caller to also find the notification.
4447 if (reason == REASON_CLICK) {
4448 mUsageStats.registerClickedByUser(r);
4451 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
4454 if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
4458 // Cancel the notification.
4459 boolean wasPosted = removeFromNotificationListsLocked(r);
4460 cancelNotificationLocked(r, sendDelete, reason, wasPosted);
4461 cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
4463 updateLightsLocked();
4465 // No notification was found, assume that it is snoozed and cancel it.
4466 if (reason != REASON_SNOOZED) {
4467 final boolean wasSnoozed = mSnoozeHelper.cancel(userId, pkg, tag, id);
4479 * Determine whether the userId applies to the notification in question, either because
4480 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
4482 private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
4484 // looking for USER_ALL notifications? match everything
4485 userId == UserHandle.USER_ALL
4486 // a notification sent to USER_ALL matches any query
4487 || r.getUserId() == UserHandle.USER_ALL
4488 // an exact user match
4489 || r.getUserId() == userId;
4493 * Determine whether the userId applies to the notification in question, either because
4494 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
4495 * because it matches one of the users profiles.
4497 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
4498 return notificationMatchesUserId(r, userId)
4499 || mUserProfiles.isCurrentProfile(r.getUserId());
4503 * Cancels all notifications from a given package that have all of the
4504 * {@code mustHaveFlags}.
4506 void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
4507 int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
4508 ManagedServiceInfo listener) {
4509 mHandler.post(new Runnable() {
4512 String listenerName = listener == null ? null : listener.component.toShortString();
4513 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
4514 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
4517 // Why does this parameter exist? Do we actually want to execute the above if doit
4523 synchronized (mNotificationLock) {
4524 FlagChecker flagChecker = (int flags) -> {
4525 if ((flags & mustHaveFlags) != mustHaveFlags) {
4528 if ((flags & mustNotHaveFlags) != 0) {
4534 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
4535 pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
4536 false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
4537 listenerName, true /* wasPosted */);
4538 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
4539 callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
4540 flagChecker, false /*includeCurrentProfiles*/, userId,
4541 false /*sendDelete*/, reason, listenerName, false /* wasPosted */);
4542 mSnoozeHelper.cancel(userId, pkg);
4548 private interface FlagChecker {
4549 // Returns false if these flags do not pass the defined flag test.
4550 public boolean apply(int flags);
4553 @GuardedBy("mNotificationLock")
4554 private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
4555 int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
4556 String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
4557 boolean sendDelete, int reason, String listenerName, boolean wasPosted) {
4558 ArrayList<NotificationRecord> canceledNotifications = null;
4559 for (int i = notificationList.size() - 1; i >= 0; --i) {
4560 NotificationRecord r = notificationList.get(i);
4561 if (includeCurrentProfiles) {
4562 if (!notificationMatchesCurrentProfiles(r, userId)) {
4565 } else if (!notificationMatchesUserId(r, userId)) {
4568 // Don't remove notifications to all, if there's no package name specified
4569 if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
4572 if (!flagChecker.apply(r.getFlags())) {
4575 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
4578 if (channelId != null && !channelId.equals(r.getChannel().getId())) {
4582 if (canceledNotifications == null) {
4583 canceledNotifications = new ArrayList<>();
4585 notificationList.remove(i);
4586 mNotificationsByKey.remove(r.getKey());
4587 canceledNotifications.add(r);
4588 cancelNotificationLocked(r, sendDelete, reason, wasPosted);
4590 if (canceledNotifications != null) {
4591 final int M = canceledNotifications.size();
4592 for (int i = 0; i < M; i++) {
4593 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
4594 listenerName, false /* sendDelete */);
4596 updateLightsLocked();
4600 void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
4601 ManagedServiceInfo listener) {
4602 String listenerName = listener == null ? null : listener.component.toShortString();
4603 if (duration <= 0 && snoozeCriterionId == null || key == null) {
4608 Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
4609 snoozeCriterionId, listenerName));
4611 // Needs to post so that it can cancel notifications not yet enqueued.
4612 mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
4615 void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
4616 String listenerName = listener == null ? null : listener.component.toShortString();
4618 Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
4620 mSnoozeHelper.repost(key);
4624 @GuardedBy("mNotificationLock")
4625 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
4626 ManagedServiceInfo listener, boolean includeCurrentProfiles) {
4627 mHandler.post(new Runnable() {
4630 synchronized (mNotificationLock) {
4631 String listenerName =
4632 listener == null ? null : listener.component.toShortString();
4633 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
4634 null, userId, 0, 0, reason, listenerName);
4636 FlagChecker flagChecker = (int flags) -> {
4637 if ((flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR))
4644 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
4645 null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
4646 includeCurrentProfiles, userId, true /*sendDelete*/, reason,
4647 listenerName, true);
4648 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
4649 callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
4650 flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
4651 reason, listenerName, false);
4652 mSnoozeHelper.cancel(userId, includeCurrentProfiles);
4658 // Warning: The caller is responsible for invoking updateLightsLocked().
4659 @GuardedBy("mNotificationLock")
4660 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
4661 String listenerName, boolean sendDelete) {
4662 Notification n = r.getNotification();
4663 if (!n.isGroupSummary()) {
4667 String pkg = r.sbn.getPackageName();
4670 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
4674 cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
4676 cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
4677 listenerName, sendDelete, false);
4680 @GuardedBy("mNotificationLock")
4681 private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
4682 NotificationRecord parentNotification, int callingUid, int callingPid,
4683 String listenerName, boolean sendDelete, boolean wasPosted) {
4684 final String pkg = parentNotification.sbn.getPackageName();
4685 final int userId = parentNotification.getUserId();
4686 final int reason = REASON_GROUP_SUMMARY_CANCELED;
4687 for (int i = notificationList.size() - 1; i >= 0; i--) {
4688 final NotificationRecord childR = notificationList.get(i);
4689 final StatusBarNotification childSbn = childR.sbn;
4690 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
4691 childR.getGroupKey().equals(parentNotification.getGroupKey())
4692 && (childR.getFlags() & Notification.FLAG_FOREGROUND_SERVICE) == 0) {
4693 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
4694 childSbn.getTag(), userId, 0, 0, reason, listenerName);
4695 notificationList.remove(i);
4696 mNotificationsByKey.remove(childR.getKey());
4697 cancelNotificationLocked(childR, sendDelete, reason, wasPosted);
4702 @GuardedBy("mNotificationLock")
4703 void updateLightsLocked()
4705 // handle notification lights
4706 NotificationRecord ledNotification = null;
4707 while (ledNotification == null && !mLights.isEmpty()) {
4708 final String owner = mLights.get(mLights.size() - 1);
4709 ledNotification = mNotificationsByKey.get(owner);
4710 if (ledNotification == null) {
4711 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
4712 mLights.remove(owner);
4716 // Don't flash while we are in a call or screen is on
4717 if (ledNotification == null || mInCall || mScreenOn) {
4718 mNotificationLight.turnOff();
4720 NotificationRecord.Light light = ledNotification.getLight();
4721 if (light != null && mNotificationPulseEnabled) {
4723 mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
4724 light.onMs, light.offMs);
4729 @GuardedBy("mNotificationLock")
4730 @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
4731 String groupKey, int userId) {
4732 List<NotificationRecord> records = new ArrayList<>();
4733 records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
4735 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
4740 @GuardedBy("mNotificationLock")
4741 private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
4742 ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
4743 List<NotificationRecord> records = new ArrayList<>();
4744 final int len = list.size();
4745 for (int i = 0; i < len; i++) {
4746 NotificationRecord r = list.get(i);
4747 if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey)
4748 && r.sbn.getPackageName().equals(pkg)) {
4755 // Searches both enqueued and posted notifications by key.
4756 // TODO: need to combine a bunch of these getters with slightly different behavior.
4757 // TODO: Should enqueuing just add to mNotificationsByKey instead?
4758 @GuardedBy("mNotificationLock")
4759 private NotificationRecord findNotificationByKeyLocked(String key) {
4760 NotificationRecord r;
4761 if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
4764 if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
4770 @GuardedBy("mNotificationLock")
4771 NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
4772 NotificationRecord r;
4773 if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
4776 if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
4783 @GuardedBy("mNotificationLock")
4784 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
4785 String pkg, String tag, int id, int userId) {
4786 final int len = list.size();
4787 for (int i = 0; i < len; i++) {
4788 NotificationRecord r = list.get(i);
4789 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
4790 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
4797 @GuardedBy("mNotificationLock")
4798 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
4800 final int N = list.size();
4801 for (int i = 0; i < N; i++) {
4802 if (key.equals(list.get(i).getKey())) {
4809 @GuardedBy("mNotificationLock")
4810 int indexOfNotificationLocked(String key) {
4811 final int N = mNotificationList.size();
4812 for (int i = 0; i < N; i++) {
4813 if (key.equals(mNotificationList.get(i).getKey())) {
4820 private void updateNotificationPulse() {
4821 synchronized (mNotificationLock) {
4822 updateLightsLocked();
4826 protected boolean isCallingUidSystem() {
4827 final int uid = Binder.getCallingUid();
4828 return uid == Process.SYSTEM_UID;
4831 protected boolean isUidSystemOrPhone(int uid) {
4832 final int appid = UserHandle.getAppId(uid);
4833 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
4836 // TODO: Most calls should probably move to isCallerSystem.
4837 protected boolean isCallerSystemOrPhone() {
4838 return isUidSystemOrPhone(Binder.getCallingUid());
4841 private void checkCallerIsSystem() {
4842 if (isCallerSystemOrPhone()) {
4845 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
4848 private void checkCallerIsSystemOrSameApp(String pkg) {
4849 if (isCallerSystemOrPhone()) {
4852 checkCallerIsSameApp(pkg);
4855 private boolean isCallerInstantApp(String pkg) {
4856 // System is always allowed to act for ephemeral apps.
4857 if (isCallerSystemOrPhone()) {
4861 mAppOps.checkPackage(Binder.getCallingUid(), pkg);
4864 ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0,
4865 UserHandle.getCallingUserId());
4867 throw new SecurityException("Unknown package " + pkg);
4869 return ai.isInstantApp();
4870 } catch (RemoteException re) {
4871 throw new SecurityException("Unknown package " + pkg, re);
4876 private void checkCallerIsSameApp(String pkg) {
4877 final int uid = Binder.getCallingUid();
4879 ApplicationInfo ai = mPackageManager.getApplicationInfo(
4880 pkg, 0, UserHandle.getCallingUserId());
4882 throw new SecurityException("Unknown package " + pkg);
4884 if (!UserHandle.isSameApp(ai.uid, uid)) {
4885 throw new SecurityException("Calling uid " + uid + " gave package "
4886 + pkg + " which is owned by uid " + ai.uid);
4888 } catch (RemoteException re) {
4889 throw new SecurityException("Unknown package " + pkg + "\n" + re);
4893 private static String callStateToString(int state) {
4895 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
4896 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
4897 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
4898 default: return "CALL_STATE_UNKNOWN_" + state;
4902 private void listenForCallState() {
4903 TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
4905 public void onCallStateChanged(int state, String incomingNumber) {
4906 if (mCallState == state) return;
4907 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
4910 }, PhoneStateListener.LISTEN_CALL_STATE);
4914 * Generates a NotificationRankingUpdate from 'sbns', considering only
4915 * notifications visible to the given listener.
4917 @GuardedBy("mNotificationLock")
4918 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
4919 final int N = mNotificationList.size();
4920 ArrayList<String> keys = new ArrayList<String>(N);
4921 ArrayList<String> interceptedKeys = new ArrayList<String>(N);
4922 ArrayList<Integer> importance = new ArrayList<>(N);
4923 Bundle overrideGroupKeys = new Bundle();
4924 Bundle visibilityOverrides = new Bundle();
4925 Bundle suppressedVisualEffects = new Bundle();
4926 Bundle explanation = new Bundle();
4927 Bundle channels = new Bundle();
4928 Bundle overridePeople = new Bundle();
4929 Bundle snoozeCriteria = new Bundle();
4930 Bundle showBadge = new Bundle();
4931 for (int i = 0; i < N; i++) {
4932 NotificationRecord record = mNotificationList.get(i);
4933 if (!isVisibleToListener(record.sbn, info)) {
4936 final String key = record.sbn.getKey();
4938 importance.add(record.getImportance());
4939 if (record.getImportanceExplanation() != null) {
4940 explanation.putCharSequence(key, record.getImportanceExplanation());
4942 if (record.isIntercepted()) {
4943 interceptedKeys.add(key);
4946 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
4947 if (record.getPackageVisibilityOverride()
4948 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
4949 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
4951 overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
4952 channels.putParcelable(key, record.getChannel());
4953 overridePeople.putStringArrayList(key, record.getPeopleOverride());
4954 snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria());
4955 showBadge.putBoolean(key, record.canShowBadge());
4957 final int M = keys.size();
4958 String[] keysAr = keys.toArray(new String[M]);
4959 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
4960 int[] importanceAr = new int[M];
4961 for (int i = 0; i < M; i++) {
4962 importanceAr[i] = importance.get(i);
4964 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
4965 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
4966 channels, overridePeople, snoozeCriteria, showBadge);
4969 boolean hasCompanionDevice(ManagedServiceInfo info) {
4970 if (mCompanionManager == null) {
4971 mCompanionManager = getCompanionManager();
4973 // Companion mgr doesn't exist on all device types
4974 if (mCompanionManager == null) {
4977 long identity = Binder.clearCallingIdentity();
4979 List<String> associations = mCompanionManager.getAssociations(
4980 info.component.getPackageName(), info.userid);
4981 if (!ArrayUtils.isEmpty(associations)) {
4984 } catch (SecurityException se) {
4985 // Not a privileged listener
4986 } catch (RemoteException re) {
4987 Slog.e(TAG, "Cannot reach companion device service", re);
4988 } catch (Exception e) {
4989 Slog.e(TAG, "Cannot verify listener " + info, e);
4991 Binder.restoreCallingIdentity(identity);
4996 protected ICompanionDeviceManager getCompanionManager() {
4997 return ICompanionDeviceManager.Stub.asInterface(
4998 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
5001 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
5002 if (!listener.enabledAndUserMatches(sbn.getUserId())) {
5005 // TODO: remove this for older listeners.
5009 private boolean isPackageSuspendedForUser(String pkg, int uid) {
5010 int userId = UserHandle.getUserId(uid);
5012 return mPackageManager.isPackageSuspendedForUser(pkg, userId);
5013 } catch (RemoteException re) {
5014 throw new SecurityException("Could not talk to package manager service");
5015 } catch (IllegalArgumentException ex) {
5016 // Package not found.
5021 private class TrimCache {
5022 StatusBarNotification heavy;
5023 StatusBarNotification sbnClone;
5024 StatusBarNotification sbnCloneLight;
5026 TrimCache(StatusBarNotification sbn) {
5030 StatusBarNotification ForListener(ManagedServiceInfo info) {
5031 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
5032 if (sbnCloneLight == null) {
5033 sbnCloneLight = heavy.cloneLight();
5035 return sbnCloneLight;
5037 if (sbnClone == null) {
5038 sbnClone = heavy.clone();
5045 public class NotificationAssistants extends ManagedServices {
5047 public NotificationAssistants() {
5048 super(getContext(), mHandler, mNotificationLock, mUserProfiles);
5052 protected Config getConfig() {
5053 Config c = new Config();
5054 c.caption = "notification assistant service";
5055 c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
5056 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
5057 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
5058 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
5059 c.clientLabel = R.string.notification_ranker_binding_label;
5064 protected IInterface asInterface(IBinder binder) {
5065 return INotificationListener.Stub.asInterface(binder);
5069 protected boolean checkType(IInterface service) {
5070 return service instanceof INotificationListener;
5074 protected void onServiceAdded(ManagedServiceInfo info) {
5075 mListeners.registerGuestService(info);
5079 @GuardedBy("mNotificationLock")
5080 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
5081 mListeners.unregisterService(removed.service, removed.userid);
5084 public void onNotificationEnqueued(final NotificationRecord r) {
5085 final StatusBarNotification sbn = r.sbn;
5086 TrimCache trimCache = new TrimCache(sbn);
5088 // There should be only one, but it's a list, so while we enforce
5089 // singularity elsewhere, we keep it general here, to avoid surprises.
5090 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
5091 boolean sbnVisible = isVisibleToListener(sbn, info);
5096 final int importance = r.getImportance();
5097 final boolean fromUser = r.isImportanceFromUser();
5098 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
5099 mHandler.post(new Runnable() {
5102 notifyEnqueued(info, sbnToPost);
5108 private void notifyEnqueued(final ManagedServiceInfo info,
5109 final StatusBarNotification sbn) {
5110 final INotificationListener assistant = (INotificationListener) info.service;
5111 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5113 assistant.onNotificationEnqueued(sbnHolder);
5114 } catch (RemoteException ex) {
5115 Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
5120 * asynchronously notify the assistant that a notification has been snoozed until a
5123 @GuardedBy("mNotificationLock")
5124 public void notifyAssistantSnoozedLocked(final StatusBarNotification sbn,
5125 final String snoozeCriterionId) {
5126 TrimCache trimCache = new TrimCache(sbn);
5127 for (final ManagedServiceInfo info : getServices()) {
5128 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
5129 mHandler.post(new Runnable() {
5132 final INotificationListener assistant =
5133 (INotificationListener) info.service;
5134 StatusBarNotificationHolder sbnHolder
5135 = new StatusBarNotificationHolder(sbnToPost);
5137 assistant.onNotificationSnoozedUntilContext(
5138 sbnHolder, snoozeCriterionId);
5139 } catch (RemoteException ex) {
5140 Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
5147 public boolean isEnabled() {
5148 return !getServices().isEmpty();
5152 public class NotificationListeners extends ManagedServices {
5154 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
5156 public NotificationListeners() {
5157 super(getContext(), mHandler, mNotificationLock, mUserProfiles);
5161 protected Config getConfig() {
5162 Config c = new Config();
5163 c.caption = "notification listener";
5164 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
5165 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
5166 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
5167 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
5168 c.clientLabel = R.string.notification_listener_binding_label;
5173 protected IInterface asInterface(IBinder binder) {
5174 return INotificationListener.Stub.asInterface(binder);
5178 protected boolean checkType(IInterface service) {
5179 return service instanceof INotificationListener;
5183 public void onServiceAdded(ManagedServiceInfo info) {
5184 final INotificationListener listener = (INotificationListener) info.service;
5185 final NotificationRankingUpdate update;
5186 synchronized (mNotificationLock) {
5187 update = makeRankingUpdateLocked(info);
5190 listener.onListenerConnected(update);
5191 } catch (RemoteException e) {
5197 @GuardedBy("mNotificationLock")
5198 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
5199 if (removeDisabledHints(removed)) {
5200 updateListenerHintsLocked();
5201 updateEffectsSuppressorLocked();
5203 mLightTrimListeners.remove(removed);
5206 @GuardedBy("mNotificationLock")
5207 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
5208 if (trim == TRIM_LIGHT) {
5209 mLightTrimListeners.add(info);
5211 mLightTrimListeners.remove(info);
5215 public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
5216 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
5220 * asynchronously notify all listeners about a new notification
5223 * Also takes care of removing a notification that has been visible to a listener before,
5224 * but isn't anymore.
5226 @GuardedBy("mNotificationLock")
5227 public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
5228 // Lazily initialized snapshots of the notification.
5229 TrimCache trimCache = new TrimCache(sbn);
5231 for (final ManagedServiceInfo info : getServices()) {
5232 boolean sbnVisible = isVisibleToListener(sbn, info);
5233 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
5234 // This notification hasn't been and still isn't visible -> ignore.
5235 if (!oldSbnVisible && !sbnVisible) {
5238 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
5240 // This notification became invisible -> remove the old one.
5241 if (oldSbnVisible && !sbnVisible) {
5242 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
5243 mHandler.post(new Runnable() {
5246 notifyRemoved(info, oldSbnLightClone, update, REASON_USER_STOPPED);
5252 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
5253 mHandler.post(new Runnable() {
5256 notifyPosted(info, sbnToPost, update);
5263 * asynchronously notify all listeners about a removed notification
5265 @GuardedBy("mNotificationLock")
5266 public void notifyRemovedLocked(StatusBarNotification sbn, int reason) {
5267 // make a copy in case changes are made to the underlying Notification object
5268 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
5270 final StatusBarNotification sbnLight = sbn.cloneLight();
5271 for (final ManagedServiceInfo info : getServices()) {
5272 if (!isVisibleToListener(sbn, info)) {
5275 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
5276 mHandler.post(new Runnable() {
5279 notifyRemoved(info, sbnLight, update, reason);
5286 * asynchronously notify all listeners about a reordering of notifications
5288 @GuardedBy("mNotificationLock")
5289 public void notifyRankingUpdateLocked() {
5290 for (final ManagedServiceInfo serviceInfo : getServices()) {
5291 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5294 final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
5295 mHandler.post(new Runnable() {
5298 notifyRankingUpdate(serviceInfo, update);
5304 @GuardedBy("mNotificationLock")
5305 public void notifyListenerHintsChangedLocked(final int hints) {
5306 for (final ManagedServiceInfo serviceInfo : getServices()) {
5307 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5310 mHandler.post(new Runnable() {
5313 notifyListenerHintsChanged(serviceInfo, hints);
5319 public void notifyInterruptionFilterChanged(final int interruptionFilter) {
5320 for (final ManagedServiceInfo serviceInfo : getServices()) {
5321 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5324 mHandler.post(new Runnable() {
5327 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
5333 protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user,
5334 final NotificationChannel channel, final int modificationType) {
5335 if (channel == null) {
5338 for (final ManagedServiceInfo serviceInfo : getServices()) {
5339 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
5343 mHandler.post(new Runnable() {
5346 if (hasCompanionDevice(serviceInfo)) {
5347 notifyNotificationChannelChanged(
5348 serviceInfo, pkg, user, channel, modificationType);
5355 protected void notifyNotificationChannelGroupChanged(
5356 final String pkg, final UserHandle user, final NotificationChannelGroup group,
5357 final int modificationType) {
5358 if (group == null) {
5361 for (final ManagedServiceInfo serviceInfo : getServices()) {
5362 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
5366 mHandler.post(new Runnable() {
5369 if (hasCompanionDevice(serviceInfo)) {
5370 notifyNotificationChannelGroupChanged(
5371 serviceInfo, pkg, user, group, modificationType);
5378 private void notifyPosted(final ManagedServiceInfo info,
5379 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
5380 final INotificationListener listener = (INotificationListener) info.service;
5381 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5383 listener.onNotificationPosted(sbnHolder, rankingUpdate);
5384 } catch (RemoteException ex) {
5385 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
5389 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
5390 NotificationRankingUpdate rankingUpdate, int reason) {
5391 if (!info.enabledAndUserMatches(sbn.getUserId())) {
5394 final INotificationListener listener = (INotificationListener) info.service;
5395 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5397 listener.onNotificationRemoved(sbnHolder, rankingUpdate, reason);
5398 } catch (RemoteException ex) {
5399 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
5403 private void notifyRankingUpdate(ManagedServiceInfo info,
5404 NotificationRankingUpdate rankingUpdate) {
5405 final INotificationListener listener = (INotificationListener) info.service;
5407 listener.onNotificationRankingUpdate(rankingUpdate);
5408 } catch (RemoteException ex) {
5409 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
5413 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
5414 final INotificationListener listener = (INotificationListener) info.service;
5416 listener.onListenerHintsChanged(hints);
5417 } catch (RemoteException ex) {
5418 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
5422 private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
5423 int interruptionFilter) {
5424 final INotificationListener listener = (INotificationListener) info.service;
5426 listener.onInterruptionFilterChanged(interruptionFilter);
5427 } catch (RemoteException ex) {
5428 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
5432 void notifyNotificationChannelChanged(ManagedServiceInfo info,
5433 final String pkg, final UserHandle user, final NotificationChannel channel,
5434 final int modificationType) {
5435 final INotificationListener listener = (INotificationListener) info.service;
5437 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
5438 } catch (RemoteException ex) {
5439 Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
5443 private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
5444 final String pkg, final UserHandle user, final NotificationChannelGroup group,
5445 final int modificationType) {
5446 final INotificationListener listener = (INotificationListener) info.service;
5448 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
5449 } catch (RemoteException ex) {
5450 Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
5454 public boolean isListenerPackage(String packageName) {
5455 if (packageName == null) {
5458 // TODO: clean up locking object later
5459 synchronized (mNotificationLock) {
5460 for (final ManagedServiceInfo serviceInfo : getServices()) {
5461 if (packageName.equals(serviceInfo.component.getPackageName())) {
5470 public static final class DumpFilter {
5471 public boolean filtered = false;
5472 public String pkgFilter;
5475 public boolean stats;
5476 public boolean redact = true;
5477 public boolean proto = false;
5479 public static DumpFilter parseFromArguments(String[] args) {
5480 final DumpFilter filter = new DumpFilter();
5481 for (int ai = 0; ai < args.length; ai++) {
5482 final String a = args[ai];
5483 if ("--proto".equals(args[0])) {
5484 filter.proto = true;
5486 if ("--noredact".equals(a) || "--reveal".equals(a)) {
5487 filter.redact = false;
5488 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
5489 if (ai < args.length-1) {
5491 filter.pkgFilter = args[ai].trim().toLowerCase();
5492 if (filter.pkgFilter.isEmpty()) {
5493 filter.pkgFilter = null;
5495 filter.filtered = true;
5498 } else if ("--zen".equals(a) || "zen".equals(a)) {
5499 filter.filtered = true;
5501 } else if ("--stats".equals(a)) {
5502 filter.stats = true;
5503 if (ai < args.length-1) {
5505 filter.since = Long.parseLong(args[ai]);
5514 public boolean matches(StatusBarNotification sbn) {
5515 if (!filtered) return true;
5516 return zen ? true : sbn != null
5517 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
5520 public boolean matches(ComponentName component) {
5521 if (!filtered) return true;
5522 return zen ? true : component != null && matches(component.getPackageName());
5525 public boolean matches(String pkg) {
5526 if (!filtered) return true;
5527 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
5531 public String toString() {
5532 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
5537 * Wrapper for a StatusBarNotification object that allows transfer across a oneway
5538 * binder without sending large amounts of data over a oneway transaction.
5540 private static final class StatusBarNotificationHolder
5541 extends IStatusBarNotificationHolder.Stub {
5542 private StatusBarNotification mValue;
5544 public StatusBarNotificationHolder(StatusBarNotification value) {
5548 /** Get the held value and clear it. This function should only be called once per holder */
5550 public StatusBarNotification get() {
5551 StatusBarNotification value = mValue;
5557 private final class PolicyAccess {
5558 private static final String SEPARATOR = ":";
5559 private final String[] PERM = {
5560 android.Manifest.permission.ACCESS_NOTIFICATION_POLICY
5563 public boolean isPackageGranted(String pkg) {
5564 return pkg != null && getGrantedPackages().contains(pkg);
5567 public void put(String pkg, boolean granted) {
5568 if (pkg == null) return;
5569 final ArraySet<String> pkgs = getGrantedPackages();
5572 changed = pkgs.add(pkg);
5574 changed = pkgs.remove(pkg);
5576 if (!changed) return;
5577 final String setting = TextUtils.join(SEPARATOR, pkgs);
5578 final int currentUser = ActivityManager.getCurrentUser();
5579 Settings.Secure.putStringForUser(getContext().getContentResolver(),
5580 Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
5583 getContext().sendBroadcastAsUser(new Intent(NotificationManager
5584 .ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
5586 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), new UserHandle(currentUser), null);
5589 public ArraySet<String> getGrantedPackages() {
5590 final ArraySet<String> pkgs = new ArraySet<>();
5592 long identity = Binder.clearCallingIdentity();
5594 final String setting = Settings.Secure.getStringForUser(
5595 getContext().getContentResolver(),
5596 Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
5597 ActivityManager.getCurrentUser());
5598 if (setting != null) {
5599 final String[] tokens = setting.split(SEPARATOR);
5600 for (int i = 0; i < tokens.length; i++) {
5601 String token = tokens[i];
5602 if (token != null) {
5603 token = token.trim();
5605 if (TextUtils.isEmpty(token)) {
5612 Binder.restoreCallingIdentity(identity);
5617 public String[] getRequestingPackages() throws RemoteException {
5618 final ParceledListSlice list = mPackageManager
5619 .getPackagesHoldingPermissions(PERM, 0 /*flags*/,
5620 ActivityManager.getCurrentUser());
5621 final List<PackageInfo> pkgs = list.getList();
5622 if (pkgs == null || pkgs.isEmpty()) return new String[0];
5623 final int N = pkgs.size();
5624 final String[] rt = new String[N];
5625 for (int i = 0; i < N; i++) {
5626 rt[i] = pkgs.get(i).packageName;