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.ACTION_APP_BLOCK_STATE_CHANGED;
20 import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED;
21 import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED;
22 import static android.app.NotificationManager.IMPORTANCE_LOW;
23 import static android.app.NotificationManager.IMPORTANCE_MIN;
24 import static android.app.NotificationManager.IMPORTANCE_NONE;
25 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECTS_UNSET;
26 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
27 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
28 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
29 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
30 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
31 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
32 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
33 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
34 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
35 import static android.content.pm.PackageManager.FEATURE_LEANBACK;
36 import static android.content.pm.PackageManager.FEATURE_TELEVISION;
37 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
38 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
39 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
40 import static android.os.UserHandle.USER_ALL;
41 import static android.os.UserHandle.USER_NULL;
42 import static android.os.UserHandle.USER_SYSTEM;
43 import static android.service.notification.NotificationListenerService
44 .HINT_HOST_DISABLE_CALL_EFFECTS;
45 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
46 import static android.service.notification.NotificationListenerService
47 .HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
48 import static android.service.notification.NotificationListenerService
49 .NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
50 import static android.service.notification.NotificationListenerService
51 .NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
52 import static android.service.notification.NotificationListenerService
53 .NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
54 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
55 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
56 import static android.service.notification.NotificationListenerService.REASON_CANCEL;
57 import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
58 import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
59 import static android.service.notification.NotificationListenerService.REASON_CLICK;
60 import static android.service.notification.NotificationListenerService.REASON_ERROR;
61 import static android.service.notification.NotificationListenerService
62 .REASON_GROUP_SUMMARY_CANCELED;
63 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL;
64 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL;
65 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED;
66 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED;
67 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED;
68 import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF;
69 import static android.service.notification.NotificationListenerService.REASON_SNOOZED;
70 import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
71 import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
72 import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
73 import static android.service.notification.NotificationListenerService.TRIM_FULL;
74 import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
75 import static android.view.Display.DEFAULT_DISPLAY;
76 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
78 import static com.android.server.utils.PriorityDump.PRIORITY_ARG;
79 import static com.android.server.utils.PriorityDump.PRIORITY_ARG_CRITICAL;
80 import static com.android.server.utils.PriorityDump.PRIORITY_ARG_NORMAL;
82 import android.Manifest;
83 import android.annotation.NonNull;
84 import android.annotation.Nullable;
85 import android.app.ActivityManager;
86 import android.app.ActivityManagerInternal;
87 import android.app.AlarmManager;
88 import android.app.AppGlobals;
89 import android.app.AppOpsManager;
90 import android.app.AutomaticZenRule;
91 import android.app.IActivityManager;
92 import android.app.INotificationManager;
93 import android.app.ITransientNotification;
94 import android.app.Notification;
95 import android.app.NotificationChannel;
96 import android.app.NotificationChannelGroup;
97 import android.app.NotificationManager;
98 import android.app.NotificationManager.Policy;
99 import android.app.PendingIntent;
100 import android.app.StatusBarManager;
101 import android.app.backup.BackupManager;
102 import android.app.usage.UsageEvents;
103 import android.app.usage.UsageStatsManagerInternal;
104 import android.companion.ICompanionDeviceManager;
105 import android.content.BroadcastReceiver;
106 import android.content.ComponentName;
107 import android.content.ContentProvider;
108 import android.content.ContentResolver;
109 import android.content.Context;
110 import android.content.Intent;
111 import android.content.IntentFilter;
112 import android.content.pm.ApplicationInfo;
113 import android.content.pm.IPackageManager;
114 import android.content.pm.PackageManager;
115 import android.content.pm.PackageManager.NameNotFoundException;
116 import android.content.pm.ParceledListSlice;
117 import android.content.pm.UserInfo;
118 import android.content.res.Resources;
119 import android.database.ContentObserver;
120 import android.media.AudioAttributes;
121 import android.media.AudioManager;
122 import android.media.AudioManagerInternal;
123 import android.media.IRingtonePlayer;
124 import android.net.Uri;
125 import android.os.Binder;
126 import android.os.Build;
127 import android.os.Bundle;
128 import android.os.Environment;
129 import android.os.Handler;
130 import android.os.HandlerThread;
131 import android.os.IBinder;
132 import android.os.IDeviceIdleController;
133 import android.os.IInterface;
134 import android.os.Looper;
135 import android.os.Message;
136 import android.os.Process;
137 import android.os.RemoteException;
138 import android.os.ResultReceiver;
139 import android.os.ServiceManager;
140 import android.os.ShellCallback;
141 import android.os.ShellCommand;
142 import android.os.SystemClock;
143 import android.os.SystemProperties;
144 import android.os.UserHandle;
145 import android.os.VibrationEffect;
146 import android.os.Vibrator;
147 import android.provider.Settings;
148 import android.service.notification.Adjustment;
149 import android.service.notification.Condition;
150 import android.service.notification.IConditionProvider;
151 import android.service.notification.INotificationListener;
152 import android.service.notification.IStatusBarNotificationHolder;
153 import android.service.notification.ListenersDisablingEffectsProto;
154 import android.service.notification.NotificationAssistantService;
155 import android.service.notification.NotificationListenerService;
156 import android.service.notification.NotificationRankingUpdate;
157 import android.service.notification.NotificationRecordProto;
158 import android.service.notification.NotificationServiceDumpProto;
159 import android.service.notification.NotificationStats;
160 import android.service.notification.NotifyingApp;
161 import android.service.notification.SnoozeCriterion;
162 import android.service.notification.StatusBarNotification;
163 import android.service.notification.ZenModeConfig;
164 import android.service.notification.ZenModeProto;
165 import android.telephony.PhoneStateListener;
166 import android.telephony.TelephonyManager;
167 import android.text.TextUtils;
168 import android.util.ArrayMap;
169 import android.util.ArraySet;
170 import android.util.AtomicFile;
171 import android.util.Log;
172 import android.util.Slog;
173 import android.util.SparseArray;
174 import android.util.Xml;
175 import android.util.proto.ProtoOutputStream;
176 import android.view.accessibility.AccessibilityEvent;
177 import android.view.accessibility.AccessibilityManager;
178 import android.widget.Toast;
180 import com.android.internal.R;
181 import com.android.internal.annotations.GuardedBy;
182 import com.android.internal.annotations.VisibleForTesting;
183 import com.android.internal.logging.MetricsLogger;
184 import com.android.internal.logging.nano.MetricsProto;
185 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
186 import com.android.internal.notification.SystemNotificationChannels;
187 import com.android.internal.os.BackgroundThread;
188 import com.android.internal.statusbar.NotificationVisibility;
189 import com.android.internal.util.ArrayUtils;
190 import com.android.internal.util.DumpUtils;
191 import com.android.internal.util.FastXmlSerializer;
192 import com.android.internal.util.Preconditions;
193 import com.android.internal.util.XmlUtils;
194 import com.android.server.DeviceIdleController;
195 import com.android.server.EventLogTags;
196 import com.android.server.LocalServices;
197 import com.android.server.SystemService;
198 import com.android.server.lights.Light;
199 import com.android.server.lights.LightsManager;
200 import com.android.server.notification.ManagedServices.ManagedServiceInfo;
201 import com.android.server.notification.ManagedServices.UserProfiles;
202 import com.android.server.policy.PhoneWindowManager;
203 import com.android.server.statusbar.StatusBarManagerInternal;
204 import com.android.server.wm.WindowManagerInternal;
206 import libcore.io.IoUtils;
208 import org.json.JSONException;
209 import org.json.JSONObject;
210 import org.xmlpull.v1.XmlPullParser;
211 import org.xmlpull.v1.XmlPullParserException;
212 import org.xmlpull.v1.XmlSerializer;
214 import java.io.ByteArrayInputStream;
215 import java.io.ByteArrayOutputStream;
217 import java.io.FileDescriptor;
218 import java.io.FileNotFoundException;
219 import java.io.FileOutputStream;
220 import java.io.IOException;
221 import java.io.InputStream;
222 import java.io.OutputStream;
223 import java.io.PrintWriter;
224 import java.nio.charset.StandardCharsets;
225 import java.util.ArrayDeque;
226 import java.util.ArrayList;
227 import java.util.Arrays;
228 import java.util.HashSet;
229 import java.util.Iterator;
230 import java.util.List;
231 import java.util.Map.Entry;
232 import java.util.Objects;
233 import java.util.Set;
234 import java.util.concurrent.TimeUnit;
237 public class NotificationManagerService extends SystemService {
238 static final String TAG = "NotificationService";
239 static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
240 public static final boolean ENABLE_CHILD_NOTIFICATIONS
241 = SystemProperties.getBoolean("debug.child_notifs", true);
243 static final int MAX_PACKAGE_NOTIFICATIONS = 50;
244 static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 5f;
247 static final int MESSAGE_DURATION_REACHED = 2;
248 static final int MESSAGE_SAVE_POLICY_FILE = 3;
249 static final int MESSAGE_SEND_RANKING_UPDATE = 4;
250 static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
251 static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
252 static final int MESSAGE_FINISH_TOKEN_TIMEOUT = 7;
254 // ranking thread messages
255 private static final int MESSAGE_RECONSIDER_RANKING = 1000;
256 private static final int MESSAGE_RANKING_SORT = 1001;
258 static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
259 static final int SHORT_DELAY = 2000; // 2 seconds
261 // 1 second past the ANR timeout.
262 static final int FINISH_TOKEN_TIMEOUT = 11 * 1000;
264 static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
266 static final long SNOOZE_UNTIL_UNSPECIFIED = -1;
268 static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
270 static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
272 static final boolean ENABLE_BLOCKED_TOASTS = true;
274 // When #matchesCallFilter is called from the ringer, wait at most
275 // 3s to resolve the contacts. This timeout is required since
276 // ContactsProvider might take a long time to start up.
278 // Return STARRED_CONTACT when the timeout is hit in order to avoid
279 // missed calls in ZEN mode "Important".
280 static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
281 static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
282 ValidateNotificationPeople.STARRED_CONTACT;
284 /** notification_enqueue status value for a newly enqueued notification. */
285 private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
287 /** notification_enqueue status value for an existing notification. */
288 private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
290 /** notification_enqueue status value for an ignored notification. */
291 private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
292 private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
294 private static final long DELAY_FOR_ASSISTANT_TIME = 100;
296 private static final String ACTION_NOTIFICATION_TIMEOUT =
297 NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
298 private static final int REQUEST_CODE_TIMEOUT = 1;
299 private static final String SCHEME_TIMEOUT = "timeout";
300 private static final String EXTRA_KEY = "key";
302 private IActivityManager mAm;
303 private ActivityManager mActivityManager;
304 private IPackageManager mPackageManager;
305 private PackageManager mPackageManagerClient;
306 AudioManager mAudioManager;
307 AudioManagerInternal mAudioManagerInternal;
308 @Nullable StatusBarManagerInternal mStatusBar;
310 private WindowManagerInternal mWindowManagerInternal;
311 private AlarmManager mAlarmManager;
312 private ICompanionDeviceManager mCompanionManager;
313 private AccessibilityManager mAccessibilityManager;
314 private IDeviceIdleController mDeviceIdleController;
315 private IBinder mPermissionOwner;
317 final IBinder mForegroundToken = new Binder();
318 private WorkerHandler mHandler;
319 private final HandlerThread mRankingThread = new HandlerThread("ranker",
320 Process.THREAD_PRIORITY_BACKGROUND);
322 private Light mNotificationLight;
323 Light mAttentionLight;
325 private long[] mFallbackVibrationPattern;
326 private boolean mUseAttentionLight;
327 boolean mSystemReady;
329 private boolean mDisableNotificationEffects;
330 private int mCallState;
331 private String mSoundNotificationKey;
332 private String mVibrateNotificationKey;
334 private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
336 private List<ComponentName> mEffectsSuppressors = new ArrayList<>();
337 private int mListenerHints; // right now, all hints are global
338 private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
340 // for enabling and disabling notification pulse behavior
341 private boolean mScreenOn = true;
342 protected boolean mInCall = false;
343 private boolean mNotificationPulseEnabled;
345 private Uri mInCallNotificationUri;
346 private AudioAttributes mInCallNotificationAudioAttributes;
347 private float mInCallNotificationVolume;
349 // used as a mutex for access to all active notifications & listeners
350 final Object mNotificationLock = new Object();
351 @GuardedBy("mNotificationLock")
352 final ArrayList<NotificationRecord> mNotificationList = new ArrayList<>();
353 @GuardedBy("mNotificationLock")
354 final ArrayMap<String, NotificationRecord> mNotificationsByKey = new ArrayMap<>();
355 @GuardedBy("mNotificationLock")
356 final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();
357 @GuardedBy("mNotificationLock")
358 final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
359 final ArrayList<ToastRecord> mToastQueue = new ArrayList<>();
360 final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
361 final ArrayMap<Integer, ArrayList<NotifyingApp>> mRecentApps = new ArrayMap<>();
363 // The last key in this list owns the hardware.
364 ArrayList<String> mLights = new ArrayList<>();
366 private AppOpsManager mAppOps;
367 private UsageStatsManagerInternal mAppUsageStats;
369 private Archive mArchive;
371 // Persistent storage for notification policy
372 private AtomicFile mPolicyFile;
374 private static final int DB_VERSION = 1;
376 private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
377 private static final String ATTR_VERSION = "version";
379 private RankingHelper mRankingHelper;
381 private final UserProfiles mUserProfiles = new UserProfiles();
382 private NotificationListeners mListeners;
383 private NotificationAssistants mAssistants;
384 private ConditionProviders mConditionProviders;
385 private NotificationUsageStats mUsageStats;
387 private static final int MY_UID = Process.myUid();
388 private static final int MY_PID = Process.myPid();
389 private static final IBinder WHITELIST_TOKEN = new Binder();
390 private RankingHandler mRankingHandler;
391 private long mLastOverRateLogTime;
392 private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
394 private SnoozeHelper mSnoozeHelper;
395 private GroupHelper mGroupHelper;
396 private boolean mIsTelevision;
398 private static class Archive {
399 final int mBufferSize;
400 final ArrayDeque<StatusBarNotification> mBuffer;
402 public Archive(int size) {
404 mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
407 public String toString() {
408 final StringBuilder sb = new StringBuilder();
409 final int N = mBuffer.size();
410 sb.append("Archive (");
412 sb.append(" notification");
413 sb.append((N==1)?")":"s)");
414 return sb.toString();
417 public void record(StatusBarNotification nr) {
418 if (mBuffer.size() == mBufferSize) {
419 mBuffer.removeFirst();
422 // We don't want to store the heavy bits of the notification in the archive,
423 // but other clients in the system process might be using the object, so we
424 // store a (lightened) copy.
425 mBuffer.addLast(nr.cloneLight());
428 public Iterator<StatusBarNotification> descendingIterator() {
429 return mBuffer.descendingIterator();
432 public StatusBarNotification[] getArray(int count) {
433 if (count == 0) count = mBufferSize;
434 final StatusBarNotification[] a
435 = new StatusBarNotification[Math.min(count, mBuffer.size())];
436 Iterator<StatusBarNotification> iter = descendingIterator();
438 while (iter.hasNext() && i < count) {
439 a[i++] = iter.next();
446 protected void readDefaultApprovedServices(int userId) {
447 String defaultListenerAccess = getContext().getResources().getString(
448 com.android.internal.R.string.config_defaultListenerAccessPackages);
449 if (defaultListenerAccess != null) {
450 for (String whitelisted :
451 defaultListenerAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
452 // Gather all notification listener components for candidate pkgs.
453 Set<ComponentName> approvedListeners =
454 mListeners.queryPackageForServices(whitelisted,
455 PackageManager.MATCH_DIRECT_BOOT_AWARE
456 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
457 for (ComponentName cn : approvedListeners) {
459 getBinderService().setNotificationListenerAccessGrantedForUser(cn,
461 } catch (RemoteException e) {
468 String defaultDndAccess = getContext().getResources().getString(
469 com.android.internal.R.string.config_defaultDndAccessPackages);
470 if (defaultListenerAccess != null) {
471 for (String whitelisted :
472 defaultDndAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
474 getBinderService().setNotificationPolicyAccessGranted(whitelisted, true);
475 } catch (RemoteException e) {
481 readDefaultAssistant(userId);
484 protected void readDefaultAssistant(int userId) {
485 String defaultAssistantAccess = getContext().getResources().getString(
486 com.android.internal.R.string.config_defaultAssistantAccessPackage);
487 if (defaultAssistantAccess != null) {
488 // Gather all notification assistant components for candidate pkg. There should
490 Set<ComponentName> approvedAssistants =
491 mAssistants.queryPackageForServices(defaultAssistantAccess,
492 PackageManager.MATCH_DIRECT_BOOT_AWARE
493 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
494 for (ComponentName cn : approvedAssistants) {
496 getBinderService().setNotificationAssistantAccessGrantedForUser(
498 } catch (RemoteException e) {
505 void readPolicyXml(InputStream stream, boolean forRestore)
506 throws XmlPullParserException, NumberFormatException, IOException {
507 final XmlPullParser parser = Xml.newPullParser();
508 parser.setInput(stream, StandardCharsets.UTF_8.name());
509 XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY);
510 boolean migratedManagedServices = false;
511 int outerDepth = parser.getDepth();
512 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
513 if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) {
514 mZenModeHelper.readXml(parser, forRestore);
515 } else if (RankingHelper.TAG_RANKING.equals(parser.getName())){
516 mRankingHelper.readXml(parser, forRestore);
518 // No non-system managed services are allowed on low ram devices
519 if (canUseManagedServices()) {
520 if (mListeners.getConfig().xmlTag.equals(parser.getName())) {
521 mListeners.readXml(parser);
522 migratedManagedServices = true;
523 } else if (mAssistants.getConfig().xmlTag.equals(parser.getName())) {
524 mAssistants.readXml(parser);
525 migratedManagedServices = true;
526 } else if (mConditionProviders.getConfig().xmlTag.equals(parser.getName())) {
527 mConditionProviders.readXml(parser);
528 migratedManagedServices = true;
533 if (!migratedManagedServices) {
534 mListeners.migrateToXml();
535 mAssistants.migrateToXml();
536 mConditionProviders.migrateToXml();
540 mAssistants.ensureAssistant();
543 private void loadPolicyFile() {
544 if (DBG) Slog.d(TAG, "loadPolicyFile");
545 synchronized (mPolicyFile) {
547 InputStream infile = null;
549 infile = mPolicyFile.openRead();
550 readPolicyXml(infile, false /*forRestore*/);
551 } catch (FileNotFoundException e) {
553 // Load default managed services approvals
554 readDefaultApprovedServices(USER_SYSTEM);
555 } catch (IOException e) {
556 Log.wtf(TAG, "Unable to read notification policy", e);
557 } catch (NumberFormatException e) {
558 Log.wtf(TAG, "Unable to parse notification policy", e);
559 } catch (XmlPullParserException e) {
560 Log.wtf(TAG, "Unable to parse notification policy", e);
562 IoUtils.closeQuietly(infile);
567 public void savePolicyFile() {
568 mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
569 mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
572 private void handleSavePolicyFile() {
573 if (DBG) Slog.d(TAG, "handleSavePolicyFile");
574 synchronized (mPolicyFile) {
575 final FileOutputStream stream;
577 stream = mPolicyFile.startWrite();
578 } catch (IOException e) {
579 Slog.w(TAG, "Failed to save policy file", e);
584 writePolicyXml(stream, false /*forBackup*/);
585 mPolicyFile.finishWrite(stream);
586 } catch (IOException e) {
587 Slog.w(TAG, "Failed to save policy file, restoring backup", e);
588 mPolicyFile.failWrite(stream);
591 BackupManager.dataChanged(getContext().getPackageName());
594 private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
595 final XmlSerializer out = new FastXmlSerializer();
596 out.setOutput(stream, StandardCharsets.UTF_8.name());
597 out.startDocument(null, true);
598 out.startTag(null, TAG_NOTIFICATION_POLICY);
599 out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
600 mZenModeHelper.writeXml(out, forBackup, null);
601 mRankingHelper.writeXml(out, forBackup);
602 mListeners.writeXml(out, forBackup);
603 mAssistants.writeXml(out, forBackup);
604 mConditionProviders.writeXml(out, forBackup);
605 out.endTag(null, TAG_NOTIFICATION_POLICY);
609 private static final class ToastRecord
613 ITransientNotification callback;
617 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
621 this.callback = callback;
622 this.duration = duration;
626 void update(int duration) {
627 this.duration = duration;
630 void update(ITransientNotification callback) {
631 this.callback = callback;
634 void dump(PrintWriter pw, String prefix, DumpFilter filter) {
635 if (filter != null && !filter.matches(pkg)) return;
636 pw.println(prefix + this);
640 public final String toString()
642 return "ToastRecord{"
643 + Integer.toHexString(System.identityHashCode(this))
645 + " callback=" + callback
646 + " duration=" + duration;
651 final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
654 public void onSetDisabled(int status) {
655 synchronized (mNotificationLock) {
656 mDisableNotificationEffects =
657 (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
658 if (disableNotificationEffects(null) != null) {
659 // cancel whatever's going on
660 long identity = Binder.clearCallingIdentity();
662 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
663 if (player != null) {
666 } catch (RemoteException e) {
668 Binder.restoreCallingIdentity(identity);
671 identity = Binder.clearCallingIdentity();
675 Binder.restoreCallingIdentity(identity);
682 public void onClearAll(int callingUid, int callingPid, int userId) {
683 synchronized (mNotificationLock) {
684 cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null,
685 /*includeCurrentProfiles*/ true);
690 public void onNotificationClick(int callingUid, int callingPid, String key) {
692 synchronized (mNotificationLock) {
693 NotificationRecord r = mNotificationsByKey.get(key);
695 Log.w(TAG, "No notification with key: " + key);
698 final long now = System.currentTimeMillis();
699 MetricsLogger.action(r.getLogMaker(now)
700 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
701 .setType(MetricsEvent.TYPE_ACTION));
702 EventLogTags.writeNotificationClicked(key,
703 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
705 StatusBarNotification sbn = r.sbn;
706 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
707 sbn.getId(), Notification.FLAG_AUTO_CANCEL,
708 Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
710 reportUserInteraction(r);
715 public void onNotificationActionClick(int callingUid, int callingPid, String key,
718 synchronized (mNotificationLock) {
719 NotificationRecord r = mNotificationsByKey.get(key);
721 Log.w(TAG, "No notification with key: " + key);
724 final long now = System.currentTimeMillis();
725 MetricsLogger.action(r.getLogMaker(now)
726 .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION)
727 .setType(MetricsEvent.TYPE_ACTION)
728 .setSubtype(actionIndex));
729 EventLogTags.writeNotificationActionClicked(key, actionIndex,
730 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
731 reportUserInteraction(r);
736 public void onNotificationClear(int callingUid, int callingPid,
737 String pkg, String tag, int id, int userId, String key,
738 @NotificationStats.DismissalSurface int dismissalSurface) {
739 synchronized (mNotificationLock) {
740 NotificationRecord r = mNotificationsByKey.get(key);
742 r.recordDismissalSurface(dismissalSurface);
745 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
746 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
747 true, userId, REASON_CANCEL, null);
751 public void onPanelRevealed(boolean clearEffects, int items) {
752 MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL);
753 MetricsLogger.histogram(getContext(), "note_load", items);
754 EventLogTags.writeNotificationPanelRevealed(items);
761 public void onPanelHidden() {
762 MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL);
763 EventLogTags.writeNotificationPanelHidden();
767 public void clearEffects() {
768 synchronized (mNotificationLock) {
769 if (DBG) Slog.d(TAG, "clearEffects");
771 clearVibrateLocked();
777 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
778 int uid, int initialPid, String message, int userId) {
779 Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
780 + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
781 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
783 long ident = Binder.clearCallingIdentity();
785 ActivityManager.getService().crashApplication(uid, initialPid, pkg, -1,
786 "Bad notification posted from package " + pkg
788 } catch (RemoteException e) {
790 Binder.restoreCallingIdentity(ident);
794 public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
795 NotificationVisibility[] noLongerVisibleKeys) {
796 synchronized (mNotificationLock) {
797 for (NotificationVisibility nv : newlyVisibleKeys) {
798 NotificationRecord r = mNotificationsByKey.get(nv.key);
799 if (r == null) continue;
801 // Report to usage stats that notification was made visible
802 if (DBG) Slog.d(TAG, "Marking notification as visible " + nv.key);
805 r.setVisibility(true, nv.rank);
808 // Note that we might receive this event after notifications
809 // have already left the system, e.g. after dismissing from the
810 // shade. Hence not finding notifications in
811 // mNotificationsByKey is not an exceptional condition.
812 for (NotificationVisibility nv : noLongerVisibleKeys) {
813 NotificationRecord r = mNotificationsByKey.get(nv.key);
814 if (r == null) continue;
815 r.setVisibility(false, nv.rank);
822 public void onNotificationExpansionChanged(String key,
823 boolean userAction, boolean expanded) {
824 synchronized (mNotificationLock) {
825 NotificationRecord r = mNotificationsByKey.get(key);
827 r.stats.onExpansionChanged(userAction, expanded);
828 final long now = System.currentTimeMillis();
830 MetricsLogger.action(r.getLogMaker(now)
831 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
832 .setType(expanded ? MetricsEvent.TYPE_DETAIL
833 : MetricsEvent.TYPE_COLLAPSE));
835 if (expanded && userAction) {
838 EventLogTags.writeNotificationExpansion(key,
839 userAction ? 1 : 0, expanded ? 1 : 0,
840 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
846 public void onNotificationDirectReplied(String key) {
848 synchronized (mNotificationLock) {
849 NotificationRecord r = mNotificationsByKey.get(key);
851 r.recordDirectReplied();
852 reportUserInteraction(r);
858 public void onNotificationSettingsViewed(String key) {
859 synchronized (mNotificationLock) {
860 NotificationRecord r = mNotificationsByKey.get(key);
862 r.recordViewedSettings();
868 @GuardedBy("mNotificationLock")
869 private void clearSoundLocked() {
870 mSoundNotificationKey = null;
871 long identity = Binder.clearCallingIdentity();
873 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
874 if (player != null) {
877 } catch (RemoteException e) {
879 Binder.restoreCallingIdentity(identity);
883 @GuardedBy("mNotificationLock")
884 private void clearVibrateLocked() {
885 mVibrateNotificationKey = null;
886 long identity = Binder.clearCallingIdentity();
890 Binder.restoreCallingIdentity(identity);
894 @GuardedBy("mNotificationLock")
895 private void clearLightsLocked() {
898 updateLightsLocked();
901 protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() {
903 public void onReceive(Context context, Intent intent) {
904 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
905 // update system notification channels
906 SystemNotificationChannels.createAll(context);
907 mZenModeHelper.updateDefaultZenRules();
908 mRankingHelper.onLocaleChanged(context, ActivityManager.getCurrentUser());
913 private final BroadcastReceiver mRestoreReceiver = new BroadcastReceiver() {
915 public void onReceive(Context context, Intent intent) {
916 if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
918 String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
919 String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
920 int restoredFromSdkInt = intent.getIntExtra(
921 Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, 0);
922 mListeners.onSettingRestored(
923 element, newValue, restoredFromSdkInt, getSendingUserId());
924 mConditionProviders.onSettingRestored(
925 element, newValue, restoredFromSdkInt, getSendingUserId());
926 } catch (Exception e) {
927 Slog.wtf(TAG, "Cannot restore managed services from settings", e);
933 private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() {
935 public void onReceive(Context context, Intent intent) {
936 String action = intent.getAction();
937 if (action == null) {
940 if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) {
941 final NotificationRecord record;
942 synchronized (mNotificationLock) {
943 record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
945 if (record != null) {
946 cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(),
947 record.sbn.getPackageName(), record.sbn.getTag(),
948 record.sbn.getId(), 0,
949 Notification.FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
950 REASON_TIMEOUT, null);
956 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
958 public void onReceive(Context context, Intent intent) {
959 String action = intent.getAction();
960 if (action == null) {
964 boolean queryRestart = false;
965 boolean queryRemove = false;
966 boolean packageChanged = false;
967 boolean cancelNotifications = true;
968 boolean hideNotifications = false;
969 boolean unhideNotifications = false;
970 int reason = REASON_PACKAGE_CHANGED;
972 if (action.equals(Intent.ACTION_PACKAGE_ADDED)
973 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
974 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
975 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
976 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
977 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
978 || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)
979 || action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) {
980 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
981 UserHandle.USER_ALL);
982 String pkgList[] = null;
983 int uidList[] = null;
984 boolean removingPackage = queryRemove &&
985 !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
986 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
987 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
988 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
989 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
990 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
991 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
992 cancelNotifications = false;
993 hideNotifications = true;
994 } else if (action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) {
995 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
996 cancelNotifications = false;
997 unhideNotifications = true;
998 } else if (queryRestart) {
999 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
1000 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
1002 Uri uri = intent.getData();
1006 String pkgName = uri.getSchemeSpecificPart();
1007 if (pkgName == null) {
1010 if (packageChanged) {
1011 // We cancel notifications for packages which have just been disabled
1013 final int enabled = mPackageManager.getApplicationEnabledSetting(
1015 changeUserId != UserHandle.USER_ALL ? changeUserId :
1017 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
1018 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
1019 cancelNotifications = false;
1021 } catch (IllegalArgumentException e) {
1022 // Package doesn't exist; probably racing with uninstall.
1023 // cancelNotifications is already true, so nothing to do here.
1025 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
1027 } catch (RemoteException e) {
1028 // Failed to talk to PackageManagerService Should never happen!
1031 pkgList = new String[]{pkgName};
1032 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
1034 if (pkgList != null && (pkgList.length > 0)) {
1035 for (String pkgName : pkgList) {
1036 if (cancelNotifications) {
1037 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0,
1038 !queryRestart, changeUserId, reason, null);
1039 } else if (hideNotifications) {
1040 hideNotificationsForPackages(pkgList);
1041 } else if (unhideNotifications) {
1042 unhideNotificationsForPackages(pkgList);
1048 mListeners.onPackagesChanged(removingPackage, pkgList, uidList);
1049 mAssistants.onPackagesChanged(removingPackage, pkgList, uidList);
1050 mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList);
1051 mRankingHelper.onPackagesChanged(removingPackage, changeUserId, pkgList, uidList);
1057 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
1059 public void onReceive(Context context, Intent intent) {
1060 String action = intent.getAction();
1062 if (action.equals(Intent.ACTION_SCREEN_ON)) {
1063 // Keep track of screen on/off state, but do not turn off the notification light
1064 // until user passes through the lock screen or views the notification.
1066 updateNotificationPulse();
1067 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1069 updateNotificationPulse();
1070 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
1071 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
1072 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
1073 updateNotificationPulse();
1074 } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
1075 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
1076 if (userHandle >= 0) {
1077 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
1078 REASON_USER_STOPPED, null);
1080 } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
1081 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
1082 if (userHandle >= 0) {
1083 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
1084 REASON_PROFILE_TURNED_OFF, null);
1086 } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
1087 // turn off LED when user passes through lock screen
1088 mNotificationLight.turnOff();
1089 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
1090 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1091 // reload per-user settings
1092 mSettingsObserver.update(null);
1093 mUserProfiles.updateCache(context);
1094 // Refresh managed services
1095 mConditionProviders.onUserSwitched(user);
1096 mListeners.onUserSwitched(user);
1097 mAssistants.onUserSwitched(user);
1098 mZenModeHelper.onUserSwitched(user);
1099 } else if (action.equals(Intent.ACTION_USER_ADDED)) {
1100 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1101 if (userId != USER_NULL) {
1102 mUserProfiles.updateCache(context);
1103 if (!mUserProfiles.isManagedProfile(userId)) {
1104 readDefaultApprovedServices(userId);
1107 } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
1108 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1109 mUserProfiles.updateCache(context);
1110 mZenModeHelper.onUserRemoved(user);
1111 mRankingHelper.onUserRemoved(user);
1112 mListeners.onUserRemoved(user);
1113 mConditionProviders.onUserRemoved(user);
1114 mAssistants.onUserRemoved(user);
1116 } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
1117 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1118 mConditionProviders.onUserUnlocked(user);
1119 mListeners.onUserUnlocked(user);
1120 mAssistants.onUserUnlocked(user);
1121 mZenModeHelper.onUserUnlocked(user);
1126 private final class SettingsObserver extends ContentObserver {
1127 private final Uri NOTIFICATION_BADGING_URI
1128 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING);
1129 private final Uri NOTIFICATION_LIGHT_PULSE_URI
1130 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
1131 private final Uri NOTIFICATION_RATE_LIMIT_URI
1132 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
1134 SettingsObserver(Handler handler) {
1139 ContentResolver resolver = getContext().getContentResolver();
1140 resolver.registerContentObserver(NOTIFICATION_BADGING_URI,
1141 false, this, UserHandle.USER_ALL);
1142 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
1143 false, this, UserHandle.USER_ALL);
1144 resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
1145 false, this, UserHandle.USER_ALL);
1149 @Override public void onChange(boolean selfChange, Uri uri) {
1153 public void update(Uri uri) {
1154 ContentResolver resolver = getContext().getContentResolver();
1155 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
1156 boolean pulseEnabled = Settings.System.getIntForUser(resolver,
1157 Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT) != 0;
1158 if (mNotificationPulseEnabled != pulseEnabled) {
1159 mNotificationPulseEnabled = pulseEnabled;
1160 updateNotificationPulse();
1163 if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
1164 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
1165 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
1167 if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) {
1168 mRankingHelper.updateBadgingEnabled();
1173 private SettingsObserver mSettingsObserver;
1174 protected ZenModeHelper mZenModeHelper;
1176 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
1177 int[] ar = r.getIntArray(resid);
1181 final int len = ar.length > maxlen ? maxlen : ar.length;
1182 long[] out = new long[len];
1183 for (int i=0; i<len; i++) {
1189 public NotificationManagerService(Context context) {
1191 Notification.processWhitelistToken = WHITELIST_TOKEN;
1194 // TODO - replace these methods with a single VisibleForTesting constructor
1196 void setAudioManager(AudioManager audioMananger) {
1197 mAudioManager = audioMananger;
1201 void setVibrator(Vibrator vibrator) {
1202 mVibrator = vibrator;
1206 void setLights(Light light) {
1207 mNotificationLight = light;
1208 mAttentionLight = light;
1209 mNotificationPulseEnabled = true;
1213 void setScreenOn(boolean on) {
1218 int getNotificationRecordCount() {
1219 synchronized (mNotificationLock) {
1220 int count = mNotificationList.size() + mNotificationsByKey.size()
1221 + mSummaryByGroupKey.size() + mEnqueuedNotifications.size();
1222 // subtract duplicates
1223 for (NotificationRecord posted : mNotificationList) {
1224 if (mNotificationsByKey.containsKey(posted.getKey())) {
1227 if (posted.sbn.isGroup() && posted.getNotification().isGroupSummary()) {
1237 void clearNotifications() {
1238 mEnqueuedNotifications.clear();
1239 mNotificationList.clear();
1240 mNotificationsByKey.clear();
1241 mSummaryByGroupKey.clear();
1245 void addNotification(NotificationRecord r) {
1246 mNotificationList.add(r);
1247 mNotificationsByKey.put(r.sbn.getKey(), r);
1248 if (r.sbn.isGroup()) {
1249 mSummaryByGroupKey.put(r.getGroupKey(), r);
1254 void addEnqueuedNotification(NotificationRecord r) {
1255 mEnqueuedNotifications.add(r);
1259 NotificationRecord getNotificationRecord(String key) {
1260 return mNotificationsByKey.get(key);
1265 void setSystemReady(boolean systemReady) {
1266 mSystemReady = systemReady;
1270 void setHandler(WorkerHandler handler) {
1275 void setFallbackVibrationPattern(long[] vibrationPattern) {
1276 mFallbackVibrationPattern = vibrationPattern;
1280 void setPackageManager(IPackageManager packageManager) {
1281 mPackageManager = packageManager;
1285 void setRankingHelper(RankingHelper rankingHelper) {
1286 mRankingHelper = rankingHelper;
1290 void setRankingHandler(RankingHandler rankingHandler) {
1291 mRankingHandler = rankingHandler;
1295 void setIsTelevision(boolean isTelevision) {
1296 mIsTelevision = isTelevision;
1300 void setUsageStats(NotificationUsageStats us) {
1305 void setAccessibilityManager(AccessibilityManager am) {
1306 mAccessibilityManager = am;
1309 // TODO: All tests should use this init instead of the one-off setters above.
1311 void init(Looper looper, IPackageManager packageManager,
1312 PackageManager packageManagerClient,
1313 LightsManager lightsManager, NotificationListeners notificationListeners,
1314 NotificationAssistants notificationAssistants, ConditionProviders conditionProviders,
1315 ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
1316 NotificationUsageStats usageStats, AtomicFile policyFile,
1317 ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am,
1318 UsageStatsManagerInternal appUsageStats) {
1319 Resources resources = getContext().getResources();
1320 mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
1321 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
1322 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
1324 mAccessibilityManager =
1325 (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
1327 mPackageManager = packageManager;
1328 mPackageManagerClient = packageManagerClient;
1329 mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
1330 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
1331 mAppUsageStats = appUsageStats;
1332 mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
1333 mCompanionManager = companionManager;
1334 mActivityManager = activityManager;
1335 mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
1336 ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
1338 mPermissionOwner = mAm.newUriPermissionOwner("notification");
1339 } catch (RemoteException e) {
1340 Slog.w(TAG, "AM dead", e);
1343 mHandler = new WorkerHandler(looper);
1344 mRankingThread.start();
1345 String[] extractorNames;
1347 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
1348 } catch (Resources.NotFoundException e) {
1349 extractorNames = new String[0];
1351 mUsageStats = usageStats;
1352 mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
1353 mConditionProviders = conditionProviders;
1354 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
1355 mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
1357 public void onConfigChanged() {
1362 void onZenModeChanged() {
1363 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
1364 getContext().sendBroadcastAsUser(
1365 new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
1366 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
1367 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
1368 synchronized (mNotificationLock) {
1369 updateInterruptionFilterLocked();
1371 mRankingHandler.requestSort();
1375 void onPolicyChanged() {
1376 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
1377 mRankingHandler.requestSort();
1380 mRankingHelper = new RankingHelper(getContext(),
1381 mPackageManagerClient,
1386 mSnoozeHelper = snoozeHelper;
1387 mGroupHelper = groupHelper;
1389 // This is a ManagedServices object that keeps track of the listeners.
1390 mListeners = notificationListeners;
1392 // This is a MangedServices object that keeps track of the assistant.
1393 mAssistants = notificationAssistants;
1395 mPolicyFile = policyFile;
1398 mStatusBar = getLocalService(StatusBarManagerInternal.class);
1399 if (mStatusBar != null) {
1400 mStatusBar.setNotificationDelegate(mNotificationDelegate);
1403 mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
1404 mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
1406 mFallbackVibrationPattern = getLongArray(resources,
1407 R.array.config_notificationFallbackVibePattern,
1408 VIBRATE_PATTERN_MAXLEN,
1409 DEFAULT_VIBRATE_PATTERN);
1410 mInCallNotificationUri = Uri.parse("file://" +
1411 resources.getString(R.string.config_inCallNotificationSound));
1412 mInCallNotificationAudioAttributes = new AudioAttributes.Builder()
1413 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
1414 .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
1416 mInCallNotificationVolume = resources.getFloat(R.dimen.config_inCallNotificationVolume);
1418 mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
1420 // Don't start allowing notifications until the setup wizard has run once.
1421 // After that, including subsequent boots, init with notifications turned on.
1422 // This works on the first boot because the setup wizard will toggle this
1423 // flag at least once and we'll go back to 0 after that.
1424 if (0 == Settings.Global.getInt(getContext().getContentResolver(),
1425 Settings.Global.DEVICE_PROVISIONED, 0)) {
1426 mDisableNotificationEffects = true;
1428 mZenModeHelper.initZenMode();
1429 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1431 mUserProfiles.updateCache(getContext());
1432 listenForCallState();
1434 mSettingsObserver = new SettingsObserver(mHandler);
1436 mArchive = new Archive(resources.getInteger(
1437 R.integer.config_notificationServiceArchiveSize));
1439 mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
1440 || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
1444 public void onStart() {
1445 SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() {
1447 public void repost(int userId, NotificationRecord r) {
1450 Slog.d(TAG, "Reposting " + r.getKey());
1452 enqueueNotificationInternal(r.sbn.getPackageName(), r.sbn.getOpPkg(),
1453 r.sbn.getUid(), r.sbn.getInitialPid(), r.sbn.getTag(), r.sbn.getId(),
1454 r.sbn.getNotification(), userId);
1455 } catch (Exception e) {
1456 Slog.e(TAG, "Cannot un-snooze notification", e);
1461 final File systemDir = new File(Environment.getDataDirectory(), "system");
1463 init(Looper.myLooper(),
1464 AppGlobals.getPackageManager(), getContext().getPackageManager(),
1465 getLocalService(LightsManager.class),
1466 new NotificationListeners(AppGlobals.getPackageManager()),
1467 new NotificationAssistants(getContext(), mNotificationLock, mUserProfiles,
1468 AppGlobals.getPackageManager()),
1469 new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()),
1470 null, snoozeHelper, new NotificationUsageStats(getContext()),
1471 new AtomicFile(new File(systemDir, "notification_policy.xml"), "notification-policy"),
1472 (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE),
1473 getGroupHelper(), ActivityManager.getService(),
1474 LocalServices.getService(UsageStatsManagerInternal.class));
1476 // register for various Intents
1477 IntentFilter filter = new IntentFilter();
1478 filter.addAction(Intent.ACTION_SCREEN_ON);
1479 filter.addAction(Intent.ACTION_SCREEN_OFF);
1480 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
1481 filter.addAction(Intent.ACTION_USER_PRESENT);
1482 filter.addAction(Intent.ACTION_USER_STOPPED);
1483 filter.addAction(Intent.ACTION_USER_SWITCHED);
1484 filter.addAction(Intent.ACTION_USER_ADDED);
1485 filter.addAction(Intent.ACTION_USER_REMOVED);
1486 filter.addAction(Intent.ACTION_USER_UNLOCKED);
1487 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
1488 getContext().registerReceiver(mIntentReceiver, filter);
1490 IntentFilter pkgFilter = new IntentFilter();
1491 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
1492 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1493 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
1494 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1495 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1496 pkgFilter.addDataScheme("package");
1497 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1500 IntentFilter suspendedPkgFilter = new IntentFilter();
1501 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
1502 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
1503 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1504 suspendedPkgFilter, null, null);
1506 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
1507 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1510 IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
1511 timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
1512 getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter);
1514 IntentFilter settingsRestoredFilter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
1515 getContext().registerReceiver(mRestoreReceiver, settingsRestoredFilter);
1517 IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
1518 getContext().registerReceiver(mLocaleChangeReceiver, localeChangedFilter);
1520 publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
1521 DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL);
1522 publishLocalService(NotificationManagerInternal.class, mInternalService);
1525 private GroupHelper getGroupHelper() {
1526 return new GroupHelper(new GroupHelper.Callback() {
1528 public void addAutoGroup(String key) {
1529 synchronized (mNotificationLock) {
1530 addAutogroupKeyLocked(key);
1535 public void removeAutoGroup(String key) {
1536 synchronized (mNotificationLock) {
1537 removeAutogroupKeyLocked(key);
1542 public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) {
1543 createAutoGroupSummary(userId, pkg, triggeringKey);
1547 public void removeAutoGroupSummary(int userId, String pkg) {
1548 synchronized (mNotificationLock) {
1549 clearAutogroupSummaryLocked(userId, pkg);
1555 private void sendRegisteredOnlyBroadcast(String action) {
1556 getContext().sendBroadcastAsUser(new Intent(action)
1557 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
1561 public void onBootPhase(int phase) {
1562 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1563 // no beeping until we're basically done booting
1564 mSystemReady = true;
1566 // Grab our optional AudioService
1567 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
1568 mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
1569 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
1570 mZenModeHelper.onSystemReady();
1571 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1572 // This observer will force an update when observe is called, causing us to
1573 // bind to listener services.
1574 mSettingsObserver.observe();
1575 mListeners.onBootPhaseAppsCanStart();
1576 mAssistants.onBootPhaseAppsCanStart();
1577 mConditionProviders.onBootPhaseAppsCanStart();
1581 @GuardedBy("mNotificationLock")
1582 private void updateListenerHintsLocked() {
1583 final int hints = calculateHints();
1584 if (hints == mListenerHints) return;
1585 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
1586 mListenerHints = hints;
1587 scheduleListenerHintsChanged(hints);
1590 @GuardedBy("mNotificationLock")
1591 private void updateEffectsSuppressorLocked() {
1592 final long updatedSuppressedEffects = calculateSuppressedEffects();
1593 if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1594 final List<ComponentName> suppressors = getSuppressors();
1595 ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1596 mEffectsSuppressors = suppressors;
1597 mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
1598 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
1601 private void exitIdle() {
1603 if (mDeviceIdleController != null) {
1604 mDeviceIdleController.exitIdle("notification interaction");
1606 } catch (RemoteException e) {
1610 private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
1611 boolean fromListener) {
1612 if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
1614 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
1615 UserHandle.getUserId(uid), REASON_CHANNEL_BANNED,
1617 if (isUidSystemOrPhone(uid)) {
1618 int[] profileIds = mUserProfiles.getCurrentProfileIds();
1619 int N = profileIds.length;
1620 for (int i = 0; i < N; i++) {
1621 int profileId = profileIds[i];
1622 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
1623 profileId, REASON_CHANNEL_BANNED,
1628 final NotificationChannel preUpdate =
1629 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), true);
1631 mRankingHelper.updateNotificationChannel(pkg, uid, channel, true);
1632 maybeNotifyChannelOwner(pkg, uid, preUpdate, channel);
1634 if (!fromListener) {
1635 final NotificationChannel modifiedChannel =
1636 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
1637 mListeners.notifyNotificationChannelChanged(
1638 pkg, UserHandle.getUserHandleForUid(uid),
1639 modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
1645 private void maybeNotifyChannelOwner(String pkg, int uid, NotificationChannel preUpdate,
1646 NotificationChannel update) {
1648 if ((preUpdate.getImportance() == IMPORTANCE_NONE
1649 && update.getImportance() != IMPORTANCE_NONE)
1650 || (preUpdate.getImportance() != IMPORTANCE_NONE
1651 && update.getImportance() == IMPORTANCE_NONE)) {
1652 getContext().sendBroadcastAsUser(
1653 new Intent(ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED)
1654 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID,
1656 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
1657 update.getImportance() == IMPORTANCE_NONE)
1658 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
1660 UserHandle.of(UserHandle.getUserId(uid)), null);
1662 } catch (SecurityException e) {
1663 Slog.w(TAG, "Can't notify app about channel change", e);
1667 private void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
1668 boolean fromApp, boolean fromListener) {
1669 Preconditions.checkNotNull(group);
1670 Preconditions.checkNotNull(pkg);
1672 final NotificationChannelGroup preUpdate =
1673 mRankingHelper.getNotificationChannelGroup(group.getId(), pkg, uid);
1674 mRankingHelper.createNotificationChannelGroup(pkg, uid, group,
1677 maybeNotifyChannelGroupOwner(pkg, uid, preUpdate, group);
1679 if (!fromListener) {
1680 mListeners.notifyNotificationChannelGroupChanged(pkg,
1681 UserHandle.of(UserHandle.getCallingUserId()), group,
1682 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1686 private void maybeNotifyChannelGroupOwner(String pkg, int uid,
1687 NotificationChannelGroup preUpdate, NotificationChannelGroup update) {
1689 if (preUpdate.isBlocked() != update.isBlocked()) {
1690 getContext().sendBroadcastAsUser(
1691 new Intent(ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED)
1692 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID,
1694 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
1696 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
1698 UserHandle.of(UserHandle.getUserId(uid)), null);
1700 } catch (SecurityException e) {
1701 Slog.w(TAG, "Can't notify app about group change", e);
1705 private ArrayList<ComponentName> getSuppressors() {
1706 ArrayList<ComponentName> names = new ArrayList<ComponentName>();
1707 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1708 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1710 for (ManagedServiceInfo info : serviceInfoList) {
1711 names.add(info.component);
1718 private boolean removeDisabledHints(ManagedServiceInfo info) {
1719 return removeDisabledHints(info, 0);
1722 private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
1723 boolean removed = false;
1725 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1726 final int hint = mListenersDisablingEffects.keyAt(i);
1727 final ArraySet<ManagedServiceInfo> listeners =
1728 mListenersDisablingEffects.valueAt(i);
1730 if (hints == 0 || (hint & hints) == hint) {
1731 removed = removed || listeners.remove(info);
1738 private void addDisabledHints(ManagedServiceInfo info, int hints) {
1739 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1740 addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
1743 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1744 addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1747 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1748 addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
1752 private void addDisabledHint(ManagedServiceInfo info, int hint) {
1753 if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
1754 mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
1757 ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
1758 hintListeners.add(info);
1761 private int calculateHints() {
1763 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1764 int hint = mListenersDisablingEffects.keyAt(i);
1765 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1767 if (!serviceInfoList.isEmpty()) {
1775 private long calculateSuppressedEffects() {
1776 int hints = calculateHints();
1777 long suppressedEffects = 0;
1779 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1780 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
1783 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1784 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
1787 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1788 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
1791 return suppressedEffects;
1794 @GuardedBy("mNotificationLock")
1795 private void updateInterruptionFilterLocked() {
1796 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1797 if (interruptionFilter == mInterruptionFilter) return;
1798 mInterruptionFilter = interruptionFilter;
1799 scheduleInterruptionFilterChanged(interruptionFilter);
1803 INotificationManager getBinderService() {
1804 return INotificationManager.Stub.asInterface(mService);
1808 * Report to usage stats that the notification was seen.
1809 * @param r notification record
1811 @GuardedBy("mNotificationLock")
1812 protected void reportSeen(NotificationRecord r) {
1813 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
1814 getRealUserId(r.sbn.getUserId()),
1815 UsageEvents.Event.NOTIFICATION_SEEN);
1818 protected int calculateSuppressedVisualEffects(Policy incomingPolicy, Policy currPolicy,
1819 int targetSdkVersion) {
1820 if (incomingPolicy.suppressedVisualEffects == SUPPRESSED_EFFECTS_UNSET) {
1821 return incomingPolicy.suppressedVisualEffects;
1823 final int[] effectsIntroducedInP = {
1824 SUPPRESSED_EFFECT_FULL_SCREEN_INTENT,
1825 SUPPRESSED_EFFECT_LIGHTS,
1826 SUPPRESSED_EFFECT_PEEK,
1827 SUPPRESSED_EFFECT_STATUS_BAR,
1828 SUPPRESSED_EFFECT_BADGE,
1829 SUPPRESSED_EFFECT_AMBIENT,
1830 SUPPRESSED_EFFECT_NOTIFICATION_LIST
1833 int newSuppressedVisualEffects = incomingPolicy.suppressedVisualEffects;
1834 if (targetSdkVersion <= Build.VERSION_CODES.O_MR1) {
1835 // unset higher order bits introduced in P, maintain the user's higher order bits
1836 for (int i = 0; i < effectsIntroducedInP.length ; i++) {
1837 newSuppressedVisualEffects &= ~effectsIntroducedInP[i];
1838 newSuppressedVisualEffects |=
1839 (currPolicy.suppressedVisualEffects & effectsIntroducedInP[i]);
1841 // set higher order bits according to lower order bits
1842 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
1843 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
1844 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
1845 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_AMBIENT;
1847 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
1848 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
1851 boolean hasNewEffects = (newSuppressedVisualEffects
1852 - SUPPRESSED_EFFECT_SCREEN_ON - SUPPRESSED_EFFECT_SCREEN_OFF) > 0;
1853 // if any of the new effects introduced in P are set
1854 if (hasNewEffects) {
1855 // clear out the deprecated effects
1856 newSuppressedVisualEffects &= ~ (SUPPRESSED_EFFECT_SCREEN_ON
1857 | SUPPRESSED_EFFECT_SCREEN_OFF);
1859 // set the deprecated effects according to the new more specific effects
1860 if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_PEEK) != 0) {
1861 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_ON;
1863 if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_LIGHTS) != 0
1864 && (newSuppressedVisualEffects
1865 & Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT) != 0
1866 && (newSuppressedVisualEffects
1867 & Policy.SUPPRESSED_EFFECT_AMBIENT) != 0) {
1868 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_OFF;
1871 // set higher order bits according to lower order bits
1872 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
1873 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
1874 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
1875 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_AMBIENT;
1877 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
1878 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
1883 return newSuppressedVisualEffects;
1886 @GuardedBy("mNotificationLock")
1887 protected void maybeRecordInterruptionLocked(NotificationRecord r) {
1888 if (r.isInterruptive()) {
1889 mAppUsageStats.reportInterruptiveNotification(r.sbn.getPackageName(),
1890 r.getChannel().getId(),
1891 getRealUserId(r.sbn.getUserId()));
1897 * Report to usage stats that the notification was clicked.
1898 * @param r notification record
1900 protected void reportUserInteraction(NotificationRecord r) {
1901 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
1902 getRealUserId(r.sbn.getUserId()),
1903 UsageEvents.Event.USER_INTERACTION);
1906 private int getRealUserId(int userId) {
1907 return userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId;
1911 NotificationManagerInternal getInternalService() {
1912 return mInternalService;
1915 private final IBinder mService = new INotificationManager.Stub() {
1917 // ============================================================================
1920 public void enqueueToast(String pkg, ITransientNotification callback, int duration)
1923 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1924 + " duration=" + duration);
1927 if (pkg == null || callback == null) {
1928 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1931 final boolean isSystemToast = isCallerSystemOrPhone() || ("android".equals(pkg));
1932 final boolean isPackageSuspended =
1933 isPackageSuspendedForUser(pkg, Binder.getCallingUid());
1935 if (ENABLE_BLOCKED_TOASTS && !isSystemToast &&
1936 (!areNotificationsEnabledForPackage(pkg, Binder.getCallingUid())
1937 || isPackageSuspended)) {
1938 Slog.e(TAG, "Suppressing toast from package " + pkg
1939 + (isPackageSuspended
1940 ? " due to package suspended by administrator."
1941 : " by user request."));
1945 synchronized (mToastQueue) {
1946 int callingPid = Binder.getCallingPid();
1947 long callingId = Binder.clearCallingIdentity();
1951 // All packages aside from the android package can enqueue one toast at a time
1952 if (!isSystemToast) {
1953 index = indexOfToastPackageLocked(pkg);
1955 index = indexOfToastLocked(pkg, callback);
1958 // If the package already has a toast, we update its toast
1959 // in the queue, we don't move it to the end of the queue.
1961 record = mToastQueue.get(index);
1962 record.update(duration);
1964 record.callback.hide();
1965 } catch (RemoteException e) {
1967 record.update(callback);
1969 Binder token = new Binder();
1970 mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, DEFAULT_DISPLAY);
1971 record = new ToastRecord(callingPid, pkg, callback, duration, token);
1972 mToastQueue.add(record);
1973 index = mToastQueue.size() - 1;
1975 keepProcessAliveIfNeededLocked(callingPid);
1976 // If it's at index 0, it's the current toast. It doesn't matter if it's
1977 // new or just been updated. Call back and tell it to show itself.
1978 // If the callback fails, this will remove it from the list, so don't
1979 // assume that it's valid after this.
1981 showNextToastLocked();
1984 Binder.restoreCallingIdentity(callingId);
1990 public void cancelToast(String pkg, ITransientNotification callback) {
1991 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
1993 if (pkg == null || callback == null) {
1994 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
1998 synchronized (mToastQueue) {
1999 long callingId = Binder.clearCallingIdentity();
2001 int index = indexOfToastLocked(pkg, callback);
2003 cancelToastLocked(index);
2005 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
2006 + " callback=" + callback);
2009 Binder.restoreCallingIdentity(callingId);
2015 public void finishToken(String pkg, ITransientNotification callback) {
2016 synchronized (mToastQueue) {
2017 long callingId = Binder.clearCallingIdentity();
2019 int index = indexOfToastLocked(pkg, callback);
2021 ToastRecord record = mToastQueue.get(index);
2022 finishTokenLocked(record.token);
2024 Slog.w(TAG, "Toast already killed. pkg=" + pkg
2025 + " callback=" + callback);
2028 Binder.restoreCallingIdentity(callingId);
2034 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
2035 Notification notification, int userId) throws RemoteException {
2036 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
2037 Binder.getCallingPid(), tag, id, notification, userId);
2041 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
2042 checkCallerIsSystemOrSameApp(pkg);
2043 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2044 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
2045 // Don't allow client applications to cancel foreground service notis or autobundled
2047 final int mustNotHaveFlags = isCallingUidSystem() ? 0 :
2048 (Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTOGROUP_SUMMARY);
2049 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
2050 mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null);
2054 public void cancelAllNotifications(String pkg, int userId) {
2055 checkCallerIsSystemOrSameApp(pkg);
2057 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2058 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
2060 // Calling from user space, don't allow the canceling of actively
2061 // running foreground services.
2062 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
2063 pkg, null, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
2064 REASON_APP_CANCEL_ALL, null);
2068 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
2069 enforceSystemOrSystemUI("setNotificationsEnabledForPackage");
2071 mRankingHelper.setEnabled(pkg, uid, enabled);
2072 // Now, cancel any outstanding notifications that are part of a just-disabled app
2074 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
2075 UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
2079 getContext().sendBroadcastAsUser(
2080 new Intent(ACTION_APP_BLOCK_STATE_CHANGED)
2081 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE, !enabled)
2082 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
2084 UserHandle.of(UserHandle.getUserId(uid)), null);
2085 } catch (SecurityException e) {
2086 Slog.w(TAG, "Can't notify app about app block change", e);
2093 * Use this when you just want to know if notifications are OK for this package.
2096 public boolean areNotificationsEnabled(String pkg) {
2097 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
2101 * Use this when you just want to know if notifications are OK for this package.
2104 public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
2105 checkCallerIsSystemOrSameApp(pkg);
2107 return mRankingHelper.getImportance(pkg, uid) != IMPORTANCE_NONE;
2111 public int getPackageImportance(String pkg) {
2112 checkCallerIsSystemOrSameApp(pkg);
2113 return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
2117 public boolean canShowBadge(String pkg, int uid) {
2118 checkCallerIsSystem();
2119 return mRankingHelper.canShowBadge(pkg, uid);
2123 public void setShowBadge(String pkg, int uid, boolean showBadge) {
2124 checkCallerIsSystem();
2125 mRankingHelper.setShowBadge(pkg, uid, showBadge);
2130 public void updateNotificationChannelGroupForPackage(String pkg, int uid,
2131 NotificationChannelGroup group) throws RemoteException {
2132 enforceSystemOrSystemUI("Caller not system or systemui");
2133 createNotificationChannelGroup(pkg, uid, group, false, false);
2138 public void createNotificationChannelGroups(String pkg,
2139 ParceledListSlice channelGroupList) throws RemoteException {
2140 checkCallerIsSystemOrSameApp(pkg);
2141 List<NotificationChannelGroup> groups = channelGroupList.getList();
2142 final int groupSize = groups.size();
2143 for (int i = 0; i < groupSize; i++) {
2144 final NotificationChannelGroup group = groups.get(i);
2145 createNotificationChannelGroup(pkg, Binder.getCallingUid(), group, true, false);
2150 private void createNotificationChannelsImpl(String pkg, int uid,
2151 ParceledListSlice channelsList) {
2152 List<NotificationChannel> channels = channelsList.getList();
2153 final int channelsSize = channels.size();
2154 for (int i = 0; i < channelsSize; i++) {
2155 final NotificationChannel channel = channels.get(i);
2156 Preconditions.checkNotNull(channel, "channel in list is null");
2157 mRankingHelper.createNotificationChannel(pkg, uid, channel,
2158 true /* fromTargetApp */, mConditionProviders.isPackageOrComponentAllowed(
2159 pkg, UserHandle.getUserId(uid)));
2160 mListeners.notifyNotificationChannelChanged(pkg,
2161 UserHandle.getUserHandleForUid(uid),
2162 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false),
2163 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
2169 public void createNotificationChannels(String pkg,
2170 ParceledListSlice channelsList) throws RemoteException {
2171 checkCallerIsSystemOrSameApp(pkg);
2172 createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList);
2176 public void createNotificationChannelsForPackage(String pkg, int uid,
2177 ParceledListSlice channelsList) throws RemoteException {
2178 checkCallerIsSystem();
2179 createNotificationChannelsImpl(pkg, uid, channelsList);
2183 public NotificationChannel getNotificationChannel(String pkg, String channelId) {
2184 checkCallerIsSystemOrSameApp(pkg);
2185 return mRankingHelper.getNotificationChannel(
2186 pkg, Binder.getCallingUid(), channelId, false /* includeDeleted */);
2190 public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
2191 String channelId, boolean includeDeleted) {
2192 checkCallerIsSystem();
2193 return mRankingHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted);
2197 public void deleteNotificationChannel(String pkg, String channelId) {
2198 checkCallerIsSystemOrSameApp(pkg);
2199 final int callingUid = Binder.getCallingUid();
2200 if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
2201 throw new IllegalArgumentException("Cannot delete default channel");
2203 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
2204 UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
2205 mRankingHelper.deleteNotificationChannel(pkg, callingUid, channelId);
2206 mListeners.notifyNotificationChannelChanged(pkg,
2207 UserHandle.getUserHandleForUid(callingUid),
2208 mRankingHelper.getNotificationChannel(pkg, callingUid, channelId, true),
2209 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
2214 public NotificationChannelGroup getNotificationChannelGroup(String pkg, String groupId) {
2215 checkCallerIsSystemOrSameApp(pkg);
2216 return mRankingHelper.getNotificationChannelGroupWithChannels(
2217 pkg, Binder.getCallingUid(), groupId, false);
2221 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
2223 checkCallerIsSystemOrSameApp(pkg);
2224 return mRankingHelper.getNotificationChannelGroups(
2225 pkg, Binder.getCallingUid(), false, false);
2229 public void deleteNotificationChannelGroup(String pkg, String groupId) {
2230 checkCallerIsSystemOrSameApp(pkg);
2232 final int callingUid = Binder.getCallingUid();
2233 NotificationChannelGroup groupToDelete =
2234 mRankingHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
2235 if (groupToDelete != null) {
2236 List<NotificationChannel> deletedChannels =
2237 mRankingHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
2238 for (int i = 0; i < deletedChannels.size(); i++) {
2239 final NotificationChannel deletedChannel = deletedChannels.get(i);
2240 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
2242 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
2244 mListeners.notifyNotificationChannelChanged(pkg,
2245 UserHandle.getUserHandleForUid(callingUid),
2247 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
2249 mListeners.notifyNotificationChannelGroupChanged(
2250 pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete,
2251 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
2257 public void updateNotificationChannelForPackage(String pkg, int uid,
2258 NotificationChannel channel) {
2259 enforceSystemOrSystemUI("Caller not system or systemui");
2260 Preconditions.checkNotNull(channel);
2261 updateNotificationChannelInt(pkg, uid, channel, false);
2265 public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
2266 int uid, boolean includeDeleted) {
2267 enforceSystemOrSystemUI("getNotificationChannelsForPackage");
2268 return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted);
2272 public int getNumNotificationChannelsForPackage(String pkg, int uid,
2273 boolean includeDeleted) {
2274 enforceSystemOrSystemUI("getNumNotificationChannelsForPackage");
2275 return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted)
2280 public boolean onlyHasDefaultChannel(String pkg, int uid) {
2281 enforceSystemOrSystemUI("onlyHasDefaultChannel");
2282 return mRankingHelper.onlyHasDefaultChannel(pkg, uid);
2286 public int getDeletedChannelCount(String pkg, int uid) {
2287 enforceSystemOrSystemUI("getDeletedChannelCount");
2288 return mRankingHelper.getDeletedChannelCount(pkg, uid);
2292 public int getBlockedChannelCount(String pkg, int uid) {
2293 enforceSystemOrSystemUI("getBlockedChannelCount");
2294 return mRankingHelper.getBlockedChannelCount(pkg, uid);
2298 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
2299 String pkg, int uid, boolean includeDeleted) {
2300 checkCallerIsSystem();
2301 return mRankingHelper.getNotificationChannelGroups(pkg, uid, includeDeleted, true);
2305 public NotificationChannelGroup getPopulatedNotificationChannelGroupForPackage(
2306 String pkg, int uid, String groupId, boolean includeDeleted) {
2307 enforceSystemOrSystemUI("getPopulatedNotificationChannelGroupForPackage");
2308 return mRankingHelper.getNotificationChannelGroupWithChannels(
2309 pkg, uid, groupId, includeDeleted);
2313 public NotificationChannelGroup getNotificationChannelGroupForPackage(
2314 String groupId, String pkg, int uid) {
2315 enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
2316 return mRankingHelper.getNotificationChannelGroup(groupId, pkg, uid);
2320 public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
2321 checkCallerIsSystemOrSameApp(pkg);
2322 return mRankingHelper.getNotificationChannels(
2323 pkg, Binder.getCallingUid(), false /* includeDeleted */);
2327 public ParceledListSlice<NotifyingApp> getRecentNotifyingAppsForUser(int userId) {
2328 checkCallerIsSystem();
2329 synchronized (mNotificationLock) {
2330 List<NotifyingApp> apps = new ArrayList<>(
2331 mRecentApps.getOrDefault(userId, new ArrayList<>()));
2332 return new ParceledListSlice<>(apps);
2337 public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
2338 checkCallerIsSystem();
2340 // Cancel posted notifications
2341 cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true,
2342 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
2344 final String[] packages = new String[] {packageName};
2345 final int[] uids = new int[] {uid};
2347 // Listener & assistant
2348 mListeners.onPackagesChanged(true, packages, uids);
2349 mAssistants.onPackagesChanged(true, packages, uids);
2352 mConditionProviders.onPackagesChanged(true, packages, uids);
2354 // Reset notification preferences
2356 mRankingHelper.onPackagesChanged(
2357 true, UserHandle.getCallingUserId(), packages, uids);
2365 * System-only API for getting a list of current (i.e. not cleared) notifications.
2367 * Requires ACCESS_NOTIFICATIONS which is signature|system.
2368 * @returns A list of all the notifications, in natural order.
2371 public StatusBarNotification[] getActiveNotifications(String callingPkg) {
2372 // enforce() will ensure the calling uid has the correct permission
2373 getContext().enforceCallingOrSelfPermission(
2374 android.Manifest.permission.ACCESS_NOTIFICATIONS,
2375 "NotificationManagerService.getActiveNotifications");
2377 StatusBarNotification[] tmp = null;
2378 int uid = Binder.getCallingUid();
2380 // noteOp will check to make sure the callingPkg matches the uid
2381 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2382 == AppOpsManager.MODE_ALLOWED) {
2383 synchronized (mNotificationLock) {
2384 tmp = new StatusBarNotification[mNotificationList.size()];
2385 final int N = mNotificationList.size();
2386 for (int i=0; i<N; i++) {
2387 tmp[i] = mNotificationList.get(i).sbn;
2395 * Public API for getting a list of current notifications for the calling package/uid.
2397 * Note that since notification posting is done asynchronously, this will not return
2398 * notifications that are in the process of being posted.
2400 * @returns A list of all the package's notifications, in natural order.
2403 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
2404 int incomingUserId) {
2405 checkCallerIsSystemOrSameApp(pkg);
2406 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2407 Binder.getCallingUid(), incomingUserId, true, false,
2408 "getAppActiveNotifications", pkg);
2409 synchronized (mNotificationLock) {
2410 final ArrayMap<String, StatusBarNotification> map
2411 = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
2412 final int N = mNotificationList.size();
2413 for (int i = 0; i < N; i++) {
2414 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2415 mNotificationList.get(i).sbn);
2417 map.put(sbn.getKey(), sbn);
2420 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
2421 StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn);
2423 map.put(sbn.getKey(), sbn);
2426 final int M = mEnqueuedNotifications.size();
2427 for (int i = 0; i < M; i++) {
2428 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2429 mEnqueuedNotifications.get(i).sbn);
2431 map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
2434 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
2435 list.addAll(map.values());
2436 return new ParceledListSlice<StatusBarNotification>(list);
2440 private StatusBarNotification sanitizeSbn(String pkg, int userId,
2441 StatusBarNotification sbn) {
2442 if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId) {
2443 // We could pass back a cloneLight() but clients might get confused and
2444 // try to send this thing back to notify() again, which would not work
2446 return new StatusBarNotification(
2447 sbn.getPackageName(),
2449 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
2450 sbn.getNotification().clone(),
2451 sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
2457 * System-only API for getting a list of recent (cleared, no longer shown) notifications.
2459 * Requires ACCESS_NOTIFICATIONS which is signature|system.
2462 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
2463 // enforce() will ensure the calling uid has the correct permission
2464 getContext().enforceCallingOrSelfPermission(
2465 android.Manifest.permission.ACCESS_NOTIFICATIONS,
2466 "NotificationManagerService.getHistoricalNotifications");
2468 StatusBarNotification[] tmp = null;
2469 int uid = Binder.getCallingUid();
2471 // noteOp will check to make sure the callingPkg matches the uid
2472 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2473 == AppOpsManager.MODE_ALLOWED) {
2474 synchronized (mArchive) {
2475 tmp = mArchive.getArray(count);
2482 * Register a listener binder directly with the notification manager.
2484 * Only works with system callers. Apps should extend
2485 * {@link android.service.notification.NotificationListenerService}.
2488 public void registerListener(final INotificationListener listener,
2489 final ComponentName component, final int userid) {
2490 enforceSystemOrSystemUI("INotificationManager.registerListener");
2491 mListeners.registerService(listener, component, userid);
2495 * Remove a listener binder directly
2498 public void unregisterListener(INotificationListener token, int userid) {
2499 mListeners.unregisterService(token, userid);
2503 * Allow an INotificationListener to simulate a "clear all" operation.
2505 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
2507 * @param token The binder for the listener, to check that the caller is allowed
2510 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
2511 final int callingUid = Binder.getCallingUid();
2512 final int callingPid = Binder.getCallingPid();
2513 long identity = Binder.clearCallingIdentity();
2515 synchronized (mNotificationLock) {
2516 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2519 final int N = keys.length;
2520 for (int i = 0; i < N; i++) {
2521 NotificationRecord r = mNotificationsByKey.get(keys[i]);
2522 if (r == null) continue;
2523 final int userId = r.sbn.getUserId();
2524 if (userId != info.userid && userId != UserHandle.USER_ALL &&
2525 !mUserProfiles.isCurrentProfile(userId)) {
2526 throw new SecurityException("Disallowed call from listener: "
2529 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2530 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
2534 cancelAllLocked(callingUid, callingPid, info.userid,
2535 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
2539 Binder.restoreCallingIdentity(identity);
2544 * Handle request from an approved listener to re-enable itself.
2546 * @param component The componenet to be re-enabled, caller must match package.
2549 public void requestBindListener(ComponentName component) {
2550 checkCallerIsSystemOrSameApp(component.getPackageName());
2551 long identity = Binder.clearCallingIdentity();
2553 ManagedServices manager =
2554 mAssistants.isComponentEnabledForCurrentProfiles(component)
2557 manager.setComponentState(component, true);
2559 Binder.restoreCallingIdentity(identity);
2564 public void requestUnbindListener(INotificationListener token) {
2565 long identity = Binder.clearCallingIdentity();
2567 // allow bound services to disable themselves
2568 synchronized (mNotificationLock) {
2569 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2570 info.getOwner().setComponentState(info.component, false);
2573 Binder.restoreCallingIdentity(identity);
2578 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
2579 long identity = Binder.clearCallingIdentity();
2581 synchronized (mNotificationLock) {
2582 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2584 final int N = keys.length;
2585 for (int i = 0; i < N; i++) {
2586 NotificationRecord r = mNotificationsByKey.get(keys[i]);
2587 if (r == null) continue;
2588 final int userId = r.sbn.getUserId();
2589 if (userId != info.userid && userId != UserHandle.USER_ALL &&
2590 !mUserProfiles.isCurrentProfile(userId)) {
2591 throw new SecurityException("Disallowed call from listener: "
2595 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
2603 Binder.restoreCallingIdentity(identity);
2608 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2610 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2612 * @param info The binder for the listener, to check that the caller is allowed
2614 @GuardedBy("mNotificationLock")
2615 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
2616 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
2617 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
2618 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
2620 userId, REASON_LISTENER_CANCEL, info);
2624 * Allow an INotificationListener to snooze a single notification until a context.
2626 * @param token The binder for the listener, to check that the caller is allowed
2629 public void snoozeNotificationUntilContextFromListener(INotificationListener token,
2630 String key, String snoozeCriterionId) {
2631 long identity = Binder.clearCallingIdentity();
2633 synchronized (mNotificationLock) {
2634 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2635 snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info);
2638 Binder.restoreCallingIdentity(identity);
2643 * Allow an INotificationListener to snooze a single notification until a time.
2645 * @param token The binder for the listener, to check that the caller is allowed
2648 public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
2650 long identity = Binder.clearCallingIdentity();
2652 synchronized (mNotificationLock) {
2653 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2654 snoozeNotificationInt(key, duration, null, info);
2657 Binder.restoreCallingIdentity(identity);
2662 * Allows the notification assistant to un-snooze a single notification.
2664 * @param token The binder for the assistant, to check that the caller is allowed
2667 public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
2668 long identity = Binder.clearCallingIdentity();
2670 synchronized (mNotificationLock) {
2671 final ManagedServiceInfo info =
2672 mAssistants.checkServiceTokenLocked(token);
2673 unsnoozeNotificationInt(key, info);
2676 Binder.restoreCallingIdentity(identity);
2681 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2683 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2685 * @param token The binder for the listener, to check that the caller is allowed
2688 public void cancelNotificationFromListener(INotificationListener token, String pkg,
2689 String tag, int id) {
2690 final int callingUid = Binder.getCallingUid();
2691 final int callingPid = Binder.getCallingPid();
2692 long identity = Binder.clearCallingIdentity();
2694 synchronized (mNotificationLock) {
2695 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2696 if (info.supportsProfiles()) {
2697 Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
2698 + "from " + info.component
2699 + " use cancelNotification(key) instead.");
2701 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2702 pkg, tag, id, info.userid);
2706 Binder.restoreCallingIdentity(identity);
2711 * Allow an INotificationListener to request the list of outstanding notifications seen by
2712 * the current user. Useful when starting up, after which point the listener callbacks
2715 * @param token The binder for the listener, to check that the caller is allowed
2716 * @param keys An array of notification keys to fetch, or null to fetch everything
2717 * @returns The return value will contain the notifications specified in keys, in that
2718 * order, or if keys is null, all the notifications, in natural order.
2721 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
2722 INotificationListener token, String[] keys, int trim) {
2723 synchronized (mNotificationLock) {
2724 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2725 final boolean getKeys = keys != null;
2726 final int N = getKeys ? keys.length : mNotificationList.size();
2727 final ArrayList<StatusBarNotification> list
2728 = new ArrayList<StatusBarNotification>(N);
2729 for (int i=0; i<N; i++) {
2730 final NotificationRecord r = getKeys
2731 ? mNotificationsByKey.get(keys[i])
2732 : mNotificationList.get(i);
2733 if (r == null) continue;
2734 StatusBarNotification sbn = r.sbn;
2735 if (!isVisibleToListener(sbn, info)) continue;
2736 StatusBarNotification sbnToSend =
2737 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2738 list.add(sbnToSend);
2740 return new ParceledListSlice<StatusBarNotification>(list);
2745 * Allow an INotificationListener to request the list of outstanding snoozed notifications
2746 * seen by the current user. Useful when starting up, after which point the listener
2747 * callbacks should be used.
2749 * @param token The binder for the listener, to check that the caller is allowed
2750 * @returns The return value will contain the notifications specified in keys, in that
2751 * order, or if keys is null, all the notifications, in natural order.
2754 public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
2755 INotificationListener token, int trim) {
2756 synchronized (mNotificationLock) {
2757 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2758 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
2759 final int N = snoozedRecords.size();
2760 final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
2761 for (int i=0; i < N; i++) {
2762 final NotificationRecord r = snoozedRecords.get(i);
2763 if (r == null) continue;
2764 StatusBarNotification sbn = r.sbn;
2765 if (!isVisibleToListener(sbn, info)) continue;
2766 StatusBarNotification sbnToSend =
2767 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2768 list.add(sbnToSend);
2770 return new ParceledListSlice<>(list);
2775 public void requestHintsFromListener(INotificationListener token, int hints) {
2776 final long identity = Binder.clearCallingIdentity();
2778 synchronized (mNotificationLock) {
2779 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2780 final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
2781 | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
2782 | HINT_HOST_DISABLE_CALL_EFFECTS;
2783 final boolean disableEffects = (hints & disableEffectsMask) != 0;
2784 if (disableEffects) {
2785 addDisabledHints(info, hints);
2787 removeDisabledHints(info, hints);
2789 updateListenerHintsLocked();
2790 updateEffectsSuppressorLocked();
2793 Binder.restoreCallingIdentity(identity);
2798 public int getHintsFromListener(INotificationListener token) {
2799 synchronized (mNotificationLock) {
2800 return mListenerHints;
2805 public void requestInterruptionFilterFromListener(INotificationListener token,
2806 int interruptionFilter) throws RemoteException {
2807 final long identity = Binder.clearCallingIdentity();
2809 synchronized (mNotificationLock) {
2810 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2811 mZenModeHelper.requestFromListener(info.component, interruptionFilter);
2812 updateInterruptionFilterLocked();
2815 Binder.restoreCallingIdentity(identity);
2820 public int getInterruptionFilterFromListener(INotificationListener token)
2821 throws RemoteException {
2822 synchronized (mNotificationLight) {
2823 return mInterruptionFilter;
2828 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
2829 throws RemoteException {
2830 synchronized (mNotificationLock) {
2831 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2832 if (info == null) return;
2833 mListeners.setOnNotificationPostedTrimLocked(info, trim);
2838 public int getZenMode() {
2839 return mZenModeHelper.getZenMode();
2843 public ZenModeConfig getZenModeConfig() {
2844 enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
2845 return mZenModeHelper.getConfig();
2849 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
2850 enforceSystemOrSystemUI("INotificationManager.setZenMode");
2851 final long identity = Binder.clearCallingIdentity();
2853 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
2855 Binder.restoreCallingIdentity(identity);
2860 public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
2861 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
2862 return mZenModeHelper.getZenRules();
2866 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
2867 Preconditions.checkNotNull(id, "Id is null");
2868 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
2869 return mZenModeHelper.getAutomaticZenRule(id);
2873 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
2874 throws RemoteException {
2875 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2876 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2877 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2878 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2879 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
2881 return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
2882 "addAutomaticZenRule");
2886 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
2887 throws RemoteException {
2888 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2889 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2890 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2891 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2892 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
2894 return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
2895 "updateAutomaticZenRule");
2899 public boolean removeAutomaticZenRule(String id) throws RemoteException {
2900 Preconditions.checkNotNull(id, "Id is null");
2901 // Verify that they can modify zen rules.
2902 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
2904 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
2908 public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
2909 Preconditions.checkNotNull(packageName, "Package name is null");
2910 enforceSystemOrSystemUI("removeAutomaticZenRules");
2912 return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
2916 public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
2917 Preconditions.checkNotNull(owner, "Owner is null");
2918 enforceSystemOrSystemUI("getRuleInstanceCount");
2920 return mZenModeHelper.getCurrentInstanceCount(owner);
2924 public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
2925 enforcePolicyAccess(pkg, "setInterruptionFilter");
2926 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
2927 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
2928 final long identity = Binder.clearCallingIdentity();
2930 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
2932 Binder.restoreCallingIdentity(identity);
2937 public void notifyConditions(final String pkg, IConditionProvider provider,
2938 final Condition[] conditions) {
2939 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2940 checkCallerIsSystemOrSameApp(pkg);
2941 mHandler.post(new Runnable() {
2944 mConditionProviders.notifyConditions(pkg, info, conditions);
2950 public void requestUnbindProvider(IConditionProvider provider) {
2951 long identity = Binder.clearCallingIdentity();
2953 // allow bound services to disable themselves
2954 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2955 info.getOwner().setComponentState(info.component, false);
2957 Binder.restoreCallingIdentity(identity);
2962 public void requestBindProvider(ComponentName component) {
2963 checkCallerIsSystemOrSameApp(component.getPackageName());
2964 long identity = Binder.clearCallingIdentity();
2966 mConditionProviders.setComponentState(component, true);
2968 Binder.restoreCallingIdentity(identity);
2972 private void enforceSystemOrSystemUI(String message) {
2973 if (isCallerSystemOrPhone()) return;
2974 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
2978 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
2980 checkCallerIsSystemOrSameApp(pkg);
2981 } catch (SecurityException e) {
2982 getContext().enforceCallingPermission(
2983 android.Manifest.permission.STATUS_BAR_SERVICE,
2988 private void enforcePolicyAccess(int uid, String method) {
2989 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2990 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2993 boolean accessAllowed = false;
2994 String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
2995 final int packageCount = packages.length;
2996 for (int i = 0; i < packageCount; i++) {
2997 if (mConditionProviders.isPackageOrComponentAllowed(
2998 packages[i], UserHandle.getUserId(uid))) {
2999 accessAllowed = true;
3002 if (!accessAllowed) {
3003 Slog.w(TAG, "Notification policy access denied calling " + method);
3004 throw new SecurityException("Notification policy access denied");
3008 private void enforcePolicyAccess(String pkg, String method) {
3009 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
3010 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
3013 checkCallerIsSameApp(pkg);
3014 if (!checkPolicyAccess(pkg)) {
3015 Slog.w(TAG, "Notification policy access denied calling " + method);
3016 throw new SecurityException("Notification policy access denied");
3020 private boolean checkPackagePolicyAccess(String pkg) {
3021 return mConditionProviders.isPackageOrComponentAllowed(
3022 pkg, getCallingUserHandle().getIdentifier());
3025 private boolean checkPolicyAccess(String pkg) {
3027 int uid = getContext().getPackageManager().getPackageUidAsUser(
3028 pkg, UserHandle.getCallingUserId());
3029 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
3030 android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
3034 } catch (NameNotFoundException e) {
3037 return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
3041 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
3042 if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
3043 final DumpFilter filter = DumpFilter.parseFromArguments(args);
3045 dumpJson(pw, filter);
3046 } else if (filter.proto) {
3047 dumpProto(fd, filter);
3048 } else if (filter.criticalPriority) {
3049 dumpNotificationRecords(pw, filter);
3051 dumpImpl(pw, filter);
3056 public ComponentName getEffectsSuppressor() {
3057 return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
3061 public boolean matchesCallFilter(Bundle extras) {
3062 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
3063 return mZenModeHelper.matchesCallFilter(
3064 Binder.getCallingUserHandle(),
3066 mRankingHelper.findExtractor(ValidateNotificationPeople.class),
3067 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
3068 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
3072 public boolean isSystemConditionProviderEnabled(String path) {
3073 enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
3074 return mConditionProviders.isSystemProviderEnabled(path);
3077 // Backup/restore interface
3079 public byte[] getBackupPayload(int user) {
3080 checkCallerIsSystem();
3081 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
3082 //TODO: http://b/22388012
3083 if (user != USER_SYSTEM) {
3084 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
3087 synchronized(mPolicyFile) {
3088 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
3090 writePolicyXml(baos, true /*forBackup*/);
3091 return baos.toByteArray();
3092 } catch (IOException e) {
3093 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
3100 public void applyRestore(byte[] payload, int user) {
3101 checkCallerIsSystem();
3102 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
3103 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
3104 if (payload == null) {
3105 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
3108 //TODO: http://b/22388012
3109 if (user != USER_SYSTEM) {
3110 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
3113 synchronized(mPolicyFile) {
3114 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
3116 readPolicyXml(bais, true /*forRestore*/);
3118 } catch (NumberFormatException | XmlPullParserException | IOException e) {
3119 Slog.w(TAG, "applyRestore: error reading payload", e);
3125 public boolean isNotificationPolicyAccessGranted(String pkg) {
3126 return checkPolicyAccess(pkg);
3130 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
3131 enforceSystemOrSystemUIOrSamePackage(pkg,
3132 "request policy access status for another package");
3133 return checkPolicyAccess(pkg);
3137 public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
3138 throws RemoteException {
3139 setNotificationPolicyAccessGrantedForUser(
3140 pkg, getCallingUserHandle().getIdentifier(), granted);
3144 public void setNotificationPolicyAccessGrantedForUser(
3145 String pkg, int userId, boolean granted) {
3146 checkCallerIsSystemOrShell();
3147 final long identity = Binder.clearCallingIdentity();
3149 if (canUseManagedServices()) {
3150 mConditionProviders.setPackageOrComponentEnabled(
3151 pkg, userId, true, granted);
3153 getContext().sendBroadcastAsUser(new Intent(
3154 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
3156 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
3157 UserHandle.of(userId), null);
3161 Binder.restoreCallingIdentity(identity);
3166 public Policy getNotificationPolicy(String pkg) {
3167 final long identity = Binder.clearCallingIdentity();
3169 return mZenModeHelper.getNotificationPolicy();
3171 Binder.restoreCallingIdentity(identity);
3176 * Sets the notification policy. Apps that target API levels below
3177 * {@link android.os.Build.VERSION_CODES#P} cannot change user-designated values to
3178 * allow or disallow {@link Policy#PRIORITY_CATEGORY_ALARMS},
3179 * {@link Policy#PRIORITY_CATEGORY_SYSTEM} and
3180 * {@link Policy#PRIORITY_CATEGORY_MEDIA} from bypassing dnd
3183 public void setNotificationPolicy(String pkg, Policy policy) {
3184 enforcePolicyAccess(pkg, "setNotificationPolicy");
3185 final long identity = Binder.clearCallingIdentity();
3187 final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(pkg,
3188 0, UserHandle.getUserId(MY_UID));
3189 Policy currPolicy = mZenModeHelper.getNotificationPolicy();
3191 if (applicationInfo.targetSdkVersion <= Build.VERSION_CODES.O_MR1) {
3192 int priorityCategories = policy.priorityCategories;
3193 // ignore alarm and media values from new policy
3194 priorityCategories &= ~Policy.PRIORITY_CATEGORY_ALARMS;
3195 priorityCategories &= ~Policy.PRIORITY_CATEGORY_MEDIA;
3196 priorityCategories &= ~Policy.PRIORITY_CATEGORY_SYSTEM;
3197 // use user-designated values
3198 priorityCategories |= currPolicy.priorityCategories
3199 & Policy.PRIORITY_CATEGORY_ALARMS;
3200 priorityCategories |= currPolicy.priorityCategories
3201 & Policy.PRIORITY_CATEGORY_MEDIA;
3202 priorityCategories |= currPolicy.priorityCategories
3203 & Policy.PRIORITY_CATEGORY_SYSTEM;
3205 policy = new Policy(priorityCategories,
3206 policy.priorityCallSenders, policy.priorityMessageSenders,
3207 policy.suppressedVisualEffects);
3209 int newVisualEffects = calculateSuppressedVisualEffects(
3210 policy, currPolicy, applicationInfo.targetSdkVersion);
3211 policy = new Policy(policy.priorityCategories,
3212 policy.priorityCallSenders, policy.priorityMessageSenders,
3215 ZenLog.traceSetNotificationPolicy(pkg, applicationInfo.targetSdkVersion, policy);
3216 mZenModeHelper.setNotificationPolicy(policy);
3217 } catch (RemoteException e) {
3219 Binder.restoreCallingIdentity(identity);
3224 public List<String> getEnabledNotificationListenerPackages() {
3225 checkCallerIsSystem();
3226 return mListeners.getAllowedPackages(getCallingUserHandle().getIdentifier());
3230 public List<ComponentName> getEnabledNotificationListeners(int userId) {
3231 checkCallerIsSystem();
3232 return mListeners.getAllowedComponents(userId);
3236 public boolean isNotificationListenerAccessGranted(ComponentName listener) {
3237 Preconditions.checkNotNull(listener);
3238 checkCallerIsSystemOrSameApp(listener.getPackageName());
3239 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
3240 getCallingUserHandle().getIdentifier());
3244 public boolean isNotificationListenerAccessGrantedForUser(ComponentName listener,
3246 Preconditions.checkNotNull(listener);
3247 checkCallerIsSystem();
3248 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
3253 public boolean isNotificationAssistantAccessGranted(ComponentName assistant) {
3254 Preconditions.checkNotNull(assistant);
3255 checkCallerIsSystemOrSameApp(assistant.getPackageName());
3256 return mAssistants.isPackageOrComponentAllowed(assistant.flattenToString(),
3257 getCallingUserHandle().getIdentifier());
3261 public void setNotificationListenerAccessGranted(ComponentName listener,
3262 boolean granted) throws RemoteException {
3263 setNotificationListenerAccessGrantedForUser(
3264 listener, getCallingUserHandle().getIdentifier(), granted);
3268 public void setNotificationAssistantAccessGranted(ComponentName assistant,
3269 boolean granted) throws RemoteException {
3270 setNotificationAssistantAccessGrantedForUser(
3271 assistant, getCallingUserHandle().getIdentifier(), granted);
3275 public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
3276 boolean granted) throws RemoteException {
3277 Preconditions.checkNotNull(listener);
3278 checkCallerIsSystemOrShell();
3279 final long identity = Binder.clearCallingIdentity();
3281 if (canUseManagedServices()) {
3282 mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
3283 userId, false, granted);
3284 mListeners.setPackageOrComponentEnabled(listener.flattenToString(),
3285 userId, true, granted);
3287 getContext().sendBroadcastAsUser(new Intent(
3288 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
3289 .setPackage(listener.getPackageName())
3290 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
3291 UserHandle.of(userId), null);
3296 Binder.restoreCallingIdentity(identity);
3301 public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
3302 int userId, boolean granted) throws RemoteException {
3303 Preconditions.checkNotNull(assistant);
3304 checkCallerIsSystemOrShell();
3305 final long identity = Binder.clearCallingIdentity();
3307 if (canUseManagedServices()) {
3308 mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
3309 userId, false, granted);
3310 mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
3311 userId, true, granted);
3313 getContext().sendBroadcastAsUser(new Intent(
3314 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
3315 .setPackage(assistant.getPackageName())
3316 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
3317 UserHandle.of(userId), null);
3322 Binder.restoreCallingIdentity(identity);
3327 public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
3328 Adjustment adjustment) throws RemoteException {
3329 final long identity = Binder.clearCallingIdentity();
3331 synchronized (mNotificationLock) {
3332 mAssistants.checkServiceTokenLocked(token);
3333 int N = mEnqueuedNotifications.size();
3334 for (int i = 0; i < N; i++) {
3335 final NotificationRecord n = mEnqueuedNotifications.get(i);
3336 if (Objects.equals(adjustment.getKey(), n.getKey())
3337 && Objects.equals(adjustment.getUser(), n.getUserId())) {
3338 applyAdjustment(n, adjustment);
3344 Binder.restoreCallingIdentity(identity);
3349 public void applyAdjustmentFromAssistant(INotificationListener token,
3350 Adjustment adjustment) throws RemoteException {
3351 final long identity = Binder.clearCallingIdentity();
3353 synchronized (mNotificationLock) {
3354 mAssistants.checkServiceTokenLocked(token);
3355 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
3356 applyAdjustment(n, adjustment);
3358 mRankingHandler.requestSort();
3360 Binder.restoreCallingIdentity(identity);
3365 public void applyAdjustmentsFromAssistant(INotificationListener token,
3366 List<Adjustment> adjustments) throws RemoteException {
3368 final long identity = Binder.clearCallingIdentity();
3370 synchronized (mNotificationLock) {
3371 mAssistants.checkServiceTokenLocked(token);
3372 for (Adjustment adjustment : adjustments) {
3373 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
3374 applyAdjustment(n, adjustment);
3377 mRankingHandler.requestSort();
3379 Binder.restoreCallingIdentity(identity);
3384 public void updateNotificationChannelGroupFromPrivilegedListener(
3385 INotificationListener token, String pkg, UserHandle user,
3386 NotificationChannelGroup group) throws RemoteException {
3387 Preconditions.checkNotNull(user);
3388 verifyPrivilegedListener(token, user);
3389 createNotificationChannelGroup(
3390 pkg, getUidForPackageAndUser(pkg, user), group, false, true);
3395 public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
3396 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
3397 Preconditions.checkNotNull(channel);
3398 Preconditions.checkNotNull(pkg);
3399 Preconditions.checkNotNull(user);
3401 verifyPrivilegedListener(token, user);
3402 updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
3406 public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
3407 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
3408 Preconditions.checkNotNull(pkg);
3409 Preconditions.checkNotNull(user);
3410 verifyPrivilegedListener(token, user);
3412 return mRankingHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user),
3413 false /* includeDeleted */);
3417 public ParceledListSlice<NotificationChannelGroup>
3418 getNotificationChannelGroupsFromPrivilegedListener(
3419 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
3420 Preconditions.checkNotNull(pkg);
3421 Preconditions.checkNotNull(user);
3422 verifyPrivilegedListener(token, user);
3424 List<NotificationChannelGroup> groups = new ArrayList<>();
3425 groups.addAll(mRankingHelper.getNotificationChannelGroups(
3426 pkg, getUidForPackageAndUser(pkg, user)));
3427 return new ParceledListSlice<>(groups);
3430 private void verifyPrivilegedListener(INotificationListener token, UserHandle user) {
3431 ManagedServiceInfo info;
3432 synchronized (mNotificationLock) {
3433 info = mListeners.checkServiceTokenLocked(token);
3435 if (!hasCompanionDevice(info)) {
3436 throw new SecurityException(info + " does not have access");
3438 if (!info.enabledAndUserMatches(user.getIdentifier())) {
3439 throw new SecurityException(info + " does not have access");
3443 private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
3445 long identity = Binder.clearCallingIdentity();
3447 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
3449 Binder.restoreCallingIdentity(identity);
3455 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
3456 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
3457 throws RemoteException {
3458 new ShellCmd().exec(this, in, out, err, args, callback, resultReceiver);
3462 private void applyAdjustment(NotificationRecord r, Adjustment adjustment) {
3466 if (adjustment.getSignals() != null) {
3467 Bundle.setDefusable(adjustment.getSignals(), true);
3468 r.addAdjustment(adjustment);
3472 @GuardedBy("mNotificationLock")
3473 void addAutogroupKeyLocked(String key) {
3474 NotificationRecord r = mNotificationsByKey.get(key);
3478 if (r.sbn.getOverrideGroupKey() == null) {
3479 addAutoGroupAdjustment(r, GroupHelper.AUTOGROUP_KEY);
3480 EventLogTags.writeNotificationAutogrouped(key);
3481 mRankingHandler.requestSort();
3485 @GuardedBy("mNotificationLock")
3486 void removeAutogroupKeyLocked(String key) {
3487 NotificationRecord r = mNotificationsByKey.get(key);
3491 if (r.sbn.getOverrideGroupKey() != null) {
3492 addAutoGroupAdjustment(r, null);
3493 EventLogTags.writeNotificationUnautogrouped(key);
3494 mRankingHandler.requestSort();
3498 private void addAutoGroupAdjustment(NotificationRecord r, String overrideGroupKey) {
3499 Bundle signals = new Bundle();
3500 signals.putString(Adjustment.KEY_GROUP_KEY, overrideGroupKey);
3501 Adjustment adjustment =
3502 new Adjustment(r.sbn.getPackageName(), r.getKey(), signals, "", r.sbn.getUserId());
3503 r.addAdjustment(adjustment);
3506 // Clears the 'fake' auto-group summary.
3507 @GuardedBy("mNotificationLock")
3508 private void clearAutogroupSummaryLocked(int userId, String pkg) {
3509 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3510 if (summaries != null && summaries.containsKey(pkg)) {
3512 final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
3513 if (removed != null) {
3514 boolean wasPosted = removeFromNotificationListsLocked(removed);
3515 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED, wasPosted, null);
3520 @GuardedBy("mNotificationLock")
3521 private boolean hasAutoGroupSummaryLocked(StatusBarNotification sbn) {
3522 ArrayMap<String, String> summaries = mAutobundledSummaries.get(sbn.getUserId());
3523 return summaries != null && summaries.containsKey(sbn.getPackageName());
3526 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
3527 private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
3528 NotificationRecord summaryRecord = null;
3529 synchronized (mNotificationLock) {
3530 NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
3531 if (notificationRecord == null) {
3532 // The notification could have been cancelled again already. A successive
3533 // adjustment will post a summary if needed.
3536 final StatusBarNotification adjustedSbn = notificationRecord.sbn;
3537 userId = adjustedSbn.getUser().getIdentifier();
3538 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3539 if (summaries == null) {
3540 summaries = new ArrayMap<>();
3542 mAutobundledSummaries.put(userId, summaries);
3543 if (!summaries.containsKey(pkg)) {
3545 final ApplicationInfo appInfo =
3546 adjustedSbn.getNotification().extras.getParcelable(
3547 Notification.EXTRA_BUILDER_APPLICATION_INFO);
3548 final Bundle extras = new Bundle();
3549 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
3550 final String channelId = notificationRecord.getChannel().getId();
3551 final Notification summaryNotification =
3552 new Notification.Builder(getContext(), channelId)
3553 .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
3554 .setGroupSummary(true)
3555 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN)
3556 .setGroup(GroupHelper.AUTOGROUP_KEY)
3557 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
3558 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
3559 .setColor(adjustedSbn.getNotification().color)
3562 summaryNotification.extras.putAll(extras);
3563 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
3564 if (appIntent != null) {
3565 summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
3566 getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
3568 final StatusBarNotification summarySbn =
3569 new StatusBarNotification(adjustedSbn.getPackageName(),
3570 adjustedSbn.getOpPkg(),
3572 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
3573 adjustedSbn.getInitialPid(), summaryNotification,
3574 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
3575 System.currentTimeMillis());
3576 summaryRecord = new NotificationRecord(getContext(), summarySbn,
3577 notificationRecord.getChannel());
3578 summaries.put(pkg, summarySbn.getKey());
3581 if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
3582 summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord, true)) {
3583 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
3587 private String disableNotificationEffects(NotificationRecord record) {
3588 if (mDisableNotificationEffects) {
3589 return "booleanState";
3591 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
3592 return "listenerHints";
3594 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
3600 private void dumpJson(PrintWriter pw, @NonNull DumpFilter filter) {
3601 JSONObject dump = new JSONObject();
3603 dump.put("service", "Notification Manager");
3604 dump.put("bans", mRankingHelper.dumpBansJson(filter));
3605 dump.put("ranking", mRankingHelper.dumpJson(filter));
3606 dump.put("stats", mUsageStats.dumpJson(filter));
3607 dump.put("channels", mRankingHelper.dumpChannelsJson(filter));
3608 } catch (JSONException e) {
3609 e.printStackTrace();
3614 private void dumpProto(FileDescriptor fd, @NonNull DumpFilter filter) {
3615 final ProtoOutputStream proto = new ProtoOutputStream(fd);
3616 synchronized (mNotificationLock) {
3617 int N = mNotificationList.size();
3618 for (int i = 0; i < N; i++) {
3619 final NotificationRecord nr = mNotificationList.get(i);
3620 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3621 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3622 NotificationRecordProto.POSTED);
3624 N = mEnqueuedNotifications.size();
3625 for (int i = 0; i < N; i++) {
3626 final NotificationRecord nr = mEnqueuedNotifications.get(i);
3627 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3628 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3629 NotificationRecordProto.ENQUEUED);
3631 List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
3633 for (int i = 0; i < N; i++) {
3634 final NotificationRecord nr = snoozed.get(i);
3635 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3636 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3637 NotificationRecordProto.SNOOZED);
3640 long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
3641 mZenModeHelper.dump(proto);
3642 for (ComponentName suppressor : mEffectsSuppressors) {
3643 suppressor.writeToProto(proto, ZenModeProto.SUPPRESSORS);
3647 long listenersToken = proto.start(NotificationServiceDumpProto.NOTIFICATION_LISTENERS);
3648 mListeners.dump(proto, filter);
3649 proto.end(listenersToken);
3651 proto.write(NotificationServiceDumpProto.LISTENER_HINTS, mListenerHints);
3653 for (int i = 0; i < mListenersDisablingEffects.size(); ++i) {
3654 long effectsToken = proto.start(
3655 NotificationServiceDumpProto.LISTENERS_DISABLING_EFFECTS);
3658 ListenersDisablingEffectsProto.HINT, mListenersDisablingEffects.keyAt(i));
3659 final ArraySet<ManagedServiceInfo> listeners =
3660 mListenersDisablingEffects.valueAt(i);
3661 for (int j = 0; j < listeners.size(); j++) {
3662 final ManagedServiceInfo listener = listeners.valueAt(i);
3663 listener.writeToProto(proto, ListenersDisablingEffectsProto.LISTENERS, null);
3666 proto.end(effectsToken);
3669 long assistantsToken = proto.start(
3670 NotificationServiceDumpProto.NOTIFICATION_ASSISTANTS);
3671 mAssistants.dump(proto, filter);
3672 proto.end(assistantsToken);
3674 long conditionsToken = proto.start(NotificationServiceDumpProto.CONDITION_PROVIDERS);
3675 mConditionProviders.dump(proto, filter);
3676 proto.end(conditionsToken);
3678 long rankingToken = proto.start(NotificationServiceDumpProto.RANKING_CONFIG);
3679 mRankingHelper.dump(proto, filter);
3680 proto.end(rankingToken);
3686 private void dumpNotificationRecords(PrintWriter pw, @NonNull DumpFilter filter) {
3687 synchronized (mNotificationLock) {
3689 N = mNotificationList.size();
3691 pw.println(" Notification List:");
3692 for (int i = 0; i < N; i++) {
3693 final NotificationRecord nr = mNotificationList.get(i);
3694 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3695 nr.dump(pw, " ", getContext(), filter.redact);
3702 void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter) {
3703 pw.print("Current Notification Manager state");
3704 if (filter.filtered) {
3705 pw.print(" (filtered to "); pw.print(filter); pw.print(")");
3709 final boolean zenOnly = filter.filtered && filter.zen;
3712 synchronized (mToastQueue) {
3713 N = mToastQueue.size();
3715 pw.println(" Toast Queue:");
3716 for (int i=0; i<N; i++) {
3717 mToastQueue.get(i).dump(pw, " ", filter);
3724 synchronized (mNotificationLock) {
3726 // Priority filters are only set when called via bugreport. If set
3727 // skip sections that are part of the critical section.
3728 if (!filter.normalPriority) {
3729 dumpNotificationRecords(pw, filter);
3731 if (!filter.filtered) {
3734 pw.println(" Lights List:");
3735 for (int i=0; i<N; i++) {
3741 pw.println(mLights.get(i));
3745 pw.println(" mUseAttentionLight=" + mUseAttentionLight);
3746 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled);
3747 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey);
3748 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey);
3749 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects);
3750 pw.println(" mCallState=" + callStateToString(mCallState));
3751 pw.println(" mSystemReady=" + mSystemReady);
3752 pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
3754 pw.println(" mArchive=" + mArchive.toString());
3755 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
3757 while (iter.hasNext()) {
3758 final StatusBarNotification sbn = iter.next();
3759 if (filter != null && !filter.matches(sbn)) continue;
3760 pw.println(" " + sbn);
3762 if (iter.hasNext()) pw.println(" ...");
3768 N = mEnqueuedNotifications.size();
3770 pw.println(" Enqueued Notification List:");
3771 for (int i = 0; i < N; i++) {
3772 final NotificationRecord nr = mEnqueuedNotifications.get(i);
3773 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3774 nr.dump(pw, " ", getContext(), filter.redact);
3779 mSnoozeHelper.dump(pw, filter);
3784 pw.println("\n Ranking Config:");
3785 mRankingHelper.dump(pw, " ", filter);
3787 pw.println("\n Notification listeners:");
3788 mListeners.dump(pw, filter);
3789 pw.print(" mListenerHints: "); pw.println(mListenerHints);
3790 pw.print(" mListenersDisablingEffects: (");
3791 N = mListenersDisablingEffects.size();
3792 for (int i = 0; i < N; i++) {
3793 final int hint = mListenersDisablingEffects.keyAt(i);
3794 if (i > 0) pw.print(';');
3795 pw.print("hint[" + hint + "]:");
3797 final ArraySet<ManagedServiceInfo> listeners =
3798 mListenersDisablingEffects.valueAt(i);
3799 final int listenerSize = listeners.size();
3801 for (int j = 0; j < listenerSize; j++) {
3802 if (i > 0) pw.print(',');
3803 final ManagedServiceInfo listener = listeners.valueAt(i);
3804 pw.print(listener.component);
3808 pw.println("\n Notification assistant services:");
3809 mAssistants.dump(pw, filter);
3812 if (!filter.filtered || zenOnly) {
3813 pw.println("\n Zen Mode:");
3814 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter);
3815 mZenModeHelper.dump(pw, " ");
3817 pw.println("\n Zen Log:");
3818 ZenLog.dump(pw, " ");
3821 pw.println("\n Condition providers:");
3822 mConditionProviders.dump(pw, filter);
3824 pw.println("\n Group summaries:");
3825 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
3826 NotificationRecord r = entry.getValue();
3827 pw.println(" " + entry.getKey() + " -> " + r.getKey());
3828 if (mNotificationsByKey.get(r.getKey()) != r) {
3829 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
3830 r.dump(pw, " ", getContext(), filter.redact);
3835 pw.println("\n Usage Stats:");
3836 mUsageStats.dump(pw, " ", filter);
3842 * The private API only accessible to the system process.
3844 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
3846 public NotificationChannel getNotificationChannel(String pkg, int uid, String
3848 return mRankingHelper.getNotificationChannel(pkg, uid, channelId, false);
3852 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
3853 String tag, int id, Notification notification, int userId) {
3854 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
3859 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
3861 checkCallerIsSystem();
3862 mHandler.post(new Runnable() {
3865 synchronized (mNotificationLock) {
3866 removeForegroundServiceFlagByListLocked(
3867 mEnqueuedNotifications, pkg, notificationId, userId);
3868 removeForegroundServiceFlagByListLocked(
3869 mNotificationList, pkg, notificationId, userId);
3875 @GuardedBy("mNotificationLock")
3876 private void removeForegroundServiceFlagByListLocked(
3877 ArrayList<NotificationRecord> notificationList, String pkg, int notificationId,
3879 NotificationRecord r = findNotificationByListLocked(
3880 notificationList, pkg, null, notificationId, userId);
3884 StatusBarNotification sbn = r.sbn;
3885 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
3886 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
3887 // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
3888 // initially *and* force remove FLAG_FOREGROUND_SERVICE.
3889 sbn.getNotification().flags =
3890 (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
3891 mRankingHelper.sort(mNotificationList);
3892 mListeners.notifyPostedLocked(r, sbn /* oldSbn */);
3896 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
3897 final int callingPid, final String tag, final int id, final Notification notification,
3898 int incomingUserId) {
3900 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
3901 + " notification=" + notification);
3903 checkCallerIsSystemOrSameApp(pkg);
3905 final int userId = ActivityManager.handleIncomingUser(callingPid,
3906 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
3907 final UserHandle user = new UserHandle(userId);
3909 if (pkg == null || notification == null) {
3910 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
3911 + " id=" + id + " notification=" + notification);
3914 // The system can post notifications for any package, let us resolve that.
3915 final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);
3917 // Fix the notification as best we can.
3919 final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
3920 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
3921 (userId == UserHandle.USER_ALL) ? USER_SYSTEM : userId);
3922 Notification.addFieldsFromContext(ai, notification);
3924 int canColorize = mPackageManagerClient.checkPermission(
3925 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, pkg);
3926 if (canColorize == PERMISSION_GRANTED) {
3927 notification.flags |= Notification.FLAG_CAN_COLORIZE;
3929 notification.flags &= ~Notification.FLAG_CAN_COLORIZE;
3932 } catch (NameNotFoundException e) {
3933 Slog.e(TAG, "Cannot create a context for sending app", e);
3937 mUsageStats.registerEnqueuedByApp(pkg);
3939 // setup local book-keeping
3940 String channelId = notification.getChannelId();
3941 if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
3942 channelId = (new Notification.TvExtender(notification)).getChannelId();
3944 final NotificationChannel channel = mRankingHelper.getNotificationChannel(pkg,
3945 notificationUid, channelId, false /* includeDeleted */);
3946 if (channel == null) {
3947 final String noChannelStr = "No Channel found for "
3949 + ", channelId=" + channelId
3952 + ", opPkg=" + opPkg
3953 + ", callingUid=" + callingUid
3954 + ", userId=" + userId
3955 + ", incomingUserId=" + incomingUserId
3956 + ", notificationUid=" + notificationUid
3957 + ", notification=" + notification;
3958 Log.e(TAG, noChannelStr);
3959 doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
3960 "Failed to post notification on channel \"" + channelId + "\"\n" +
3961 "See log for more details");
3965 final StatusBarNotification n = new StatusBarNotification(
3966 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
3967 user, null, System.currentTimeMillis());
3968 final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
3970 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0
3971 && (channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
3972 && (r.getImportance() == IMPORTANCE_MIN || r.getImportance() == IMPORTANCE_NONE)) {
3973 // Increase the importance of foreground service notifications unless the user had an
3974 // opinion otherwise
3975 if (TextUtils.isEmpty(channelId)
3976 || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
3977 r.setImportance(IMPORTANCE_LOW, "Bumped for foreground service");
3979 channel.setImportance(IMPORTANCE_LOW);
3980 mRankingHelper.updateNotificationChannel(pkg, notificationUid, channel, false);
3981 r.updateNotificationChannel(channel);
3985 if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
3986 r.sbn.getOverrideGroupKey() != null)) {
3990 // Whitelist pending intents.
3991 if (notification.allPendingIntents != null) {
3992 final int intentCount = notification.allPendingIntents.size();
3993 if (intentCount > 0) {
3994 final ActivityManagerInternal am = LocalServices
3995 .getService(ActivityManagerInternal.class);
3996 final long duration = LocalServices.getService(
3997 DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
3998 for (int i = 0; i < intentCount; i++) {
3999 PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
4000 if (pendingIntent != null) {
4001 am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
4002 WHITELIST_TOKEN, duration);
4008 mHandler.post(new EnqueueNotificationRunnable(userId, r));
4011 private void doChannelWarningToast(CharSequence toastText) {
4012 final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
4013 final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
4014 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
4015 if (warningEnabled) {
4016 Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
4017 Toast.LENGTH_SHORT);
4022 private int resolveNotificationUid(String opPackageName, int callingUid, int userId) {
4023 // The system can post notifications on behalf of any package it wants
4024 if (isCallerSystemOrPhone() && opPackageName != null && !"android".equals(opPackageName)) {
4026 return getContext().getPackageManager()
4027 .getPackageUidAsUser(opPackageName, userId);
4028 } catch (NameNotFoundException e) {
4036 * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
4040 private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag,
4041 NotificationRecord r, boolean isAutogroup) {
4042 final String pkg = r.sbn.getPackageName();
4043 final boolean isSystemNotification =
4044 isUidSystemOrPhone(callingUid) || ("android".equals(pkg));
4045 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
4047 // Limit the number of notifications that any given package except the android
4048 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
4049 if (!isSystemNotification && !isNotificationFromListener) {
4050 synchronized (mNotificationLock) {
4051 if (mNotificationsByKey.get(r.sbn.getKey()) == null && isCallerInstantApp(pkg)) {
4052 // Ephemeral apps have some special constraints for notifications.
4053 // They are not allowed to create new notifications however they are allowed to
4054 // update notifications created by the system (e.g. a foreground service
4056 throw new SecurityException("Instant app " + pkg
4057 + " cannot create notifications");
4060 // rate limit updates that aren't completed progress notifications
4061 if (mNotificationsByKey.get(r.sbn.getKey()) != null
4062 && !r.getNotification().hasCompletedProgress()
4065 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
4066 if (appEnqueueRate > mMaxPackageEnqueueRate) {
4067 mUsageStats.registerOverRateQuota(pkg);
4068 final long now = SystemClock.elapsedRealtime();
4069 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
4070 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
4071 + ". Shedding " + r.sbn.getKey() + ". package=" + pkg);
4072 mLastOverRateLogTime = now;
4078 // limit the number of outstanding notificationrecords an app can have
4079 int count = getNotificationCountLocked(pkg, userId, id, tag);
4080 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
4081 mUsageStats.registerOverCountQuota(pkg);
4082 Slog.e(TAG, "Package has already posted or enqueued " + count
4083 + " notifications. Not showing more. package=" + pkg);
4090 if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
4091 MetricsLogger.action(r.getLogMaker()
4092 .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
4093 .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
4095 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
4097 mSnoozeHelper.update(userId, r);
4104 if (isBlocked(r, mUsageStats)) {
4111 @GuardedBy("mNotificationLock")
4112 protected int getNotificationCountLocked(String pkg, int userId, int excludedId,
4113 String excludedTag) {
4115 final int N = mNotificationList.size();
4116 for (int i = 0; i < N; i++) {
4117 final NotificationRecord existing = mNotificationList.get(i);
4118 if (existing.sbn.getPackageName().equals(pkg)
4119 && existing.sbn.getUserId() == userId) {
4120 if (existing.sbn.getId() == excludedId
4121 && TextUtils.equals(existing.sbn.getTag(), excludedTag)) {
4127 final int M = mEnqueuedNotifications.size();
4128 for (int i = 0; i < M; i++) {
4129 final NotificationRecord existing = mEnqueuedNotifications.get(i);
4130 if (existing.sbn.getPackageName().equals(pkg)
4131 && existing.sbn.getUserId() == userId) {
4138 protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
4139 final String pkg = r.sbn.getPackageName();
4140 final int callingUid = r.sbn.getUid();
4142 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
4143 if (isPackageSuspended) {
4144 Slog.e(TAG, "Suppressing notification from package due to package "
4145 + "suspended by administrator.");
4146 usageStats.registerSuspendedByAdmin(r);
4147 return isPackageSuspended;
4149 final boolean isBlocked =
4150 mRankingHelper.isGroupBlocked(pkg, callingUid, r.getChannel().getGroup())
4151 || mRankingHelper.getImportance(pkg, callingUid)
4152 == NotificationManager.IMPORTANCE_NONE
4153 || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE;
4155 Slog.e(TAG, "Suppressing notification from package by user request.");
4156 usageStats.registerBlocked(r);
4161 protected class SnoozeNotificationRunnable implements Runnable {
4162 private final String mKey;
4163 private final long mDuration;
4164 private final String mSnoozeCriterionId;
4166 SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) {
4168 mDuration = duration;
4169 mSnoozeCriterionId = snoozeCriterionId;
4174 synchronized (mNotificationLock) {
4175 final NotificationRecord r = findNotificationByKeyLocked(mKey);
4182 @GuardedBy("mNotificationLock")
4183 void snoozeLocked(NotificationRecord r) {
4184 if (r.sbn.isGroup()) {
4185 final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked(
4186 r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId());
4187 if (r.getNotification().isGroupSummary()) {
4188 // snooze summary and all children
4189 for (int i = 0; i < groupNotifications.size(); i++) {
4190 snoozeNotificationLocked(groupNotifications.get(i));
4193 // if there is a valid summary for this group, and we are snoozing the only
4194 // child, also snooze the summary
4195 if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) {
4196 if (groupNotifications.size() != 2) {
4197 snoozeNotificationLocked(r);
4199 // snooze summary and the one child
4200 for (int i = 0; i < groupNotifications.size(); i++) {
4201 snoozeNotificationLocked(groupNotifications.get(i));
4205 snoozeNotificationLocked(r);
4209 // just snooze the one notification
4210 snoozeNotificationLocked(r);
4214 @GuardedBy("mNotificationLock")
4215 void snoozeNotificationLocked(NotificationRecord r) {
4216 MetricsLogger.action(r.getLogMaker()
4217 .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
4218 .setType(MetricsEvent.TYPE_CLOSE)
4219 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS,
4221 .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
4222 mSnoozeCriterionId == null ? 0 : 1));
4223 boolean wasPosted = removeFromNotificationListsLocked(r);
4224 cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null);
4225 updateLightsLocked();
4226 if (mSnoozeCriterionId != null) {
4227 mAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
4228 mSnoozeHelper.snooze(r);
4230 mSnoozeHelper.snooze(r, mDuration);
4237 protected class EnqueueNotificationRunnable implements Runnable {
4238 private final NotificationRecord r;
4239 private final int userId;
4241 EnqueueNotificationRunnable(int userId, NotificationRecord r) {
4242 this.userId = userId;
4248 synchronized (mNotificationLock) {
4249 mEnqueuedNotifications.add(r);
4250 scheduleTimeoutLocked(r);
4252 final StatusBarNotification n = r.sbn;
4253 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
4254 NotificationRecord old = mNotificationsByKey.get(n.getKey());
4256 // Retain ranking information from previous record
4257 r.copyRankingInformation(old);
4260 final int callingUid = n.getUid();
4261 final int callingPid = n.getInitialPid();
4262 final Notification notification = n.getNotification();
4263 final String pkg = n.getPackageName();
4264 final int id = n.getId();
4265 final String tag = n.getTag();
4267 // Handle grouped notifications and bail out early if we
4268 // can to avoid extracting signals.
4269 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
4271 // if this is a group child, unsnooze parent summary
4272 if (n.isGroup() && notification.isGroupChild()) {
4273 mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
4276 // This conditional is a dirty hack to limit the logging done on
4277 // behalf of the download manager without affecting other apps.
4278 if (!pkg.equals("com.android.providers.downloads")
4279 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
4280 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
4282 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
4284 EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
4285 pkg, id, tag, userId, notification.toString(),
4289 mRankingHelper.extractSignals(r);
4291 // tell the assistant service about the notification
4292 if (mAssistants.isEnabled()) {
4293 mAssistants.onNotificationEnqueued(r);
4294 mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
4295 DELAY_FOR_ASSISTANT_TIME);
4297 mHandler.post(new PostNotificationRunnable(r.getKey()));
4303 @GuardedBy("mNotificationLock")
4304 private boolean isPackageSuspendedLocked(NotificationRecord r) {
4305 final String pkg = r.sbn.getPackageName();
4306 final int callingUid = r.sbn.getUid();
4308 return isPackageSuspendedForUser(pkg, callingUid);
4311 protected class PostNotificationRunnable implements Runnable {
4312 private final String key;
4314 PostNotificationRunnable(String key) {
4320 synchronized (mNotificationLock) {
4322 NotificationRecord r = null;
4323 int N = mEnqueuedNotifications.size();
4324 for (int i = 0; i < N; i++) {
4325 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
4326 if (Objects.equals(key, enqueued.getKey())) {
4332 Slog.i(TAG, "Cannot find enqueued record for key: " + key);
4336 r.setHidden(isPackageSuspendedLocked(r));
4337 NotificationRecord old = mNotificationsByKey.get(key);
4338 final StatusBarNotification n = r.sbn;
4339 final Notification notification = n.getNotification();
4340 int index = indexOfNotificationLocked(n.getKey());
4342 mNotificationList.add(r);
4343 mUsageStats.registerPostedByApp(r);
4344 r.setInterruptive(true);
4346 old = mNotificationList.get(index);
4347 mNotificationList.set(index, r);
4348 mUsageStats.registerUpdatedByApp(r, old);
4349 // Make sure we don't lose the foreground service state.
4350 notification.flags |=
4351 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
4352 // revoke uri permissions for changed uris
4353 revokeUriPermissions(r, old);
4355 r.setInterruptive(isVisuallyInterruptive(old, r));
4358 mNotificationsByKey.put(n.getKey(), r);
4360 // Ensure if this is a foreground service that the proper additional
4362 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
4363 notification.flags |= Notification.FLAG_ONGOING_EVENT
4364 | Notification.FLAG_NO_CLEAR;
4367 applyZenModeLocked(r);
4368 mRankingHelper.sort(mNotificationList);
4370 if (notification.getSmallIcon() != null) {
4371 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
4372 mListeners.notifyPostedLocked(r, oldSbn);
4373 if (oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())) {
4374 mHandler.post(new Runnable() {
4377 mGroupHelper.onNotificationPosted(
4378 n, hasAutoGroupSummaryLocked(n));
4383 Slog.e(TAG, "Not posting notification without small icon: " + notification);
4384 if (old != null && !old.isCanceled) {
4385 mListeners.notifyRemovedLocked(r,
4386 NotificationListenerService.REASON_ERROR, null);
4387 mHandler.post(new Runnable() {
4390 mGroupHelper.onNotificationRemoved(n);
4394 // ATTENTION: in a future release we will bail out here
4395 // so that we do not play sounds, show lights, etc. for invalid
4397 Slog.e(TAG, "WARNING: In a future release this will crash the app: "
4398 + n.getPackageName());
4401 if (!r.isHidden()) {
4402 buzzBeepBlinkLocked(r);
4404 maybeRecordInterruptionLocked(r);
4406 int N = mEnqueuedNotifications.size();
4407 for (int i = 0; i < N; i++) {
4408 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
4409 if (Objects.equals(key, enqueued.getKey())) {
4410 mEnqueuedNotifications.remove(i);
4420 * If the notification differs enough visually, consider it a new interruptive notification.
4422 @GuardedBy("mNotificationLock")
4424 protected boolean isVisuallyInterruptive(NotificationRecord old, NotificationRecord r) {
4425 Notification oldN = old.sbn.getNotification();
4426 Notification newN = r.sbn.getNotification();
4427 if (oldN.extras == null || newN.extras == null) {
4430 if (!Objects.equals(oldN.extras.get(Notification.EXTRA_TITLE),
4431 newN.extras.get(Notification.EXTRA_TITLE))) {
4434 if (!Objects.equals(oldN.extras.get(Notification.EXTRA_TEXT),
4435 newN.extras.get(Notification.EXTRA_TEXT))) {
4438 if (oldN.extras.containsKey(Notification.EXTRA_PROGRESS) && newN.hasCompletedProgress()) {
4442 if (Notification.areActionsVisiblyDifferent(oldN, newN)) {
4447 Notification.Builder oldB = Notification.Builder.recoverBuilder(getContext(), oldN);
4448 Notification.Builder newB = Notification.Builder.recoverBuilder(getContext(), newN);
4450 // Style based comparisons
4451 if (Notification.areStyledNotificationsVisiblyDifferent(oldB, newB)) {
4456 if (Notification.areRemoteViewsChanged(oldB, newB)) {
4459 } catch (Exception e) {
4460 Slog.w(TAG, "error recovering builder", e);
4466 * Keeps the last 5 packages that have notified, by user.
4468 @GuardedBy("mNotificationLock")
4470 protected void logRecentLocked(NotificationRecord r) {
4474 ArrayList<NotifyingApp> recentAppsForUser =
4475 mRecentApps.getOrDefault(r.getUser().getIdentifier(), new ArrayList<>(6));
4476 NotifyingApp na = new NotifyingApp()
4477 .setPackage(r.sbn.getPackageName())
4478 .setUid(r.sbn.getUid())
4479 .setLastNotified(r.sbn.getPostTime());
4480 // A new notification gets an app moved to the front of the list
4481 for (int i = recentAppsForUser.size() - 1; i >= 0; i--) {
4482 NotifyingApp naExisting = recentAppsForUser.get(i);
4483 if (na.getPackage().equals(naExisting.getPackage())
4484 && na.getUid() == naExisting.getUid()) {
4485 recentAppsForUser.remove(i);
4489 // time is always increasing, so always add to the front of the list
4490 recentAppsForUser.add(0, na);
4491 if (recentAppsForUser.size() > 5) {
4492 recentAppsForUser.remove(recentAppsForUser.size() -1);
4494 mRecentApps.put(r.getUser().getIdentifier(), recentAppsForUser);
4498 * Ensures that grouped notification receive their special treatment.
4500 * <p>Cancels group children if the new notification causes a group to lose
4503 * <p>Updates mSummaryByGroupKey.</p>
4505 @GuardedBy("mNotificationLock")
4506 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
4507 int callingUid, int callingPid) {
4508 StatusBarNotification sbn = r.sbn;
4509 Notification n = sbn.getNotification();
4510 if (n.isGroupSummary() && !sbn.isAppGroup()) {
4511 // notifications without a group shouldn't be a summary, otherwise autobundling can
4513 n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
4516 String group = sbn.getGroupKey();
4517 boolean isSummary = n.isGroupSummary();
4519 Notification oldN = old != null ? old.sbn.getNotification() : null;
4520 String oldGroup = old != null ? old.sbn.getGroupKey() : null;
4521 boolean oldIsSummary = old != null && oldN.isGroupSummary();
4524 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
4525 if (removedSummary != old) {
4527 removedSummary != null ? removedSummary.getKey() : "<null>";
4528 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
4529 ", removed=" + removedKey);
4533 mSummaryByGroupKey.put(group, r);
4536 // Clear out group children of the old notification if the update
4537 // causes the group summary to go away. This happens when the old
4538 // notification was a summary and the new one isn't, or when the old
4539 // notification was a summary and its group key changed.
4540 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
4541 cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */,
4547 @GuardedBy("mNotificationLock")
4548 void scheduleTimeoutLocked(NotificationRecord record) {
4549 if (record.getNotification().getTimeoutAfter() > 0) {
4550 final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
4551 REQUEST_CODE_TIMEOUT,
4552 new Intent(ACTION_NOTIFICATION_TIMEOUT)
4553 .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
4554 .appendPath(record.getKey()).build())
4555 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
4556 .putExtra(EXTRA_KEY, record.getKey()),
4557 PendingIntent.FLAG_UPDATE_CURRENT);
4558 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
4559 SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
4564 @GuardedBy("mNotificationLock")
4565 void buzzBeepBlinkLocked(NotificationRecord record) {
4566 boolean buzz = false;
4567 boolean beep = false;
4568 boolean blink = false;
4570 final Notification notification = record.sbn.getNotification();
4571 final String key = record.getKey();
4573 // Should this notification make noise, vibe, or use the LED?
4574 final boolean aboveThreshold =
4575 record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
4577 // Remember if this notification already owns the notification channels.
4578 boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
4579 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
4580 // These are set inside the conditional if the notification is allowed to make noise.
4581 boolean hasValidVibrate = false;
4582 boolean hasValidSound = false;
4583 boolean sentAccessibilityEvent = false;
4584 // If the notification will appear in the status bar, it should send an accessibility
4586 if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) {
4587 sendAccessibilityEvent(notification, record.sbn.getPackageName());
4588 sentAccessibilityEvent = true;
4591 if (aboveThreshold && isNotificationForCurrentUser(record)) {
4593 if (mSystemReady && mAudioManager != null) {
4594 Uri soundUri = record.getSound();
4595 hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
4596 long[] vibration = record.getVibration();
4597 // Demote sound to vibration if vibration missing & phone in vibration mode.
4598 if (vibration == null
4600 && (mAudioManager.getRingerModeInternal()
4601 == AudioManager.RINGER_MODE_VIBRATE)
4602 && mAudioManager.getStreamVolume(
4603 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) == 0) {
4604 vibration = mFallbackVibrationPattern;
4606 hasValidVibrate = vibration != null;
4608 boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
4609 if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
4610 if (!sentAccessibilityEvent) {
4611 sendAccessibilityEvent(notification, record.sbn.getPackageName());
4612 sentAccessibilityEvent = true;
4614 if (DBG) Slog.v(TAG, "Interrupting!");
4615 if (hasValidSound) {
4616 mSoundNotificationKey = key;
4618 playInCallNotification();
4621 beep = playSound(record, soundUri);
4625 final boolean ringerModeSilent =
4626 mAudioManager.getRingerModeInternal()
4627 == AudioManager.RINGER_MODE_SILENT;
4628 if (!mInCall && hasValidVibrate && !ringerModeSilent) {
4629 mVibrateNotificationKey = key;
4631 buzz = playVibration(record, vibration, hasValidSound);
4636 // If a notification is updated to remove the actively playing sound or vibrate,
4637 // cancel that feedback now
4638 if (wasBeep && !hasValidSound) {
4641 if (wasBuzz && !hasValidVibrate) {
4642 clearVibrateLocked();
4646 // release the light
4647 boolean wasShowLights = mLights.remove(key);
4648 if (record.getLight() != null && aboveThreshold
4649 && ((record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_LIGHTS) == 0)) {
4651 updateLightsLocked();
4652 if (mUseAttentionLight) {
4653 mAttentionLight.pulse();
4656 } else if (wasShowLights) {
4657 updateLightsLocked();
4659 if (buzz || beep || blink) {
4660 record.setInterruptive(true);
4661 MetricsLogger.action(record.getLogMaker()
4662 .setCategory(MetricsEvent.NOTIFICATION_ALERT)
4663 .setType(MetricsEvent.TYPE_OPEN)
4664 .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
4665 EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
4669 @GuardedBy("mNotificationLock")
4670 boolean shouldMuteNotificationLocked(final NotificationRecord record) {
4671 // Suppressed because it's a silent update
4672 final Notification notification = record.getNotification();
4674 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
4678 // muted by listener
4679 final String disableEffects = disableNotificationEffects(record);
4680 if (disableEffects != null) {
4681 ZenLog.traceDisableEffects(record, disableEffects);
4685 // suppressed due to DND
4686 if (record.isIntercepted()) {
4690 // Suppressed because another notification in its group handles alerting
4691 if (record.sbn.isGroup()) {
4692 return notification.suppressAlertingDueToGrouping();
4695 // Suppressed for being too recently noisy
4696 final String pkg = record.sbn.getPackageName();
4697 if (mUsageStats.isAlertRateLimited(pkg)) {
4698 Slog.e(TAG, "Muting recently noisy " + record.getKey());
4705 private boolean playSound(final NotificationRecord record, Uri soundUri) {
4706 boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
4707 // play notifications if there is no user of exclusive audio focus
4708 // and the stream volume is not 0 (non-zero volume implies not silenced by SILENT or
4709 // VIBRATE ringer mode)
4710 if (!mAudioManager.isAudioFocusExclusive()
4711 && (mAudioManager.getStreamVolume(
4712 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) {
4713 final long identity = Binder.clearCallingIdentity();
4715 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4716 if (player != null) {
4717 if (DBG) Slog.v(TAG, "Playing sound " + soundUri
4718 + " with attributes " + record.getAudioAttributes());
4719 player.playAsync(soundUri, record.sbn.getUser(), looping,
4720 record.getAudioAttributes());
4723 } catch (RemoteException e) {
4725 Binder.restoreCallingIdentity(identity);
4731 private boolean playVibration(final NotificationRecord record, long[] vibration,
4732 boolean delayVibForSound) {
4733 // Escalate privileges so we can use the vibrator even if the
4734 // notifying app does not have the VIBRATE permission.
4735 long identity = Binder.clearCallingIdentity();
4737 final VibrationEffect effect;
4739 final boolean insistent =
4740 (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
4741 effect = VibrationEffect.createWaveform(
4742 vibration, insistent ? 0 : -1 /*repeatIndex*/);
4743 } catch (IllegalArgumentException e) {
4744 Slog.e(TAG, "Error creating vibration waveform with pattern: " +
4745 Arrays.toString(vibration));
4748 if (delayVibForSound) {
4750 // delay the vibration by the same amount as the notification sound
4751 final int waitMs = mAudioManager.getFocusRampTimeMs(
4752 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
4753 record.getAudioAttributes());
4754 if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms");
4756 Thread.sleep(waitMs);
4757 } catch (InterruptedException e) { }
4758 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
4759 effect, record.getAudioAttributes());
4762 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
4763 effect, record.getAudioAttributes());
4767 Binder.restoreCallingIdentity(identity);
4771 private boolean isNotificationForCurrentUser(NotificationRecord record) {
4772 final int currentUser;
4773 final long token = Binder.clearCallingIdentity();
4775 currentUser = ActivityManager.getCurrentUser();
4777 Binder.restoreCallingIdentity(token);
4779 return (record.getUserId() == UserHandle.USER_ALL ||
4780 record.getUserId() == currentUser ||
4781 mUserProfiles.isCurrentProfile(record.getUserId()));
4784 protected void playInCallNotification() {
4788 final long identity = Binder.clearCallingIdentity();
4790 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4791 if (player != null) {
4792 player.play(new Binder(), mInCallNotificationUri,
4793 mInCallNotificationAudioAttributes,
4794 mInCallNotificationVolume, false);
4796 } catch (RemoteException e) {
4798 Binder.restoreCallingIdentity(identity);
4804 @GuardedBy("mToastQueue")
4805 void showNextToastLocked() {
4806 ToastRecord record = mToastQueue.get(0);
4807 while (record != null) {
4808 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
4810 record.callback.show(record.token);
4811 scheduleDurationReachedLocked(record);
4813 } catch (RemoteException e) {
4814 Slog.w(TAG, "Object died trying to show notification " + record.callback
4815 + " in package " + record.pkg);
4816 // remove it from the list and let the process die
4817 int index = mToastQueue.indexOf(record);
4819 mToastQueue.remove(index);
4821 keepProcessAliveIfNeededLocked(record.pid);
4822 if (mToastQueue.size() > 0) {
4823 record = mToastQueue.get(0);
4831 @GuardedBy("mToastQueue")
4832 void cancelToastLocked(int index) {
4833 ToastRecord record = mToastQueue.get(index);
4835 record.callback.hide();
4836 } catch (RemoteException e) {
4837 Slog.w(TAG, "Object died trying to hide notification " + record.callback
4838 + " in package " + record.pkg);
4839 // don't worry about this, we're about to remove it from
4843 ToastRecord lastToast = mToastQueue.remove(index);
4845 mWindowManagerInternal.removeWindowToken(lastToast.token, false /* removeWindows */,
4847 // We passed 'false' for 'removeWindows' so that the client has time to stop
4848 // rendering (as hide above is a one-way message), otherwise we could crash
4849 // a client which was actively using a surface made from the token. However
4850 // we need to schedule a timeout to make sure the token is eventually killed
4851 // one way or another.
4852 scheduleKillTokenTimeout(lastToast.token);
4854 keepProcessAliveIfNeededLocked(record.pid);
4855 if (mToastQueue.size() > 0) {
4856 // Show the next one. If the callback fails, this will remove
4857 // it from the list, so don't assume that the list hasn't changed
4858 // after this point.
4859 showNextToastLocked();
4863 void finishTokenLocked(IBinder t) {
4864 mHandler.removeCallbacksAndMessages(t);
4865 // We pass 'true' for 'removeWindows' to let the WindowManager destroy any
4866 // remaining surfaces as either the client has called finishToken indicating
4867 // it has successfully removed the views, or the client has timed out
4868 // at which point anything goes.
4869 mWindowManagerInternal.removeWindowToken(t, true /* removeWindows */,
4873 @GuardedBy("mToastQueue")
4874 private void scheduleDurationReachedLocked(ToastRecord r)
4876 mHandler.removeCallbacksAndMessages(r);
4877 Message m = Message.obtain(mHandler, MESSAGE_DURATION_REACHED, r);
4878 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
4879 mHandler.sendMessageDelayed(m, delay);
4882 private void handleDurationReached(ToastRecord record)
4884 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
4885 synchronized (mToastQueue) {
4886 int index = indexOfToastLocked(record.pkg, record.callback);
4888 cancelToastLocked(index);
4893 @GuardedBy("mToastQueue")
4894 private void scheduleKillTokenTimeout(IBinder token)
4896 mHandler.removeCallbacksAndMessages(token);
4897 Message m = Message.obtain(mHandler, MESSAGE_FINISH_TOKEN_TIMEOUT, token);
4898 mHandler.sendMessageDelayed(m, FINISH_TOKEN_TIMEOUT);
4901 private void handleKillTokenTimeout(IBinder token)
4903 if (DBG) Slog.d(TAG, "Kill Token Timeout token=" + token);
4904 synchronized (mToastQueue) {
4905 finishTokenLocked(token);
4909 @GuardedBy("mToastQueue")
4910 int indexOfToastLocked(String pkg, ITransientNotification callback)
4912 IBinder cbak = callback.asBinder();
4913 ArrayList<ToastRecord> list = mToastQueue;
4914 int len = list.size();
4915 for (int i=0; i<len; i++) {
4916 ToastRecord r = list.get(i);
4917 if (r.pkg.equals(pkg) && r.callback.asBinder().equals(cbak)) {
4924 @GuardedBy("mToastQueue")
4925 int indexOfToastPackageLocked(String pkg)
4927 ArrayList<ToastRecord> list = mToastQueue;
4928 int len = list.size();
4929 for (int i=0; i<len; i++) {
4930 ToastRecord r = list.get(i);
4931 if (r.pkg.equals(pkg)) {
4938 @GuardedBy("mToastQueue")
4939 void keepProcessAliveIfNeededLocked(int pid)
4941 int toastCount = 0; // toasts from this pid
4942 ArrayList<ToastRecord> list = mToastQueue;
4943 int N = list.size();
4944 for (int i=0; i<N; i++) {
4945 ToastRecord r = list.get(i);
4951 mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
4952 } catch (RemoteException e) {
4953 // Shouldn't happen.
4957 private void handleRankingReconsideration(Message message) {
4958 if (!(message.obj instanceof RankingReconsideration)) return;
4959 RankingReconsideration recon = (RankingReconsideration) message.obj;
4962 synchronized (mNotificationLock) {
4963 final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
4964 if (record == null) {
4967 int indexBefore = findNotificationRecordIndexLocked(record);
4968 boolean interceptBefore = record.isIntercepted();
4969 float contactAffinityBefore = record.getContactAffinity();
4970 int visibilityBefore = record.getPackageVisibilityOverride();
4971 recon.applyChangesLocked(record);
4972 applyZenModeLocked(record);
4973 mRankingHelper.sort(mNotificationList);
4974 int indexAfter = findNotificationRecordIndexLocked(record);
4975 boolean interceptAfter = record.isIntercepted();
4976 float contactAffinityAfter = record.getContactAffinity();
4977 int visibilityAfter = record.getPackageVisibilityOverride();
4978 changed = indexBefore != indexAfter || interceptBefore != interceptAfter
4979 || visibilityBefore != visibilityAfter;
4980 if (interceptBefore && !interceptAfter
4981 && Float.compare(contactAffinityBefore, contactAffinityAfter) != 0) {
4982 buzzBeepBlinkLocked(record);
4986 mHandler.scheduleSendRankingUpdate();
4990 void handleRankingSort() {
4991 if (mRankingHelper == null) return;
4992 synchronized (mNotificationLock) {
4993 final int N = mNotificationList.size();
4994 // Any field that can change via one of the extractors needs to be added here.
4995 ArrayList<String> orderBefore = new ArrayList<>(N);
4996 int[] visibilities = new int[N];
4997 boolean[] showBadges = new boolean[N];
4998 ArrayList<NotificationChannel> channelBefore = new ArrayList<>(N);
4999 ArrayList<String> groupKeyBefore = new ArrayList<>(N);
5000 ArrayList<ArrayList<String>> overridePeopleBefore = new ArrayList<>(N);
5001 ArrayList<ArrayList<SnoozeCriterion>> snoozeCriteriaBefore = new ArrayList<>(N);
5002 ArrayList<Integer> userSentimentBefore = new ArrayList<>(N);
5003 ArrayList<Integer> suppressVisuallyBefore = new ArrayList<>(N);
5004 for (int i = 0; i < N; i++) {
5005 final NotificationRecord r = mNotificationList.get(i);
5006 orderBefore.add(r.getKey());
5007 visibilities[i] = r.getPackageVisibilityOverride();
5008 showBadges[i] = r.canShowBadge();
5009 channelBefore.add(r.getChannel());
5010 groupKeyBefore.add(r.getGroupKey());
5011 overridePeopleBefore.add(r.getPeopleOverride());
5012 snoozeCriteriaBefore.add(r.getSnoozeCriteria());
5013 userSentimentBefore.add(r.getUserSentiment());
5014 suppressVisuallyBefore.add(r.getSuppressedVisualEffects());
5015 mRankingHelper.extractSignals(r);
5017 mRankingHelper.sort(mNotificationList);
5018 for (int i = 0; i < N; i++) {
5019 final NotificationRecord r = mNotificationList.get(i);
5020 if (!orderBefore.get(i).equals(r.getKey())
5021 || visibilities[i] != r.getPackageVisibilityOverride()
5022 || showBadges[i] != r.canShowBadge()
5023 || !Objects.equals(channelBefore.get(i), r.getChannel())
5024 || !Objects.equals(groupKeyBefore.get(i), r.getGroupKey())
5025 || !Objects.equals(overridePeopleBefore.get(i), r.getPeopleOverride())
5026 || !Objects.equals(snoozeCriteriaBefore.get(i), r.getSnoozeCriteria())
5027 || !Objects.equals(userSentimentBefore.get(i), r.getUserSentiment())
5028 || !Objects.equals(suppressVisuallyBefore.get(i),
5029 r.getSuppressedVisualEffects())) {
5030 mHandler.scheduleSendRankingUpdate();
5037 @GuardedBy("mNotificationLock")
5038 private void recordCallerLocked(NotificationRecord record) {
5039 if (mZenModeHelper.isCall(record)) {
5040 mZenModeHelper.recordCaller(record);
5044 // let zen mode evaluate this record
5045 @GuardedBy("mNotificationLock")
5046 private void applyZenModeLocked(NotificationRecord record) {
5047 record.setIntercepted(mZenModeHelper.shouldIntercept(record));
5048 if (record.isIntercepted()) {
5049 record.setSuppressedVisualEffects(
5050 mZenModeHelper.getNotificationPolicy().suppressedVisualEffects);
5052 record.setSuppressedVisualEffects(0);
5056 @GuardedBy("mNotificationLock")
5057 private int findNotificationRecordIndexLocked(NotificationRecord target) {
5058 return mRankingHelper.indexOf(mNotificationList, target);
5061 private void handleSendRankingUpdate() {
5062 synchronized (mNotificationLock) {
5063 mListeners.notifyRankingUpdateLocked(null);
5067 private void scheduleListenerHintsChanged(int state) {
5068 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
5069 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
5072 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
5073 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
5074 mHandler.obtainMessage(
5075 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
5076 listenerInterruptionFilter,
5080 private void handleListenerHintsChanged(int hints) {
5081 synchronized (mNotificationLock) {
5082 mListeners.notifyListenerHintsChangedLocked(hints);
5086 private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
5087 synchronized (mNotificationLock) {
5088 mListeners.notifyInterruptionFilterChanged(interruptionFilter);
5092 protected class WorkerHandler extends Handler
5094 public WorkerHandler(Looper looper) {
5099 public void handleMessage(Message msg)
5103 case MESSAGE_DURATION_REACHED:
5104 handleDurationReached((ToastRecord)msg.obj);
5106 case MESSAGE_FINISH_TOKEN_TIMEOUT:
5107 handleKillTokenTimeout((IBinder)msg.obj);
5109 case MESSAGE_SAVE_POLICY_FILE:
5110 handleSavePolicyFile();
5112 case MESSAGE_SEND_RANKING_UPDATE:
5113 handleSendRankingUpdate();
5115 case MESSAGE_LISTENER_HINTS_CHANGED:
5116 handleListenerHintsChanged(msg.arg1);
5118 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
5119 handleListenerInterruptionFilterChanged(msg.arg1);
5124 protected void scheduleSendRankingUpdate() {
5125 if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
5126 Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE);
5133 private final class RankingHandlerWorker extends Handler implements RankingHandler
5135 public RankingHandlerWorker(Looper looper) {
5140 public void handleMessage(Message msg) {
5142 case MESSAGE_RECONSIDER_RANKING:
5143 handleRankingReconsideration(msg);
5145 case MESSAGE_RANKING_SORT:
5146 handleRankingSort();
5151 public void requestSort() {
5152 removeMessages(MESSAGE_RANKING_SORT);
5153 Message msg = Message.obtain();
5154 msg.what = MESSAGE_RANKING_SORT;
5158 public void requestReconsideration(RankingReconsideration recon) {
5159 Message m = Message.obtain(this,
5160 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
5161 long delay = recon.getDelay(TimeUnit.MILLISECONDS);
5162 sendMessageDelayed(m, delay);
5167 // ============================================================================
5168 static int clamp(int x, int low, int high) {
5169 return (x < low) ? low : ((x > high) ? high : x);
5172 void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
5173 if (!mAccessibilityManager.isEnabled()) {
5177 AccessibilityEvent event =
5178 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
5179 event.setPackageName(packageName);
5180 event.setClassName(Notification.class.getName());
5181 event.setParcelableData(notification);
5182 CharSequence tickerText = notification.tickerText;
5183 if (!TextUtils.isEmpty(tickerText)) {
5184 event.getText().add(tickerText);
5187 mAccessibilityManager.sendAccessibilityEvent(event);
5191 * Removes all NotificationsRecords with the same key as the given notification record
5192 * from both lists. Do not call this method while iterating over either list.
5194 @GuardedBy("mNotificationLock")
5195 private boolean removeFromNotificationListsLocked(NotificationRecord r) {
5196 // Remove from both lists, either list could have a separate Record for what is
5197 // effectively the same notification.
5198 boolean wasPosted = false;
5199 NotificationRecord recordInList = null;
5200 if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))
5202 mNotificationList.remove(recordInList);
5203 mNotificationsByKey.remove(recordInList.sbn.getKey());
5206 while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
5208 mEnqueuedNotifications.remove(recordInList);
5213 @GuardedBy("mNotificationLock")
5214 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
5215 boolean wasPosted, String listenerName) {
5216 final String canceledKey = r.getKey();
5219 recordCallerLocked(r);
5221 if (r.getStats().getDismissalSurface() == NotificationStats.DISMISSAL_NOT_DISMISSED) {
5222 r.recordDismissalSurface(NotificationStats.DISMISSAL_OTHER);
5225 // Revoke permissions
5226 revokeUriPermissions(null, r);
5230 if (r.getNotification().deleteIntent != null) {
5232 r.getNotification().deleteIntent.send();
5233 } catch (PendingIntent.CanceledException ex) {
5234 // do nothing - there's no relevant way to recover, and
5235 // no reason to let this propagate
5236 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
5241 // Only cancel these if this notification actually got to be posted.
5244 if (r.getNotification().getSmallIcon() != null) {
5245 if (reason != REASON_SNOOZED) {
5246 r.isCanceled = true;
5248 mListeners.notifyRemovedLocked(r, reason, r.getStats());
5249 mHandler.post(new Runnable() {
5252 mGroupHelper.onNotificationRemoved(r.sbn);
5258 if (canceledKey.equals(mSoundNotificationKey)) {
5259 mSoundNotificationKey = null;
5260 final long identity = Binder.clearCallingIdentity();
5262 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
5263 if (player != null) {
5266 } catch (RemoteException e) {
5268 Binder.restoreCallingIdentity(identity);
5273 if (canceledKey.equals(mVibrateNotificationKey)) {
5274 mVibrateNotificationKey = null;
5275 long identity = Binder.clearCallingIdentity();
5280 Binder.restoreCallingIdentity(identity);
5285 mLights.remove(canceledKey);
5288 // Record usage stats
5289 // TODO: add unbundling stats?
5292 case REASON_CANCEL_ALL:
5293 case REASON_LISTENER_CANCEL:
5294 case REASON_LISTENER_CANCEL_ALL:
5295 mUsageStats.registerDismissedByUser(r);
5297 case REASON_APP_CANCEL:
5298 case REASON_APP_CANCEL_ALL:
5299 mUsageStats.registerRemovedByApp(r);
5303 String groupKey = r.getGroupKey();
5304 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
5305 if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
5306 mSummaryByGroupKey.remove(groupKey);
5308 final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
5309 if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
5310 summaries.remove(r.sbn.getPackageName());
5313 // Save it for users of getHistoricalNotifications()
5314 mArchive.record(r.sbn);
5316 final long now = System.currentTimeMillis();
5317 MetricsLogger.action(r.getLogMaker(now)
5318 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
5319 .setType(MetricsEvent.TYPE_DISMISS)
5320 .setSubtype(reason));
5321 EventLogTags.writeNotificationCanceled(canceledKey, reason,
5322 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), listenerName);
5325 void revokeUriPermissions(NotificationRecord newRecord, NotificationRecord oldRecord) {
5326 Set<Uri> oldUris = oldRecord.getNotificationUris();
5327 Set<Uri> newUris = newRecord == null ? new HashSet<>() : newRecord.getNotificationUris();
5328 oldUris.removeAll(newUris);
5330 long ident = Binder.clearCallingIdentity();
5332 for (Uri uri : oldUris) {
5334 int notiUserId = oldRecord.getUserId();
5335 int sourceUserId = notiUserId == USER_ALL ? USER_SYSTEM
5336 : ContentProvider.getUserIdFromUri(uri, notiUserId);
5337 uri = ContentProvider.getUriWithoutUserId(uri);
5338 mAm.revokeUriPermissionFromOwner(mPermissionOwner,
5339 uri, Intent.FLAG_GRANT_READ_URI_PERMISSION, sourceUserId);
5342 } catch (RemoteException e) {
5343 Log.e(TAG, "Count not revoke uri permissions", e);
5345 Binder.restoreCallingIdentity(ident);
5350 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
5351 * and none of the {@code mustNotHaveFlags}.
5353 void cancelNotification(final int callingUid, final int callingPid,
5354 final String pkg, final String tag, final int id,
5355 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
5356 final int userId, final int reason, final ManagedServiceInfo listener) {
5358 // In enqueueNotificationInternal notifications are added by scheduling the
5359 // work on the worker handler. Hence, we also schedule the cancel on this
5360 // handler to avoid a scenario where an add notification call followed by a
5361 // remove notification call ends up in not removing the notification.
5362 mHandler.post(new Runnable() {
5365 String listenerName = listener == null ? null : listener.component.toShortString();
5366 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
5367 userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
5369 synchronized (mNotificationLock) {
5370 // Look for the notification, searching both the posted and enqueued lists.
5371 NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
5373 // The notification was found, check if it should be removed.
5375 // Ideally we'd do this in the caller of this method. However, that would
5376 // require the caller to also find the notification.
5377 if (reason == REASON_CLICK) {
5378 mUsageStats.registerClickedByUser(r);
5381 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
5384 if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
5388 // Cancel the notification.
5389 boolean wasPosted = removeFromNotificationListsLocked(r);
5390 cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
5391 cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
5393 updateLightsLocked();
5395 // No notification was found, assume that it is snoozed and cancel it.
5396 if (reason != REASON_SNOOZED) {
5397 final boolean wasSnoozed = mSnoozeHelper.cancel(userId, pkg, tag, id);
5409 * Determine whether the userId applies to the notification in question, either because
5410 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
5412 private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
5414 // looking for USER_ALL notifications? match everything
5415 userId == UserHandle.USER_ALL
5416 // a notification sent to USER_ALL matches any query
5417 || r.getUserId() == UserHandle.USER_ALL
5418 // an exact user match
5419 || r.getUserId() == userId;
5423 * Determine whether the userId applies to the notification in question, either because
5424 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
5425 * because it matches one of the users profiles.
5427 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
5428 return notificationMatchesUserId(r, userId)
5429 || mUserProfiles.isCurrentProfile(r.getUserId());
5433 * Cancels all notifications from a given package that have all of the
5434 * {@code mustHaveFlags}.
5436 void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
5437 int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
5438 ManagedServiceInfo listener) {
5439 mHandler.post(new Runnable() {
5442 String listenerName = listener == null ? null : listener.component.toShortString();
5443 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
5444 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
5447 // Why does this parameter exist? Do we actually want to execute the above if doit
5453 synchronized (mNotificationLock) {
5454 FlagChecker flagChecker = (int flags) -> {
5455 if ((flags & mustHaveFlags) != mustHaveFlags) {
5458 if ((flags & mustNotHaveFlags) != 0) {
5463 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
5464 pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
5465 false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
5466 listenerName, true /* wasPosted */);
5467 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
5468 callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
5469 flagChecker, false /*includeCurrentProfiles*/, userId,
5470 false /*sendDelete*/, reason, listenerName, false /* wasPosted */);
5471 mSnoozeHelper.cancel(userId, pkg);
5477 private interface FlagChecker {
5478 // Returns false if these flags do not pass the defined flag test.
5479 public boolean apply(int flags);
5482 @GuardedBy("mNotificationLock")
5483 private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
5484 int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
5485 String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
5486 boolean sendDelete, int reason, String listenerName, boolean wasPosted) {
5487 ArrayList<NotificationRecord> canceledNotifications = null;
5488 for (int i = notificationList.size() - 1; i >= 0; --i) {
5489 NotificationRecord r = notificationList.get(i);
5490 if (includeCurrentProfiles) {
5491 if (!notificationMatchesCurrentProfiles(r, userId)) {
5494 } else if (!notificationMatchesUserId(r, userId)) {
5497 // Don't remove notifications to all, if there's no package name specified
5498 if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
5501 if (!flagChecker.apply(r.getFlags())) {
5504 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
5507 if (channelId != null && !channelId.equals(r.getChannel().getId())) {
5510 if (canceledNotifications == null) {
5511 canceledNotifications = new ArrayList<>();
5513 notificationList.remove(i);
5514 mNotificationsByKey.remove(r.getKey());
5515 canceledNotifications.add(r);
5516 cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
5518 if (canceledNotifications != null) {
5519 final int M = canceledNotifications.size();
5520 for (int i = 0; i < M; i++) {
5521 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
5522 listenerName, false /* sendDelete */, flagChecker);
5524 updateLightsLocked();
5528 void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
5529 ManagedServiceInfo listener) {
5530 String listenerName = listener == null ? null : listener.component.toShortString();
5531 if (duration <= 0 && snoozeCriterionId == null || key == null) {
5536 Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
5537 snoozeCriterionId, listenerName));
5539 // Needs to post so that it can cancel notifications not yet enqueued.
5540 mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
5543 void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
5544 String listenerName = listener == null ? null : listener.component.toShortString();
5546 Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
5548 mSnoozeHelper.repost(key);
5552 @GuardedBy("mNotificationLock")
5553 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
5554 ManagedServiceInfo listener, boolean includeCurrentProfiles) {
5555 mHandler.post(new Runnable() {
5558 synchronized (mNotificationLock) {
5559 String listenerName =
5560 listener == null ? null : listener.component.toShortString();
5561 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
5562 null, userId, 0, 0, reason, listenerName);
5564 FlagChecker flagChecker = (int flags) -> {
5565 if ((flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR))
5572 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
5573 null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
5574 includeCurrentProfiles, userId, true /*sendDelete*/, reason,
5575 listenerName, true);
5576 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
5577 callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
5578 flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
5579 reason, listenerName, false);
5580 mSnoozeHelper.cancel(userId, includeCurrentProfiles);
5586 // Warning: The caller is responsible for invoking updateLightsLocked().
5587 @GuardedBy("mNotificationLock")
5588 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
5589 String listenerName, boolean sendDelete, FlagChecker flagChecker) {
5590 Notification n = r.getNotification();
5591 if (!n.isGroupSummary()) {
5595 String pkg = r.sbn.getPackageName();
5598 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
5602 cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
5603 sendDelete, true, flagChecker);
5604 cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
5605 listenerName, sendDelete, false, flagChecker);
5608 @GuardedBy("mNotificationLock")
5609 private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
5610 NotificationRecord parentNotification, int callingUid, int callingPid,
5611 String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker) {
5612 final String pkg = parentNotification.sbn.getPackageName();
5613 final int userId = parentNotification.getUserId();
5614 final int reason = REASON_GROUP_SUMMARY_CANCELED;
5615 for (int i = notificationList.size() - 1; i >= 0; i--) {
5616 final NotificationRecord childR = notificationList.get(i);
5617 final StatusBarNotification childSbn = childR.sbn;
5618 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
5619 childR.getGroupKey().equals(parentNotification.getGroupKey())
5620 && (childR.getFlags() & Notification.FLAG_FOREGROUND_SERVICE) == 0
5621 && (flagChecker == null || flagChecker.apply(childR.getFlags()))) {
5622 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
5623 childSbn.getTag(), userId, 0, 0, reason, listenerName);
5624 notificationList.remove(i);
5625 mNotificationsByKey.remove(childR.getKey());
5626 cancelNotificationLocked(childR, sendDelete, reason, wasPosted, listenerName);
5631 @GuardedBy("mNotificationLock")
5632 void updateLightsLocked()
5634 // handle notification lights
5635 NotificationRecord ledNotification = null;
5636 while (ledNotification == null && !mLights.isEmpty()) {
5637 final String owner = mLights.get(mLights.size() - 1);
5638 ledNotification = mNotificationsByKey.get(owner);
5639 if (ledNotification == null) {
5640 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
5641 mLights.remove(owner);
5645 // Don't flash while we are in a call or screen is on
5646 if (ledNotification == null || mInCall || mScreenOn) {
5647 mNotificationLight.turnOff();
5649 NotificationRecord.Light light = ledNotification.getLight();
5650 if (light != null && mNotificationPulseEnabled) {
5652 mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
5653 light.onMs, light.offMs);
5658 @GuardedBy("mNotificationLock")
5659 @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
5660 String groupKey, int userId) {
5661 List<NotificationRecord> records = new ArrayList<>();
5662 records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
5664 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
5669 @GuardedBy("mNotificationLock")
5670 private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
5671 ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
5672 List<NotificationRecord> records = new ArrayList<>();
5673 final int len = list.size();
5674 for (int i = 0; i < len; i++) {
5675 NotificationRecord r = list.get(i);
5676 if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey)
5677 && r.sbn.getPackageName().equals(pkg)) {
5684 // Searches both enqueued and posted notifications by key.
5685 // TODO: need to combine a bunch of these getters with slightly different behavior.
5686 // TODO: Should enqueuing just add to mNotificationsByKey instead?
5687 @GuardedBy("mNotificationLock")
5688 private NotificationRecord findNotificationByKeyLocked(String key) {
5689 NotificationRecord r;
5690 if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
5693 if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
5699 @GuardedBy("mNotificationLock")
5700 NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
5701 NotificationRecord r;
5702 if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
5705 if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
5712 @GuardedBy("mNotificationLock")
5713 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
5714 String pkg, String tag, int id, int userId) {
5715 final int len = list.size();
5716 for (int i = 0; i < len; i++) {
5717 NotificationRecord r = list.get(i);
5718 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
5719 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
5726 @GuardedBy("mNotificationLock")
5727 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
5729 final int N = list.size();
5730 for (int i = 0; i < N; i++) {
5731 if (key.equals(list.get(i).getKey())) {
5738 @GuardedBy("mNotificationLock")
5739 int indexOfNotificationLocked(String key) {
5740 final int N = mNotificationList.size();
5741 for (int i = 0; i < N; i++) {
5742 if (key.equals(mNotificationList.get(i).getKey())) {
5750 protected void hideNotificationsForPackages(String[] pkgs) {
5751 synchronized (mNotificationLock) {
5752 List<String> pkgList = Arrays.asList(pkgs);
5753 List<NotificationRecord> changedNotifications = new ArrayList<>();
5754 int numNotifications = mNotificationList.size();
5755 for (int i = 0; i < numNotifications; i++) {
5756 NotificationRecord rec = mNotificationList.get(i);
5757 if (pkgList.contains(rec.sbn.getPackageName())) {
5758 rec.setHidden(true);
5759 changedNotifications.add(rec);
5763 mListeners.notifyHiddenLocked(changedNotifications);
5768 protected void unhideNotificationsForPackages(String[] pkgs) {
5769 synchronized (mNotificationLock) {
5770 List<String> pkgList = Arrays.asList(pkgs);
5771 List<NotificationRecord> changedNotifications = new ArrayList<>();
5772 int numNotifications = mNotificationList.size();
5773 for (int i = 0; i < numNotifications; i++) {
5774 NotificationRecord rec = mNotificationList.get(i);
5775 if (pkgList.contains(rec.sbn.getPackageName())) {
5776 rec.setHidden(false);
5777 changedNotifications.add(rec);
5781 mListeners.notifyUnhiddenLocked(changedNotifications);
5785 private void updateNotificationPulse() {
5786 synchronized (mNotificationLock) {
5787 updateLightsLocked();
5791 protected boolean isCallingUidSystem() {
5792 final int uid = Binder.getCallingUid();
5793 return uid == Process.SYSTEM_UID;
5796 protected boolean isUidSystemOrPhone(int uid) {
5797 final int appid = UserHandle.getAppId(uid);
5798 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
5801 // TODO: Most calls should probably move to isCallerSystem.
5802 protected boolean isCallerSystemOrPhone() {
5803 return isUidSystemOrPhone(Binder.getCallingUid());
5806 private void checkCallerIsSystemOrShell() {
5807 if (Binder.getCallingUid() == Process.SHELL_UID) {
5810 checkCallerIsSystem();
5813 private void checkCallerIsSystem() {
5814 if (isCallerSystemOrPhone()) {
5817 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
5820 private void checkCallerIsSystemOrSameApp(String pkg) {
5821 if (isCallerSystemOrPhone()) {
5824 checkCallerIsSameApp(pkg);
5827 private boolean isCallerInstantApp(String pkg) {
5828 // System is always allowed to act for ephemeral apps.
5829 if (isCallerSystemOrPhone()) {
5833 mAppOps.checkPackage(Binder.getCallingUid(), pkg);
5836 ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0,
5837 UserHandle.getCallingUserId());
5839 throw new SecurityException("Unknown package " + pkg);
5841 return ai.isInstantApp();
5842 } catch (RemoteException re) {
5843 throw new SecurityException("Unknown package " + pkg, re);
5848 private void checkCallerIsSameApp(String pkg) {
5849 final int uid = Binder.getCallingUid();
5851 ApplicationInfo ai = mPackageManager.getApplicationInfo(
5852 pkg, 0, UserHandle.getCallingUserId());
5854 throw new SecurityException("Unknown package " + pkg);
5856 if (!UserHandle.isSameApp(ai.uid, uid)) {
5857 throw new SecurityException("Calling uid " + uid + " gave package "
5858 + pkg + " which is owned by uid " + ai.uid);
5860 } catch (RemoteException re) {
5861 throw new SecurityException("Unknown package " + pkg + "\n" + re);
5865 private static String callStateToString(int state) {
5867 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
5868 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
5869 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
5870 default: return "CALL_STATE_UNKNOWN_" + state;
5874 private void listenForCallState() {
5875 TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
5877 public void onCallStateChanged(int state, String incomingNumber) {
5878 if (mCallState == state) return;
5879 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
5882 }, PhoneStateListener.LISTEN_CALL_STATE);
5886 * Generates a NotificationRankingUpdate from 'sbns', considering only
5887 * notifications visible to the given listener.
5889 @GuardedBy("mNotificationLock")
5890 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
5891 final int N = mNotificationList.size();
5892 ArrayList<String> keys = new ArrayList<String>(N);
5893 ArrayList<String> interceptedKeys = new ArrayList<String>(N);
5894 ArrayList<Integer> importance = new ArrayList<>(N);
5895 Bundle overrideGroupKeys = new Bundle();
5896 Bundle visibilityOverrides = new Bundle();
5897 Bundle suppressedVisualEffects = new Bundle();
5898 Bundle explanation = new Bundle();
5899 Bundle channels = new Bundle();
5900 Bundle overridePeople = new Bundle();
5901 Bundle snoozeCriteria = new Bundle();
5902 Bundle showBadge = new Bundle();
5903 Bundle userSentiment = new Bundle();
5904 Bundle hidden = new Bundle();
5905 for (int i = 0; i < N; i++) {
5906 NotificationRecord record = mNotificationList.get(i);
5907 if (!isVisibleToListener(record.sbn, info)) {
5910 final String key = record.sbn.getKey();
5912 importance.add(record.getImportance());
5913 if (record.getImportanceExplanation() != null) {
5914 explanation.putCharSequence(key, record.getImportanceExplanation());
5916 if (record.isIntercepted()) {
5917 interceptedKeys.add(key);
5920 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
5921 if (record.getPackageVisibilityOverride()
5922 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
5923 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
5925 overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
5926 channels.putParcelable(key, record.getChannel());
5927 overridePeople.putStringArrayList(key, record.getPeopleOverride());
5928 snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria());
5929 showBadge.putBoolean(key, record.canShowBadge());
5930 userSentiment.putInt(key, record.getUserSentiment());
5931 hidden.putBoolean(key, record.isHidden());
5933 final int M = keys.size();
5934 String[] keysAr = keys.toArray(new String[M]);
5935 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
5936 int[] importanceAr = new int[M];
5937 for (int i = 0; i < M; i++) {
5938 importanceAr[i] = importance.get(i);
5940 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
5941 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
5942 channels, overridePeople, snoozeCriteria, showBadge, userSentiment, hidden);
5945 boolean hasCompanionDevice(ManagedServiceInfo info) {
5946 if (mCompanionManager == null) {
5947 mCompanionManager = getCompanionManager();
5949 // Companion mgr doesn't exist on all device types
5950 if (mCompanionManager == null) {
5953 long identity = Binder.clearCallingIdentity();
5955 List<String> associations = mCompanionManager.getAssociations(
5956 info.component.getPackageName(), info.userid);
5957 if (!ArrayUtils.isEmpty(associations)) {
5960 } catch (SecurityException se) {
5961 // Not a privileged listener
5962 } catch (RemoteException re) {
5963 Slog.e(TAG, "Cannot reach companion device service", re);
5964 } catch (Exception e) {
5965 Slog.e(TAG, "Cannot verify listener " + info, e);
5967 Binder.restoreCallingIdentity(identity);
5972 protected ICompanionDeviceManager getCompanionManager() {
5973 return ICompanionDeviceManager.Stub.asInterface(
5974 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
5977 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
5978 if (!listener.enabledAndUserMatches(sbn.getUserId())) {
5981 // TODO: remove this for older listeners.
5985 private boolean isPackageSuspendedForUser(String pkg, int uid) {
5986 final long identity = Binder.clearCallingIdentity();
5987 int userId = UserHandle.getUserId(uid);
5989 return mPackageManager.isPackageSuspendedForUser(pkg, userId);
5990 } catch (RemoteException re) {
5991 throw new SecurityException("Could not talk to package manager service");
5992 } catch (IllegalArgumentException ex) {
5993 // Package not found.
5996 Binder.restoreCallingIdentity(identity);
6000 private boolean canUseManagedServices() {
6001 return !mActivityManager.isLowRamDevice()
6002 || mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_WATCH);
6005 private class TrimCache {
6006 StatusBarNotification heavy;
6007 StatusBarNotification sbnClone;
6008 StatusBarNotification sbnCloneLight;
6010 TrimCache(StatusBarNotification sbn) {
6014 StatusBarNotification ForListener(ManagedServiceInfo info) {
6015 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
6016 if (sbnCloneLight == null) {
6017 sbnCloneLight = heavy.cloneLight();
6019 return sbnCloneLight;
6021 if (sbnClone == null) {
6022 sbnClone = heavy.clone();
6029 public class NotificationAssistants extends ManagedServices {
6030 static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
6032 public NotificationAssistants(Context context, Object lock, UserProfiles up,
6033 IPackageManager pm) {
6034 super(context, lock, up, pm);
6038 protected Config getConfig() {
6039 Config c = new Config();
6040 c.caption = "notification assistant";
6041 c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
6042 c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS;
6043 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
6044 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
6045 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
6046 c.clientLabel = R.string.notification_ranker_binding_label;
6051 protected IInterface asInterface(IBinder binder) {
6052 return INotificationListener.Stub.asInterface(binder);
6056 protected boolean checkType(IInterface service) {
6057 return service instanceof INotificationListener;
6061 protected void onServiceAdded(ManagedServiceInfo info) {
6062 mListeners.registerGuestService(info);
6066 @GuardedBy("mNotificationLock")
6067 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
6068 mListeners.unregisterService(removed.service, removed.userid);
6072 public void onUserUnlocked(int user) {
6073 if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
6074 rebindServices(true);
6077 public void onNotificationEnqueued(final NotificationRecord r) {
6078 final StatusBarNotification sbn = r.sbn;
6079 TrimCache trimCache = new TrimCache(sbn);
6081 // There should be only one, but it's a list, so while we enforce
6082 // singularity elsewhere, we keep it general here, to avoid surprises.
6083 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
6084 boolean sbnVisible = isVisibleToListener(sbn, info);
6089 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
6090 mHandler.post(new Runnable() {
6093 notifyEnqueued(info, sbnToPost);
6099 private void notifyEnqueued(final ManagedServiceInfo info,
6100 final StatusBarNotification sbn) {
6101 final INotificationListener assistant = (INotificationListener) info.service;
6102 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
6104 assistant.onNotificationEnqueued(sbnHolder);
6105 } catch (RemoteException ex) {
6106 Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
6111 * asynchronously notify the assistant that a notification has been snoozed until a
6114 @GuardedBy("mNotificationLock")
6115 public void notifyAssistantSnoozedLocked(final StatusBarNotification sbn,
6116 final String snoozeCriterionId) {
6117 TrimCache trimCache = new TrimCache(sbn);
6118 for (final ManagedServiceInfo info : getServices()) {
6119 boolean sbnVisible = isVisibleToListener(sbn, info);
6123 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
6124 mHandler.post(new Runnable() {
6127 final INotificationListener assistant =
6128 (INotificationListener) info.service;
6129 StatusBarNotificationHolder sbnHolder
6130 = new StatusBarNotificationHolder(sbnToPost);
6132 assistant.onNotificationSnoozedUntilContext(
6133 sbnHolder, snoozeCriterionId);
6134 } catch (RemoteException ex) {
6135 Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
6142 public boolean isEnabled() {
6143 return !getServices().isEmpty();
6146 protected void ensureAssistant() {
6147 final List<UserInfo> activeUsers = mUm.getUsers(true);
6148 for (UserInfo userInfo : activeUsers) {
6149 int userId = userInfo.getUserHandle().getIdentifier();
6150 if (getAllowedPackages(userId).isEmpty()) {
6151 Slog.d(TAG, "Approving default notification assistant for user " + userId);
6152 readDefaultAssistant(userId);
6158 public class NotificationListeners extends ManagedServices {
6159 static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners";
6161 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
6163 public NotificationListeners(IPackageManager pm) {
6164 super(getContext(), mNotificationLock, mUserProfiles, pm);
6169 protected Config getConfig() {
6170 Config c = new Config();
6171 c.caption = "notification listener";
6172 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
6173 c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS;
6174 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
6175 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
6176 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
6177 c.clientLabel = R.string.notification_listener_binding_label;
6182 protected IInterface asInterface(IBinder binder) {
6183 return INotificationListener.Stub.asInterface(binder);
6187 protected boolean checkType(IInterface service) {
6188 return service instanceof INotificationListener;
6192 public void onServiceAdded(ManagedServiceInfo info) {
6193 final INotificationListener listener = (INotificationListener) info.service;
6194 final NotificationRankingUpdate update;
6195 synchronized (mNotificationLock) {
6196 update = makeRankingUpdateLocked(info);
6199 listener.onListenerConnected(update);
6200 } catch (RemoteException e) {
6206 @GuardedBy("mNotificationLock")
6207 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
6208 if (removeDisabledHints(removed)) {
6209 updateListenerHintsLocked();
6210 updateEffectsSuppressorLocked();
6212 mLightTrimListeners.remove(removed);
6215 @GuardedBy("mNotificationLock")
6216 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
6217 if (trim == TRIM_LIGHT) {
6218 mLightTrimListeners.add(info);
6220 mLightTrimListeners.remove(info);
6224 public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
6225 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
6229 * asynchronously notify all listeners about a new notification
6232 * Also takes care of removing a notification that has been visible to a listener before,
6233 * but isn't anymore.
6235 @GuardedBy("mNotificationLock")
6236 public void notifyPostedLocked(NotificationRecord r, StatusBarNotification oldSbn) {
6237 notifyPostedLocked(r, oldSbn, true);
6241 * @param notifyAllListeners notifies all listeners if true, else only notifies listeners
6242 * targetting <= O_MR1
6244 @GuardedBy("mNotificationLock")
6245 private void notifyPostedLocked(NotificationRecord r, StatusBarNotification oldSbn,
6246 boolean notifyAllListeners) {
6247 // Lazily initialized snapshots of the notification.
6248 StatusBarNotification sbn = r.sbn;
6249 TrimCache trimCache = new TrimCache(sbn);
6251 Set<Uri> uris = r.getNotificationUris();
6253 for (final ManagedServiceInfo info : getServices()) {
6254 boolean sbnVisible = isVisibleToListener(sbn, info);
6255 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
6256 // This notification hasn't been and still isn't visible -> ignore.
6257 if (!oldSbnVisible && !sbnVisible) {
6261 // If the notification is hidden, don't notifyPosted listeners targeting < P.
6262 // Instead, those listeners will receive notifyPosted when the notification is
6264 if (r.isHidden() && info.targetSdkVersion < Build.VERSION_CODES.P) {
6268 // If we shouldn't notify all listeners, this means the hidden state of
6269 // a notification was changed. Don't notifyPosted listeners targeting >= P.
6270 // Instead, those listeners will receive notifyRankingUpdate.
6271 if (!notifyAllListeners && info.targetSdkVersion >= Build.VERSION_CODES.P) {
6275 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
6277 // This notification became invisible -> remove the old one.
6278 if (oldSbnVisible && !sbnVisible) {
6279 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
6280 mHandler.post(new Runnable() {
6284 info, oldSbnLightClone, update, null, REASON_USER_STOPPED);
6290 grantUriPermissions(uris, sbn.getUserId(), info.component.getPackageName(),
6293 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
6294 mHandler.post(new Runnable() {
6297 notifyPosted(info, sbnToPost, update);
6303 private void grantUriPermissions(Set<Uri> uris, int notiUserId, String listenerPkg,
6304 int listenerUserId) {
6305 long ident = Binder.clearCallingIdentity();
6307 for (Uri uri : uris) {
6309 int sourceUserId = notiUserId == USER_ALL ? USER_SYSTEM
6310 : ContentProvider.getUserIdFromUri(uri, notiUserId);
6311 uri = ContentProvider.getUriWithoutUserId(uri);
6312 mAm.grantUriPermissionFromOwner(mPermissionOwner, Process.myUid(),
6314 uri, Intent.FLAG_GRANT_READ_URI_PERMISSION, sourceUserId,
6315 listenerUserId == USER_ALL ? USER_SYSTEM : listenerUserId);
6318 } catch (RemoteException e) {
6319 Log.e(TAG, "Count not grant uri permission to " + listenerPkg, e);
6321 Binder.restoreCallingIdentity(ident);
6326 * asynchronously notify all listeners about a removed notification
6328 @GuardedBy("mNotificationLock")
6329 public void notifyRemovedLocked(NotificationRecord r, int reason,
6330 NotificationStats notificationStats) {
6331 final StatusBarNotification sbn = r.sbn;
6332 // make a copy in case changes are made to the underlying Notification object
6333 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
6335 final StatusBarNotification sbnLight = sbn.cloneLight();
6336 for (final ManagedServiceInfo info : getServices()) {
6337 if (!isVisibleToListener(sbn, info)) {
6341 // don't notifyRemoved for listeners targeting < P
6342 // if not for reason package suspended
6343 if (r.isHidden() && reason != REASON_PACKAGE_SUSPENDED
6344 && info.targetSdkVersion < Build.VERSION_CODES.P) {
6348 // don't notifyRemoved for listeners targeting >= P
6349 // if the reason is package suspended
6350 if (reason == REASON_PACKAGE_SUSPENDED
6351 && info.targetSdkVersion >= Build.VERSION_CODES.P) {
6355 // Only assistants can get stats
6356 final NotificationStats stats = mAssistants.isServiceTokenValidLocked(info.service)
6357 ? notificationStats : null;
6358 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
6359 mHandler.post(new Runnable() {
6362 notifyRemoved(info, sbnLight, update, stats, reason);
6369 * Asynchronously notify all listeners about a reordering of notifications
6370 * unless changedHiddenNotifications is populated.
6371 * If changedHiddenNotifications is populated, there was a change in the hidden state
6372 * of the notifications. In this case, we only send updates to listeners that
6375 @GuardedBy("mNotificationLock")
6376 public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) {
6377 boolean isHiddenRankingUpdate = changedHiddenNotifications != null
6378 && changedHiddenNotifications.size() > 0;
6380 for (final ManagedServiceInfo serviceInfo : getServices()) {
6381 if (!serviceInfo.isEnabledForCurrentProfiles()) {
6385 boolean notifyThisListener = false;
6386 if (isHiddenRankingUpdate && serviceInfo.targetSdkVersion >=
6387 Build.VERSION_CODES.P) {
6388 for (NotificationRecord rec : changedHiddenNotifications) {
6389 if (isVisibleToListener(rec.sbn, serviceInfo)) {
6390 notifyThisListener = true;
6396 if (notifyThisListener || !isHiddenRankingUpdate) {
6397 final NotificationRankingUpdate update = makeRankingUpdateLocked(
6400 mHandler.post(new Runnable() {
6403 notifyRankingUpdate(serviceInfo, update);
6410 @GuardedBy("mNotificationLock")
6411 public void notifyListenerHintsChangedLocked(final int hints) {
6412 for (final ManagedServiceInfo serviceInfo : getServices()) {
6413 if (!serviceInfo.isEnabledForCurrentProfiles()) {
6416 mHandler.post(new Runnable() {
6419 notifyListenerHintsChanged(serviceInfo, hints);
6426 * asynchronously notify relevant listeners their notification is hidden
6427 * NotificationListenerServices that target P+:
6428 * NotificationListenerService#notifyRankingUpdateLocked()
6429 * NotificationListenerServices that target <= P:
6430 * NotificationListenerService#notifyRemovedLocked() with REASON_PACKAGE_SUSPENDED.
6432 @GuardedBy("mNotificationLock")
6433 public void notifyHiddenLocked(List<NotificationRecord> changedNotifications) {
6434 if (changedNotifications == null || changedNotifications.size() == 0) {
6438 notifyRankingUpdateLocked(changedNotifications);
6440 // for listeners that target < P, notifyRemoveLocked
6441 int numChangedNotifications = changedNotifications.size();
6442 for (int i = 0; i < numChangedNotifications; i++) {
6443 NotificationRecord rec = changedNotifications.get(i);
6444 mListeners.notifyRemovedLocked(rec, REASON_PACKAGE_SUSPENDED, rec.getStats());
6449 * asynchronously notify relevant listeners their notification is unhidden
6450 * NotificationListenerServices that target P+:
6451 * NotificationListenerService#notifyRankingUpdateLocked()
6452 * NotificationListenerServices that target <= P:
6453 * NotificationListeners#notifyPostedLocked()
6455 @GuardedBy("mNotificationLock")
6456 public void notifyUnhiddenLocked(List<NotificationRecord> changedNotifications) {
6457 if (changedNotifications == null || changedNotifications.size() == 0) {
6461 notifyRankingUpdateLocked(changedNotifications);
6463 // for listeners that target < P, notifyPostedLocked
6464 int numChangedNotifications = changedNotifications.size();
6465 for (int i = 0; i < numChangedNotifications; i++) {
6466 NotificationRecord rec = changedNotifications.get(i);
6467 mListeners.notifyPostedLocked(rec, rec.sbn, false);
6471 public void notifyInterruptionFilterChanged(final int interruptionFilter) {
6472 for (final ManagedServiceInfo serviceInfo : getServices()) {
6473 if (!serviceInfo.isEnabledForCurrentProfiles()) {
6476 mHandler.post(new Runnable() {
6479 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
6485 protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user,
6486 final NotificationChannel channel, final int modificationType) {
6487 if (channel == null) {
6490 for (final ManagedServiceInfo serviceInfo : getServices()) {
6491 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
6495 BackgroundThread.getHandler().post(() -> {
6496 if (hasCompanionDevice(serviceInfo)) {
6497 notifyNotificationChannelChanged(
6498 serviceInfo, pkg, user, channel, modificationType);
6504 protected void notifyNotificationChannelGroupChanged(
6505 final String pkg, final UserHandle user, final NotificationChannelGroup group,
6506 final int modificationType) {
6507 if (group == null) {
6510 for (final ManagedServiceInfo serviceInfo : getServices()) {
6511 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
6515 BackgroundThread.getHandler().post(() -> {
6516 if (hasCompanionDevice(serviceInfo)) {
6517 notifyNotificationChannelGroupChanged(
6518 serviceInfo, pkg, user, group, modificationType);
6524 private void notifyPosted(final ManagedServiceInfo info,
6525 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
6526 final INotificationListener listener = (INotificationListener) info.service;
6527 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
6529 listener.onNotificationPosted(sbnHolder, rankingUpdate);
6530 } catch (RemoteException ex) {
6531 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
6535 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
6536 NotificationRankingUpdate rankingUpdate, NotificationStats stats, int reason) {
6537 if (!info.enabledAndUserMatches(sbn.getUserId())) {
6540 final INotificationListener listener = (INotificationListener) info.service;
6541 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
6543 listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
6544 } catch (RemoteException ex) {
6545 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
6549 private void notifyRankingUpdate(ManagedServiceInfo info,
6550 NotificationRankingUpdate rankingUpdate) {
6551 final INotificationListener listener = (INotificationListener) info.service;
6553 listener.onNotificationRankingUpdate(rankingUpdate);
6554 } catch (RemoteException ex) {
6555 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
6559 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
6560 final INotificationListener listener = (INotificationListener) info.service;
6562 listener.onListenerHintsChanged(hints);
6563 } catch (RemoteException ex) {
6564 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
6568 private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
6569 int interruptionFilter) {
6570 final INotificationListener listener = (INotificationListener) info.service;
6572 listener.onInterruptionFilterChanged(interruptionFilter);
6573 } catch (RemoteException ex) {
6574 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
6578 void notifyNotificationChannelChanged(ManagedServiceInfo info,
6579 final String pkg, final UserHandle user, final NotificationChannel channel,
6580 final int modificationType) {
6581 final INotificationListener listener = (INotificationListener) info.service;
6583 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
6584 } catch (RemoteException ex) {
6585 Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
6589 private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
6590 final String pkg, final UserHandle user, final NotificationChannelGroup group,
6591 final int modificationType) {
6592 final INotificationListener listener = (INotificationListener) info.service;
6594 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
6595 } catch (RemoteException ex) {
6596 Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
6600 public boolean isListenerPackage(String packageName) {
6601 if (packageName == null) {
6604 // TODO: clean up locking object later
6605 synchronized (mNotificationLock) {
6606 for (final ManagedServiceInfo serviceInfo : getServices()) {
6607 if (packageName.equals(serviceInfo.component.getPackageName())) {
6616 public static final class DumpFilter {
6617 public boolean filtered = false;
6618 public String pkgFilter;
6621 public boolean stats;
6622 public boolean redact = true;
6623 public boolean proto = false;
6624 public boolean criticalPriority = false;
6625 public boolean normalPriority = false;
6628 public static DumpFilter parseFromArguments(String[] args) {
6629 final DumpFilter filter = new DumpFilter();
6630 for (int ai = 0; ai < args.length; ai++) {
6631 final String a = args[ai];
6632 if ("--proto".equals(a)) {
6633 filter.proto = true;
6634 } else if ("--noredact".equals(a) || "--reveal".equals(a)) {
6635 filter.redact = false;
6636 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
6637 if (ai < args.length-1) {
6639 filter.pkgFilter = args[ai].trim().toLowerCase();
6640 if (filter.pkgFilter.isEmpty()) {
6641 filter.pkgFilter = null;
6643 filter.filtered = true;
6646 } else if ("--zen".equals(a) || "zen".equals(a)) {
6647 filter.filtered = true;
6649 } else if ("--stats".equals(a)) {
6650 filter.stats = true;
6651 if (ai < args.length-1) {
6653 filter.since = Long.parseLong(args[ai]);
6657 } else if (PRIORITY_ARG.equals(a)) {
6658 // Bugreport will call the service twice with priority arguments, first to dump
6659 // critical sections and then non critical ones. Set approriate filters
6660 // to generate the desired data.
6661 if (ai < args.length - 1) {
6664 case PRIORITY_ARG_CRITICAL:
6665 filter.criticalPriority = true;
6667 case PRIORITY_ARG_NORMAL:
6668 filter.normalPriority = true;
6677 public boolean matches(StatusBarNotification sbn) {
6678 if (!filtered) return true;
6679 return zen ? true : sbn != null
6680 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
6683 public boolean matches(ComponentName component) {
6684 if (!filtered) return true;
6685 return zen ? true : component != null && matches(component.getPackageName());
6688 public boolean matches(String pkg) {
6689 if (!filtered) return true;
6690 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
6694 public String toString() {
6695 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
6700 protected void simulatePackageSuspendBroadcast(boolean suspend, String pkg) {
6701 // only use for testing: mimic receive broadcast that package is (un)suspended
6702 // but does not actually (un)suspend the package
6703 final Bundle extras = new Bundle();
6704 extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
6707 final String action = suspend ? Intent.ACTION_PACKAGES_SUSPENDED
6708 : Intent.ACTION_PACKAGES_UNSUSPENDED;
6709 final Intent intent = new Intent(action);
6710 intent.putExtras(extras);
6712 mPackageIntentReceiver.onReceive(getContext(), intent);
6716 * Wrapper for a StatusBarNotification object that allows transfer across a oneway
6717 * binder without sending large amounts of data over a oneway transaction.
6719 private static final class StatusBarNotificationHolder
6720 extends IStatusBarNotificationHolder.Stub {
6721 private StatusBarNotification mValue;
6723 public StatusBarNotificationHolder(StatusBarNotification value) {
6727 /** Get the held value and clear it. This function should only be called once per holder */
6729 public StatusBarNotification get() {
6730 StatusBarNotification value = mValue;
6736 private class ShellCmd extends ShellCommand {
6737 public static final String USAGE = "help\n"
6738 + "allow_listener COMPONENT [user_id]\n"
6739 + "disallow_listener COMPONENT [user_id]\n"
6740 + "allow_assistant COMPONENT\n"
6741 + "remove_assistant COMPONENT\n"
6742 + "allow_dnd PACKAGE\n"
6743 + "disallow_dnd PACKAGE\n"
6744 + "suspend_package PACKAGE\n"
6745 + "unsuspend_package PACKAGE";
6748 public int onCommand(String cmd) {
6750 return handleDefaultCommands(cmd);
6752 final PrintWriter pw = getOutPrintWriter();
6756 getBinderService().setNotificationPolicyAccessGranted(
6757 getNextArgRequired(), true);
6761 case "disallow_dnd": {
6762 getBinderService().setNotificationPolicyAccessGranted(
6763 getNextArgRequired(), false);
6766 case "allow_listener": {
6767 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
6769 pw.println("Invalid listener - must be a ComponentName");
6772 String userId = getNextArg();
6773 if (userId == null) {
6774 getBinderService().setNotificationListenerAccessGranted(cn, true);
6776 getBinderService().setNotificationListenerAccessGrantedForUser(
6777 cn, Integer.parseInt(userId), true);
6781 case "disallow_listener": {
6782 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
6784 pw.println("Invalid listener - must be a ComponentName");
6787 String userId = getNextArg();
6788 if (userId == null) {
6789 getBinderService().setNotificationListenerAccessGranted(cn, false);
6791 getBinderService().setNotificationListenerAccessGrantedForUser(
6792 cn, Integer.parseInt(userId), false);
6796 case "allow_assistant": {
6797 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
6799 pw.println("Invalid assistant - must be a ComponentName");
6802 getBinderService().setNotificationAssistantAccessGranted(cn, true);
6805 case "disallow_assistant": {
6806 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
6808 pw.println("Invalid assistant - must be a ComponentName");
6811 getBinderService().setNotificationAssistantAccessGranted(cn, false);
6814 case "suspend_package": {
6815 // only use for testing
6816 simulatePackageSuspendBroadcast(true, getNextArgRequired());
6819 case "unsuspend_package": {
6820 // only use for testing
6821 simulatePackageSuspendBroadcast(false, getNextArgRequired());
6825 return handleDefaultCommands(cmd);
6827 } catch (Exception e) {
6828 pw.println("Error occurred. Check logcat for details. " + e.getMessage());
6829 Slog.e(TAG, "Error running shell command", e);
6835 public void onHelp() {
6836 getOutPrintWriter().println(USAGE);