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.service.notification.NotificationRankerService.REASON_APP_CANCEL;
20 import static android.service.notification.NotificationRankerService.REASON_APP_CANCEL_ALL;
21 import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CANCEL;
22 import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CANCEL_ALL;
23 import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CLICK;
24 import static android.service.notification.NotificationRankerService.REASON_DELEGATE_ERROR;
25 import static android.service.notification.NotificationRankerService.REASON_GROUP_OPTIMIZATION;
26 import static android.service.notification.NotificationRankerService.REASON_GROUP_SUMMARY_CANCELED;
27 import static android.service.notification.NotificationRankerService.REASON_LISTENER_CANCEL;
28 import static android.service.notification.NotificationRankerService.REASON_LISTENER_CANCEL_ALL;
29 import static android.service.notification.NotificationRankerService.REASON_PACKAGE_BANNED;
30 import static android.service.notification.NotificationRankerService.REASON_PACKAGE_CHANGED;
31 import static android.service.notification.NotificationRankerService.REASON_PACKAGE_SUSPENDED;
32 import static android.service.notification.NotificationRankerService.REASON_PROFILE_TURNED_OFF;
33 import static android.service.notification.NotificationRankerService.REASON_USER_STOPPED;
34 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
35 import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
36 import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
37 import static android.service.notification.NotificationListenerService.TRIM_FULL;
38 import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
39 import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_DEFAULT;
40 import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_NONE;
41 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
42 import static org.xmlpull.v1.XmlPullParser.END_TAG;
43 import static org.xmlpull.v1.XmlPullParser.START_TAG;
45 import android.Manifest;
46 import android.annotation.Nullable;
47 import android.app.ActivityManager;
48 import android.app.ActivityManagerNative;
49 import android.app.AppGlobals;
50 import android.app.AppOpsManager;
51 import android.app.AutomaticZenRule;
52 import android.app.IActivityManager;
53 import android.app.INotificationManager;
54 import android.app.ITransientNotification;
55 import android.app.Notification;
56 import android.app.NotificationManager;
57 import android.app.NotificationManager.Policy;
58 import android.app.PendingIntent;
59 import android.app.StatusBarManager;
60 import android.app.backup.BackupManager;
61 import android.app.usage.UsageEvents;
62 import android.app.usage.UsageStatsManagerInternal;
63 import android.content.BroadcastReceiver;
64 import android.content.ComponentName;
65 import android.content.ContentResolver;
66 import android.content.Context;
67 import android.content.Intent;
68 import android.content.IntentFilter;
69 import android.content.pm.ApplicationInfo;
70 import android.content.pm.IPackageManager;
71 import android.content.pm.PackageInfo;
72 import android.content.pm.PackageManager;
73 import android.content.pm.PackageManager.NameNotFoundException;
74 import android.content.pm.ParceledListSlice;
75 import android.content.pm.UserInfo;
76 import android.content.res.Resources;
77 import android.database.ContentObserver;
78 import android.media.AudioAttributes;
79 import android.media.AudioManager;
80 import android.media.AudioManagerInternal;
81 import android.media.AudioSystem;
82 import android.media.IRingtonePlayer;
83 import android.net.Uri;
84 import android.os.Binder;
85 import android.os.Bundle;
86 import android.os.Environment;
87 import android.os.Handler;
88 import android.os.HandlerThread;
89 import android.os.IBinder;
90 import android.os.IInterface;
91 import android.os.Looper;
92 import android.os.Message;
93 import android.os.Process;
94 import android.os.RemoteException;
95 import android.os.SystemProperties;
96 import android.os.UserHandle;
97 import android.os.UserManager;
98 import android.os.Vibrator;
99 import android.provider.Settings;
100 import android.service.notification.Condition;
101 import android.service.notification.IConditionProvider;
102 import android.service.notification.INotificationListener;
103 import android.service.notification.IStatusBarNotificationHolder;
104 import android.service.notification.NotificationRankerService;
105 import android.service.notification.NotificationListenerService;
106 import android.service.notification.NotificationRankingUpdate;
107 import android.service.notification.StatusBarNotification;
108 import android.service.notification.ZenModeConfig;
109 import android.telephony.PhoneStateListener;
110 import android.telephony.TelephonyManager;
111 import android.text.TextUtils;
112 import android.util.ArrayMap;
113 import android.util.ArraySet;
114 import android.util.AtomicFile;
115 import android.util.Log;
116 import android.util.Slog;
117 import android.util.Xml;
118 import android.view.accessibility.AccessibilityEvent;
119 import android.view.accessibility.AccessibilityManager;
120 import android.widget.Toast;
122 import com.android.internal.R;
123 import com.android.internal.statusbar.NotificationVisibility;
124 import com.android.internal.util.FastXmlSerializer;
125 import com.android.internal.util.Preconditions;
126 import com.android.server.EventLogTags;
127 import com.android.server.LocalServices;
128 import com.android.server.SystemService;
129 import com.android.server.lights.Light;
130 import com.android.server.lights.LightsManager;
131 import com.android.server.notification.ManagedServices.ManagedServiceInfo;
132 import com.android.server.statusbar.StatusBarManagerInternal;
133 import com.android.server.vr.VrManagerInternal;
134 import com.android.server.notification.ManagedServices.UserProfiles;
136 import libcore.io.IoUtils;
138 import org.json.JSONArray;
139 import org.json.JSONException;
140 import org.json.JSONObject;
141 import org.xmlpull.v1.XmlPullParser;
142 import org.xmlpull.v1.XmlPullParserException;
143 import org.xmlpull.v1.XmlSerializer;
145 import java.io.ByteArrayInputStream;
146 import java.io.ByteArrayOutputStream;
148 import java.io.FileDescriptor;
149 import java.io.FileInputStream;
150 import java.io.FileNotFoundException;
151 import java.io.FileOutputStream;
152 import java.io.IOException;
153 import java.io.InputStream;
154 import java.io.OutputStream;
155 import java.io.PrintWriter;
156 import java.nio.charset.StandardCharsets;
157 import java.util.ArrayDeque;
158 import java.util.ArrayList;
159 import java.util.Arrays;
160 import java.util.HashSet;
161 import java.util.Iterator;
162 import java.util.List;
163 import java.util.Map.Entry;
164 import java.util.Objects;
165 import java.util.Set;
166 import java.util.concurrent.TimeUnit;
169 public class NotificationManagerService extends SystemService {
170 static final String TAG = "NotificationService";
171 static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
172 public static final boolean ENABLE_CHILD_NOTIFICATIONS
173 = SystemProperties.getBoolean("debug.child_notifs", true);
175 static final int MAX_PACKAGE_NOTIFICATIONS = 50;
178 static final int MESSAGE_TIMEOUT = 2;
179 static final int MESSAGE_SAVE_POLICY_FILE = 3;
180 static final int MESSAGE_SEND_RANKING_UPDATE = 4;
181 static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
182 static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
184 // ranking thread messages
185 private static final int MESSAGE_RECONSIDER_RANKING = 1000;
186 private static final int MESSAGE_RANKING_SORT = 1001;
188 static final int LONG_DELAY = 3500; // 3.5 seconds
189 static final int SHORT_DELAY = 2000; // 2 seconds
191 static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
193 static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
195 static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
197 static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true;
198 static final boolean ENABLE_BLOCKED_TOASTS = true;
200 // When #matchesCallFilter is called from the ringer, wait at most
201 // 3s to resolve the contacts. This timeout is required since
202 // ContactsProvider might take a long time to start up.
204 // Return STARRED_CONTACT when the timeout is hit in order to avoid
205 // missed calls in ZEN mode "Important".
206 static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
207 static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
208 ValidateNotificationPeople.STARRED_CONTACT;
210 /** notification_enqueue status value for a newly enqueued notification. */
211 private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
213 /** notification_enqueue status value for an existing notification. */
214 private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
216 /** notification_enqueue status value for an ignored notification. */
217 private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
218 private String mRankerServicePackageName;
220 private IActivityManager mAm;
221 AudioManager mAudioManager;
222 AudioManagerInternal mAudioManagerInternal;
223 @Nullable StatusBarManagerInternal mStatusBar;
225 private VrManagerInternal mVrManagerInternal;
227 final IBinder mForegroundToken = new Binder();
228 private WorkerHandler mHandler;
229 private final HandlerThread mRankingThread = new HandlerThread("ranker",
230 Process.THREAD_PRIORITY_BACKGROUND);
232 private Light mNotificationLight;
233 Light mAttentionLight;
234 private int mDefaultNotificationColor;
235 private int mDefaultNotificationLedOn;
237 private int mDefaultNotificationLedOff;
238 private long[] mDefaultVibrationPattern;
240 private long[] mFallbackVibrationPattern;
241 private boolean mUseAttentionLight;
242 boolean mSystemReady;
244 private boolean mDisableNotificationEffects;
245 private int mCallState;
246 private String mSoundNotificationKey;
247 private String mVibrateNotificationKey;
249 private final ArraySet<ManagedServiceInfo> mListenersDisablingEffects = new ArraySet<>();
250 private ComponentName mEffectsSuppressor;
251 private int mListenerHints; // right now, all hints are global
252 private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
254 // for enabling and disabling notification pulse behavior
255 private boolean mScreenOn = true;
256 private boolean mInCall = false;
257 private boolean mNotificationPulseEnabled;
259 // used as a mutex for access to all active notifications & listeners
260 final ArrayList<NotificationRecord> mNotificationList =
261 new ArrayList<NotificationRecord>();
262 final ArrayMap<String, NotificationRecord> mNotificationsByKey =
263 new ArrayMap<String, NotificationRecord>();
264 final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();
265 final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
266 final PolicyAccess mPolicyAccess = new PolicyAccess();
268 // The last key in this list owns the hardware.
269 ArrayList<String> mLights = new ArrayList<>();
271 private AppOpsManager mAppOps;
272 private UsageStatsManagerInternal mAppUsageStats;
274 private Archive mArchive;
276 // Persistent storage for notification policy
277 private AtomicFile mPolicyFile;
279 // Temporary holder for <blocked-packages> config coming from old policy files.
280 private HashSet<String> mBlockedPackages = new HashSet<String>();
282 private static final int DB_VERSION = 1;
284 private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
285 private static final String ATTR_VERSION = "version";
287 // Obsolete: converted if present, but not resaved to disk.
288 private static final String TAG_BLOCKED_PKGS = "blocked-packages";
289 private static final String TAG_PACKAGE = "package";
290 private static final String ATTR_NAME = "name";
292 private RankingHelper mRankingHelper;
294 private final UserProfiles mUserProfiles = new UserProfiles();
295 private NotificationListeners mListeners;
296 private NotificationRankers mRankerServices;
297 private ConditionProviders mConditionProviders;
298 private NotificationUsageStats mUsageStats;
300 private static final int MY_UID = Process.myUid();
301 private static final int MY_PID = Process.myPid();
302 private RankingHandler mRankingHandler;
304 private static class Archive {
305 final int mBufferSize;
306 final ArrayDeque<StatusBarNotification> mBuffer;
308 public Archive(int size) {
310 mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
313 public String toString() {
314 final StringBuilder sb = new StringBuilder();
315 final int N = mBuffer.size();
316 sb.append("Archive (");
318 sb.append(" notification");
319 sb.append((N==1)?")":"s)");
320 return sb.toString();
323 public void record(StatusBarNotification nr) {
324 if (mBuffer.size() == mBufferSize) {
325 mBuffer.removeFirst();
328 // We don't want to store the heavy bits of the notification in the archive,
329 // but other clients in the system process might be using the object, so we
330 // store a (lightened) copy.
331 mBuffer.addLast(nr.cloneLight());
334 public Iterator<StatusBarNotification> descendingIterator() {
335 return mBuffer.descendingIterator();
338 public StatusBarNotification[] getArray(int count) {
339 if (count == 0) count = mBufferSize;
340 final StatusBarNotification[] a
341 = new StatusBarNotification[Math.min(count, mBuffer.size())];
342 Iterator<StatusBarNotification> iter = descendingIterator();
344 while (iter.hasNext() && i < count) {
345 a[i++] = iter.next();
352 private void readPolicyXml(InputStream stream, boolean forRestore)
353 throws XmlPullParserException, NumberFormatException, IOException {
354 final XmlPullParser parser = Xml.newPullParser();
355 parser.setInput(stream, StandardCharsets.UTF_8.name());
359 int version = DB_VERSION;
360 while ((type = parser.next()) != END_DOCUMENT) {
361 tag = parser.getName();
362 if (type == START_TAG) {
363 if (TAG_NOTIFICATION_POLICY.equals(tag)) {
364 version = Integer.parseInt(
365 parser.getAttributeValue(null, ATTR_VERSION));
366 } else if (TAG_BLOCKED_PKGS.equals(tag)) {
367 while ((type = parser.next()) != END_DOCUMENT) {
368 tag = parser.getName();
369 if (TAG_PACKAGE.equals(tag)) {
370 mBlockedPackages.add(
371 parser.getAttributeValue(null, ATTR_NAME));
372 } else if (TAG_BLOCKED_PKGS.equals(tag) && type == END_TAG) {
378 mZenModeHelper.readXml(parser, forRestore);
379 mRankingHelper.readXml(parser, forRestore);
383 private void loadPolicyFile() {
384 if (DBG) Slog.d(TAG, "loadPolicyFile");
385 synchronized(mPolicyFile) {
386 mBlockedPackages.clear();
388 FileInputStream infile = null;
390 infile = mPolicyFile.openRead();
391 readPolicyXml(infile, false /*forRestore*/);
392 } catch (FileNotFoundException e) {
394 } catch (IOException e) {
395 Log.wtf(TAG, "Unable to read notification policy", e);
396 } catch (NumberFormatException e) {
397 Log.wtf(TAG, "Unable to parse notification policy", e);
398 } catch (XmlPullParserException e) {
399 Log.wtf(TAG, "Unable to parse notification policy", e);
401 IoUtils.closeQuietly(infile);
406 public void savePolicyFile() {
407 mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
408 mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
411 private void handleSavePolicyFile() {
412 if (DBG) Slog.d(TAG, "handleSavePolicyFile");
413 synchronized (mPolicyFile) {
414 final FileOutputStream stream;
416 stream = mPolicyFile.startWrite();
417 } catch (IOException e) {
418 Slog.w(TAG, "Failed to save policy file", e);
423 writePolicyXml(stream, false /*forBackup*/);
424 mPolicyFile.finishWrite(stream);
425 } catch (IOException e) {
426 Slog.w(TAG, "Failed to save policy file, restoring backup", e);
427 mPolicyFile.failWrite(stream);
430 BackupManager.dataChanged(getContext().getPackageName());
433 private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
434 final XmlSerializer out = new FastXmlSerializer();
435 out.setOutput(stream, StandardCharsets.UTF_8.name());
436 out.startDocument(null, true);
437 out.startTag(null, TAG_NOTIFICATION_POLICY);
438 out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
439 mZenModeHelper.writeXml(out, forBackup);
440 mRankingHelper.writeXml(out, forBackup);
441 out.endTag(null, TAG_NOTIFICATION_POLICY);
445 /** Use this when you actually want to post a notification or toast.
447 * Unchecked. Not exposed via Binder, but can be called in the course of enqueue*().
449 private boolean noteNotificationOp(String pkg, int uid) {
450 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
451 != AppOpsManager.MODE_ALLOWED) {
452 Slog.v(TAG, "notifications are disabled by AppOps for " + pkg);
458 /** Use this to check if a package can post a notification or toast. */
459 private boolean checkNotificationOp(String pkg, int uid) {
460 return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
461 == AppOpsManager.MODE_ALLOWED && !isPackageSuspendedForUser(pkg, uid);
464 private static final class ToastRecord
468 final ITransientNotification callback;
471 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration)
475 this.callback = callback;
476 this.duration = duration;
479 void update(int duration) {
480 this.duration = duration;
483 void dump(PrintWriter pw, String prefix, DumpFilter filter) {
484 if (filter != null && !filter.matches(pkg)) return;
485 pw.println(prefix + this);
489 public final String toString()
491 return "ToastRecord{"
492 + Integer.toHexString(System.identityHashCode(this))
494 + " callback=" + callback
495 + " duration=" + duration;
499 private final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
502 public void onSetDisabled(int status) {
503 synchronized (mNotificationList) {
504 mDisableNotificationEffects =
505 (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
506 if (disableNotificationEffects(null) != null) {
507 // cancel whatever's going on
508 long identity = Binder.clearCallingIdentity();
510 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
511 if (player != null) {
514 } catch (RemoteException e) {
516 Binder.restoreCallingIdentity(identity);
519 identity = Binder.clearCallingIdentity();
523 Binder.restoreCallingIdentity(identity);
530 public void onClearAll(int callingUid, int callingPid, int userId) {
531 synchronized (mNotificationList) {
532 cancelAllLocked(callingUid, callingPid, userId, REASON_DELEGATE_CANCEL_ALL, null,
533 /*includeCurrentProfiles*/ true);
538 public void onNotificationClick(int callingUid, int callingPid, String key) {
539 synchronized (mNotificationList) {
540 NotificationRecord r = mNotificationsByKey.get(key);
542 Log.w(TAG, "No notification with key: " + key);
545 final long now = System.currentTimeMillis();
546 EventLogTags.writeNotificationClicked(key,
547 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
549 StatusBarNotification sbn = r.sbn;
550 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
551 sbn.getId(), Notification.FLAG_AUTO_CANCEL,
552 Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
553 REASON_DELEGATE_CLICK, null);
558 public void onNotificationActionClick(int callingUid, int callingPid, String key,
560 synchronized (mNotificationList) {
561 NotificationRecord r = mNotificationsByKey.get(key);
563 Log.w(TAG, "No notification with key: " + key);
566 final long now = System.currentTimeMillis();
567 EventLogTags.writeNotificationActionClicked(key, actionIndex,
568 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
569 // TODO: Log action click via UsageStats.
574 public void onNotificationClear(int callingUid, int callingPid,
575 String pkg, String tag, int id, int userId) {
576 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
577 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
578 true, userId, REASON_DELEGATE_CANCEL, null);
582 public void onPanelRevealed(boolean clearEffects, int items) {
583 EventLogTags.writeNotificationPanelRevealed(items);
590 public void onPanelHidden() {
591 EventLogTags.writeNotificationPanelHidden();
595 public void clearEffects() {
596 synchronized (mNotificationList) {
597 if (DBG) Slog.d(TAG, "clearEffects");
600 mSoundNotificationKey = null;
602 long identity = Binder.clearCallingIdentity();
604 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
605 if (player != null) {
608 } catch (RemoteException e) {
610 Binder.restoreCallingIdentity(identity);
614 mVibrateNotificationKey = null;
615 identity = Binder.clearCallingIdentity();
619 Binder.restoreCallingIdentity(identity);
624 updateLightsLocked();
629 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
630 int uid, int initialPid, String message, int userId) {
631 Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
632 + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
633 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
634 REASON_DELEGATE_ERROR, null);
635 long ident = Binder.clearCallingIdentity();
637 ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg,
638 "Bad notification posted from package " + pkg
640 } catch (RemoteException e) {
642 Binder.restoreCallingIdentity(ident);
646 public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
647 NotificationVisibility[] noLongerVisibleKeys) {
648 synchronized (mNotificationList) {
649 for (NotificationVisibility nv : newlyVisibleKeys) {
650 NotificationRecord r = mNotificationsByKey.get(nv.key);
651 if (r == null) continue;
652 r.setVisibility(true, nv.rank);
655 // Note that we might receive this event after notifications
656 // have already left the system, e.g. after dismissing from the
657 // shade. Hence not finding notifications in
658 // mNotificationsByKey is not an exceptional condition.
659 for (NotificationVisibility nv : noLongerVisibleKeys) {
660 NotificationRecord r = mNotificationsByKey.get(nv.key);
661 if (r == null) continue;
662 r.setVisibility(false, nv.rank);
669 public void onNotificationExpansionChanged(String key,
670 boolean userAction, boolean expanded) {
671 synchronized (mNotificationList) {
672 NotificationRecord r = mNotificationsByKey.get(key);
674 r.stats.onExpansionChanged(userAction, expanded);
675 final long now = System.currentTimeMillis();
676 EventLogTags.writeNotificationExpansion(key,
677 userAction ? 1 : 0, expanded ? 1 : 0,
678 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
684 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
686 public void onReceive(Context context, Intent intent) {
687 String action = intent.getAction();
688 if (action == null) {
692 boolean queryRestart = false;
693 boolean queryRemove = false;
694 boolean packageChanged = false;
695 boolean cancelNotifications = true;
696 int reason = REASON_PACKAGE_CHANGED;
698 if (action.equals(Intent.ACTION_PACKAGE_ADDED)
699 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
700 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
701 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
702 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
703 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
704 || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
705 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
706 UserHandle.USER_ALL);
707 String pkgList[] = null;
708 boolean queryReplace = queryRemove &&
709 intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
710 if (DBG) Slog.i(TAG, "action=" + action + " queryReplace=" + queryReplace);
711 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
712 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
713 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
714 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
715 reason = REASON_PACKAGE_SUSPENDED;
716 } else if (queryRestart) {
717 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
719 Uri uri = intent.getData();
723 String pkgName = uri.getSchemeSpecificPart();
724 if (pkgName == null) {
727 if (packageChanged) {
728 // We cancel notifications for packages which have just been disabled
730 final IPackageManager pm = AppGlobals.getPackageManager();
731 final int enabled = pm.getApplicationEnabledSetting(pkgName,
732 changeUserId != UserHandle.USER_ALL ? changeUserId :
733 UserHandle.USER_SYSTEM);
734 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
735 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
736 cancelNotifications = false;
738 } catch (IllegalArgumentException e) {
739 // Package doesn't exist; probably racing with uninstall.
740 // cancelNotifications is already true, so nothing to do here.
742 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
744 } catch (RemoteException e) {
745 // Failed to talk to PackageManagerService Should never happen!
748 pkgList = new String[]{pkgName};
751 if (pkgList != null && (pkgList.length > 0)) {
752 for (String pkgName : pkgList) {
753 if (cancelNotifications) {
754 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart,
755 changeUserId, reason, null);
759 mListeners.onPackagesChanged(queryReplace, pkgList);
760 mRankerServices.onPackagesChanged(queryReplace, pkgList);
761 mConditionProviders.onPackagesChanged(queryReplace, pkgList);
762 mRankingHelper.onPackagesChanged(queryReplace, pkgList);
767 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
769 public void onReceive(Context context, Intent intent) {
770 String action = intent.getAction();
772 if (action.equals(Intent.ACTION_SCREEN_ON)) {
773 // Keep track of screen on/off state, but do not turn off the notification light
774 // until user passes through the lock screen or views the notification.
776 updateNotificationPulse();
777 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
779 updateNotificationPulse();
780 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
781 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
782 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
783 updateNotificationPulse();
784 } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
785 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
786 if (userHandle >= 0) {
787 cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
788 REASON_USER_STOPPED, null);
790 } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED)) {
791 boolean inQuietMode = intent.getBooleanExtra(Intent.EXTRA_QUIET_MODE, false);
792 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
793 if (inQuietMode && userHandle >= 0) {
794 cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
795 REASON_PROFILE_TURNED_OFF, null);
797 } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
798 // turn off LED when user passes through lock screen
799 mNotificationLight.turnOff();
800 if (mStatusBar != null) {
801 mStatusBar.notificationLightOff();
803 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
804 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
805 // reload per-user settings
806 mSettingsObserver.update(null);
807 mUserProfiles.updateCache(context);
808 // Refresh managed services
809 mConditionProviders.onUserSwitched(user);
810 mListeners.onUserSwitched(user);
811 mRankerServices.onUserSwitched(user);
812 mZenModeHelper.onUserSwitched(user);
813 } else if (action.equals(Intent.ACTION_USER_ADDED)) {
814 mUserProfiles.updateCache(context);
815 } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
816 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
817 mZenModeHelper.onUserRemoved(user);
818 } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
819 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
820 mConditionProviders.onUserUnlocked(user);
821 mListeners.onUserUnlocked(user);
822 mRankerServices.onUserUnlocked(user);
823 mZenModeHelper.onUserUnlocked(user);
828 private final class SettingsObserver extends ContentObserver {
829 private final Uri NOTIFICATION_LIGHT_PULSE_URI
830 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
832 SettingsObserver(Handler handler) {
837 ContentResolver resolver = getContext().getContentResolver();
838 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
839 false, this, UserHandle.USER_ALL);
843 @Override public void onChange(boolean selfChange, Uri uri) {
847 public void update(Uri uri) {
848 ContentResolver resolver = getContext().getContentResolver();
849 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
850 boolean pulseEnabled = Settings.System.getInt(resolver,
851 Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
852 if (mNotificationPulseEnabled != pulseEnabled) {
853 mNotificationPulseEnabled = pulseEnabled;
854 updateNotificationPulse();
860 private SettingsObserver mSettingsObserver;
861 private ZenModeHelper mZenModeHelper;
863 private final Runnable mBuzzBeepBlinked = new Runnable() {
866 if (mStatusBar != null) {
867 mStatusBar.buzzBeepBlinked();
872 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
873 int[] ar = r.getIntArray(resid);
877 final int len = ar.length > maxlen ? maxlen : ar.length;
878 long[] out = new long[len];
879 for (int i=0; i<len; i++) {
885 public NotificationManagerService(Context context) {
890 public void onStart() {
891 Resources resources = getContext().getResources();
893 mAm = ActivityManagerNative.getDefault();
894 mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
895 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
896 mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
898 // This is the package that contains the AOSP framework update.
899 mRankerServicePackageName = getContext().getPackageManager()
900 .getServicesSystemSharedLibraryPackageName();
902 mHandler = new WorkerHandler();
903 mRankingThread.start();
904 String[] extractorNames;
906 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
907 } catch (Resources.NotFoundException e) {
908 extractorNames = new String[0];
910 mUsageStats = new NotificationUsageStats(getContext());
911 mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
912 mRankingHelper = new RankingHelper(getContext(),
916 mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles);
917 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
918 mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
920 public void onConfigChanged() {
925 void onZenModeChanged() {
926 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
927 getContext().sendBroadcastAsUser(
928 new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
929 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
930 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
931 synchronized(mNotificationList) {
932 updateInterruptionFilterLocked();
937 void onPolicyChanged() {
938 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
941 final File systemDir = new File(Environment.getDataDirectory(), "system");
942 mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
946 // This is a MangedServices object that keeps track of the listeners.
947 mListeners = new NotificationListeners();
949 // This is a MangedServices object that keeps track of the ranker.
950 mRankerServices = new NotificationRankers();
951 // Find the updatable ranker and register it.
952 mRankerServices.registerRanker();
954 mStatusBar = getLocalService(StatusBarManagerInternal.class);
955 if (mStatusBar != null) {
956 mStatusBar.setNotificationDelegate(mNotificationDelegate);
959 final LightsManager lights = getLocalService(LightsManager.class);
960 mNotificationLight = lights.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
961 mAttentionLight = lights.getLight(LightsManager.LIGHT_ID_ATTENTION);
963 mDefaultNotificationColor = resources.getColor(
964 R.color.config_defaultNotificationColor);
965 mDefaultNotificationLedOn = resources.getInteger(
966 R.integer.config_defaultNotificationLedOn);
967 mDefaultNotificationLedOff = resources.getInteger(
968 R.integer.config_defaultNotificationLedOff);
970 mDefaultVibrationPattern = getLongArray(resources,
971 R.array.config_defaultNotificationVibePattern,
972 VIBRATE_PATTERN_MAXLEN,
973 DEFAULT_VIBRATE_PATTERN);
975 mFallbackVibrationPattern = getLongArray(resources,
976 R.array.config_notificationFallbackVibePattern,
977 VIBRATE_PATTERN_MAXLEN,
978 DEFAULT_VIBRATE_PATTERN);
980 mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
982 // Don't start allowing notifications until the setup wizard has run once.
983 // After that, including subsequent boots, init with notifications turned on.
984 // This works on the first boot because the setup wizard will toggle this
985 // flag at least once and we'll go back to 0 after that.
986 if (0 == Settings.Global.getInt(getContext().getContentResolver(),
987 Settings.Global.DEVICE_PROVISIONED, 0)) {
988 mDisableNotificationEffects = true;
990 mZenModeHelper.initZenMode();
991 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
993 mUserProfiles.updateCache(getContext());
994 listenForCallState();
996 // register for various Intents
997 IntentFilter filter = new IntentFilter();
998 filter.addAction(Intent.ACTION_SCREEN_ON);
999 filter.addAction(Intent.ACTION_SCREEN_OFF);
1000 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
1001 filter.addAction(Intent.ACTION_USER_PRESENT);
1002 filter.addAction(Intent.ACTION_USER_STOPPED);
1003 filter.addAction(Intent.ACTION_USER_SWITCHED);
1004 filter.addAction(Intent.ACTION_USER_ADDED);
1005 filter.addAction(Intent.ACTION_USER_REMOVED);
1006 filter.addAction(Intent.ACTION_USER_UNLOCKED);
1007 filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED);
1008 getContext().registerReceiver(mIntentReceiver, filter);
1010 IntentFilter pkgFilter = new IntentFilter();
1011 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
1012 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1013 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
1014 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1015 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1016 pkgFilter.addDataScheme("package");
1017 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1020 IntentFilter suspendedPkgFilter = new IntentFilter();
1021 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
1022 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1023 suspendedPkgFilter, null, null);
1025 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
1026 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1029 mSettingsObserver = new SettingsObserver(mHandler);
1031 mArchive = new Archive(resources.getInteger(
1032 R.integer.config_notificationServiceArchiveSize));
1034 publishBinderService(Context.NOTIFICATION_SERVICE, mService);
1035 publishLocalService(NotificationManagerInternal.class, mInternalService);
1038 private void sendRegisteredOnlyBroadcast(String action) {
1039 getContext().sendBroadcastAsUser(new Intent(action)
1040 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
1044 * Read the old XML-based app block database and import those blockages into the AppOps system.
1046 private void importOldBlockDb() {
1049 PackageManager pm = getContext().getPackageManager();
1050 for (String pkg : mBlockedPackages) {
1051 PackageInfo info = null;
1053 info = pm.getPackageInfo(pkg, 0);
1054 setNotificationsEnabledForPackageImpl(pkg, info.applicationInfo.uid, false);
1055 } catch (NameNotFoundException e) {
1059 mBlockedPackages.clear();
1063 public void onBootPhase(int phase) {
1064 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1065 // no beeping until we're basically done booting
1066 mSystemReady = true;
1068 // Grab our optional AudioService
1069 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
1070 mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
1071 mVrManagerInternal = getLocalService(VrManagerInternal.class);
1072 mZenModeHelper.onSystemReady();
1073 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1074 // This observer will force an update when observe is called, causing us to
1075 // bind to listener services.
1076 mSettingsObserver.observe();
1077 mListeners.onBootPhaseAppsCanStart();
1078 mRankerServices.onBootPhaseAppsCanStart();
1079 mConditionProviders.onBootPhaseAppsCanStart();
1083 void setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled) {
1084 Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
1086 mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
1087 enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
1089 // Now, cancel any outstanding notifications that are part of a just-disabled app
1090 if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
1091 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true, UserHandle.getUserId(uid),
1092 REASON_PACKAGE_BANNED, null);
1096 private void updateListenerHintsLocked() {
1097 final int hints = mListenersDisablingEffects.isEmpty() ? 0 : HINT_HOST_DISABLE_EFFECTS;
1098 if (hints == mListenerHints) return;
1099 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mListenersDisablingEffects.size());
1100 mListenerHints = hints;
1101 scheduleListenerHintsChanged(hints);
1104 private void updateEffectsSuppressorLocked() {
1105 final ComponentName suppressor = !mListenersDisablingEffects.isEmpty()
1106 ? mListenersDisablingEffects.valueAt(0).component : null;
1107 if (Objects.equals(suppressor, mEffectsSuppressor)) return;
1108 ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressor, suppressor);
1109 mEffectsSuppressor = suppressor;
1110 mZenModeHelper.setEffectsSuppressed(suppressor != null);
1111 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
1114 private void updateInterruptionFilterLocked() {
1115 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1116 if (interruptionFilter == mInterruptionFilter) return;
1117 mInterruptionFilter = interruptionFilter;
1118 scheduleInterruptionFilterChanged(interruptionFilter);
1121 private final IBinder mService = new INotificationManager.Stub() {
1123 // ============================================================================
1126 public void enqueueToast(String pkg, ITransientNotification callback, int duration)
1129 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1130 + " duration=" + duration);
1133 if (pkg == null || callback == null) {
1134 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1138 final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg));
1139 final boolean isPackageSuspended =
1140 isPackageSuspendedForUser(pkg, Binder.getCallingUid());
1142 if (ENABLE_BLOCKED_TOASTS && (!noteNotificationOp(pkg, Binder.getCallingUid())
1143 || isPackageSuspended)) {
1144 if (!isSystemToast) {
1145 Slog.e(TAG, "Suppressing toast from package " + pkg
1146 + (isPackageSuspended
1147 ? " due to package suspended by administrator."
1148 : " by user request."));
1153 synchronized (mToastQueue) {
1154 int callingPid = Binder.getCallingPid();
1155 long callingId = Binder.clearCallingIdentity();
1158 int index = indexOfToastLocked(pkg, callback);
1159 // If it's already in the queue, we update it in place, we don't
1160 // move it to the end of the queue.
1162 record = mToastQueue.get(index);
1163 record.update(duration);
1165 // Limit the number of toasts that any given package except the android
1166 // package can enqueue. Prevents DOS attacks and deals with leaks.
1167 if (!isSystemToast) {
1169 final int N = mToastQueue.size();
1170 for (int i=0; i<N; i++) {
1171 final ToastRecord r = mToastQueue.get(i);
1172 if (r.pkg.equals(pkg)) {
1174 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
1175 Slog.e(TAG, "Package has already posted " + count
1176 + " toasts. Not showing more. Package=" + pkg);
1183 record = new ToastRecord(callingPid, pkg, callback, duration);
1184 mToastQueue.add(record);
1185 index = mToastQueue.size() - 1;
1186 keepProcessAliveLocked(callingPid);
1188 // If it's at index 0, it's the current toast. It doesn't matter if it's
1189 // new or just been updated. Call back and tell it to show itself.
1190 // If the callback fails, this will remove it from the list, so don't
1191 // assume that it's valid after this.
1193 showNextToastLocked();
1196 Binder.restoreCallingIdentity(callingId);
1202 public void cancelToast(String pkg, ITransientNotification callback) {
1203 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
1205 if (pkg == null || callback == null) {
1206 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
1210 synchronized (mToastQueue) {
1211 long callingId = Binder.clearCallingIdentity();
1213 int index = indexOfToastLocked(pkg, callback);
1215 cancelToastLocked(index);
1217 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
1218 + " callback=" + callback);
1221 Binder.restoreCallingIdentity(callingId);
1227 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
1228 Notification notification, int[] idOut, int userId) throws RemoteException {
1229 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
1230 Binder.getCallingPid(), tag, id, notification, idOut, userId);
1234 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
1235 checkCallerIsSystemOrSameApp(pkg);
1236 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1237 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
1238 // Don't allow client applications to cancel foreground service notis.
1239 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
1240 Binder.getCallingUid() == Process.SYSTEM_UID
1241 ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false, userId,
1242 REASON_APP_CANCEL, null);
1246 public void cancelAllNotifications(String pkg, int userId) {
1247 checkCallerIsSystemOrSameApp(pkg);
1249 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1250 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
1252 // Calling from user space, don't allow the canceling of actively
1253 // running foreground services.
1254 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
1255 pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
1256 REASON_APP_CANCEL_ALL, null);
1260 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
1261 checkCallerIsSystem();
1263 setNotificationsEnabledForPackageImpl(pkg, uid, enabled);
1267 * Use this when you just want to know if notifications are OK for this package.
1270 public boolean areNotificationsEnabled(String pkg) {
1271 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
1275 * Use this when you just want to know if notifications are OK for this package.
1278 public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
1279 checkCallerIsSystemOrSameApp(pkg);
1280 return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
1281 == AppOpsManager.MODE_ALLOWED) && !isPackageSuspendedForUser(pkg, uid);
1285 public void setPriority(String pkg, int uid, int priority) {
1286 checkCallerIsSystem();
1287 mRankingHelper.setPriority(pkg, uid, priority);
1292 public int getPriority(String pkg, int uid) {
1293 checkCallerIsSystem();
1294 return mRankingHelper.getPriority(pkg, uid);
1298 public void setVisibilityOverride(String pkg, int uid, int visibility) {
1299 checkCallerIsSystem();
1300 mRankingHelper.setVisibilityOverride(pkg, uid, visibility);
1305 public int getVisibilityOverride(String pkg, int uid) {
1306 checkCallerIsSystem();
1307 return mRankingHelper.getVisibilityOverride(pkg, uid);
1311 public void setImportance(String pkg, int uid, int importance) {
1312 enforceSystemOrSystemUI("Caller not system or systemui");
1313 setNotificationsEnabledForPackageImpl(pkg, uid,
1314 importance != NotificationListenerService.Ranking.IMPORTANCE_NONE);
1315 mRankingHelper.setImportance(pkg, uid, importance);
1320 public int getPackageImportance(String pkg) {
1321 checkCallerIsSystemOrSameApp(pkg);
1322 return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
1326 public int getImportance(String pkg, int uid) {
1327 enforceSystemOrSystemUI("Caller not system or systemui");
1328 return mRankingHelper.getImportance(pkg, uid);
1332 * System-only API for getting a list of current (i.e. not cleared) notifications.
1334 * Requires ACCESS_NOTIFICATIONS which is signature|system.
1335 * @returns A list of all the notifications, in natural order.
1338 public StatusBarNotification[] getActiveNotifications(String callingPkg) {
1339 // enforce() will ensure the calling uid has the correct permission
1340 getContext().enforceCallingOrSelfPermission(
1341 android.Manifest.permission.ACCESS_NOTIFICATIONS,
1342 "NotificationManagerService.getActiveNotifications");
1344 StatusBarNotification[] tmp = null;
1345 int uid = Binder.getCallingUid();
1347 // noteOp will check to make sure the callingPkg matches the uid
1348 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1349 == AppOpsManager.MODE_ALLOWED) {
1350 synchronized (mNotificationList) {
1351 tmp = new StatusBarNotification[mNotificationList.size()];
1352 final int N = mNotificationList.size();
1353 for (int i=0; i<N; i++) {
1354 tmp[i] = mNotificationList.get(i).sbn;
1362 * Public API for getting a list of current notifications for the calling package/uid.
1364 * @returns A list of all the package's notifications, in natural order.
1367 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
1368 int incomingUserId) {
1369 checkCallerIsSystemOrSameApp(pkg);
1370 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1371 Binder.getCallingUid(), incomingUserId, true, false,
1372 "getAppActiveNotifications", pkg);
1374 final ArrayList<StatusBarNotification> list
1375 = new ArrayList<StatusBarNotification>(mNotificationList.size());
1377 synchronized (mNotificationList) {
1378 final int N = mNotificationList.size();
1379 for (int i = 0; i < N; i++) {
1380 final StatusBarNotification sbn = mNotificationList.get(i).sbn;
1381 if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId) {
1382 // We could pass back a cloneLight() but clients might get confused and
1383 // try to send this thing back to notify() again, which would not work
1385 final StatusBarNotification sbnOut = new StatusBarNotification(
1386 sbn.getPackageName(),
1388 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
1389 0, // hide score from apps
1390 sbn.getNotification().clone(),
1391 sbn.getUser(), sbn.getPostTime());
1397 return new ParceledListSlice<StatusBarNotification>(list);
1401 * System-only API for getting a list of recent (cleared, no longer shown) notifications.
1403 * Requires ACCESS_NOTIFICATIONS which is signature|system.
1406 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
1407 // enforce() will ensure the calling uid has the correct permission
1408 getContext().enforceCallingOrSelfPermission(
1409 android.Manifest.permission.ACCESS_NOTIFICATIONS,
1410 "NotificationManagerService.getHistoricalNotifications");
1412 StatusBarNotification[] tmp = null;
1413 int uid = Binder.getCallingUid();
1415 // noteOp will check to make sure the callingPkg matches the uid
1416 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1417 == AppOpsManager.MODE_ALLOWED) {
1418 synchronized (mArchive) {
1419 tmp = mArchive.getArray(count);
1426 * Register a listener binder directly with the notification manager.
1428 * Only works with system callers. Apps should extend
1429 * {@link android.service.notification.NotificationListenerService}.
1432 public void registerListener(final INotificationListener listener,
1433 final ComponentName component, final int userid) {
1434 enforceSystemOrSystemUI("INotificationManager.registerListener");
1435 mListeners.registerService(listener, component, userid);
1439 * Remove a listener binder directly
1442 public void unregisterListener(INotificationListener token, int userid) {
1443 mListeners.unregisterService(token, userid);
1447 * Allow an INotificationListener to simulate a "clear all" operation.
1449 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
1451 * @param token The binder for the listener, to check that the caller is allowed
1454 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
1455 final int callingUid = Binder.getCallingUid();
1456 final int callingPid = Binder.getCallingPid();
1457 long identity = Binder.clearCallingIdentity();
1459 synchronized (mNotificationList) {
1460 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1462 final int N = keys.length;
1463 for (int i = 0; i < N; i++) {
1464 NotificationRecord r = mNotificationsByKey.get(keys[i]);
1465 if (r == null) continue;
1466 final int userId = r.sbn.getUserId();
1467 if (userId != info.userid && userId != UserHandle.USER_ALL &&
1468 !mUserProfiles.isCurrentProfile(userId)) {
1469 throw new SecurityException("Disallowed call from listener: "
1472 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
1473 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
1477 cancelAllLocked(callingUid, callingPid, info.userid,
1478 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
1482 Binder.restoreCallingIdentity(identity);
1487 * Handle request from an approved listener to re-enable itself.
1489 * @param component The componenet to be re-enabled, caller must match package.
1492 public void requestBindListener(ComponentName component) {
1493 checkCallerIsSystemOrSameApp(component.getPackageName());
1494 long identity = Binder.clearCallingIdentity();
1496 ManagedServices manager = mRankerServices.isComponentEnabledForCurrentProfiles(component)
1499 manager.setComponentState(component, true);
1501 Binder.restoreCallingIdentity(identity);
1506 public void requestUnbindListener(INotificationListener token) {
1507 long identity = Binder.clearCallingIdentity();
1509 // allow bound services to disable themselves
1510 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1511 info.getOwner().setComponentState(info.component, false);
1513 Binder.restoreCallingIdentity(identity);
1518 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
1519 long identity = Binder.clearCallingIdentity();
1521 synchronized (mNotificationList) {
1522 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1524 final int N = keys.length;
1525 for (int i = 0; i < N; i++) {
1526 NotificationRecord r = mNotificationsByKey.get(keys[i]);
1527 if (r == null) continue;
1528 final int userId = r.sbn.getUserId();
1529 if (userId != info.userid && userId != UserHandle.USER_ALL &&
1530 !mUserProfiles.isCurrentProfile(userId)) {
1531 throw new SecurityException("Disallowed call from listener: "
1535 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
1536 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
1537 userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM
1539 UsageEvents.Event.USER_INTERACTION);
1546 Binder.restoreCallingIdentity(identity);
1550 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
1551 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
1552 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
1553 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
1555 userId, REASON_LISTENER_CANCEL, info);
1559 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
1561 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
1563 * @param token The binder for the listener, to check that the caller is allowed
1566 public void cancelNotificationFromListener(INotificationListener token, String pkg,
1567 String tag, int id) {
1568 final int callingUid = Binder.getCallingUid();
1569 final int callingPid = Binder.getCallingPid();
1570 long identity = Binder.clearCallingIdentity();
1572 synchronized (mNotificationList) {
1573 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1574 if (info.supportsProfiles()) {
1575 Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
1576 + "from " + info.component
1577 + " use cancelNotification(key) instead.");
1579 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
1580 pkg, tag, id, info.userid);
1584 Binder.restoreCallingIdentity(identity);
1589 * Allow an INotificationListener to request the list of outstanding notifications seen by
1590 * the current user. Useful when starting up, after which point the listener callbacks
1593 * @param token The binder for the listener, to check that the caller is allowed
1594 * @param keys An array of notification keys to fetch, or null to fetch everything
1595 * @returns The return value will contain the notifications specified in keys, in that
1596 * order, or if keys is null, all the notifications, in natural order.
1599 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
1600 INotificationListener token, String[] keys, int trim) {
1601 synchronized (mNotificationList) {
1602 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1603 final boolean getKeys = keys != null;
1604 final int N = getKeys ? keys.length : mNotificationList.size();
1605 final ArrayList<StatusBarNotification> list
1606 = new ArrayList<StatusBarNotification>(N);
1607 for (int i=0; i<N; i++) {
1608 final NotificationRecord r = getKeys
1609 ? mNotificationsByKey.get(keys[i])
1610 : mNotificationList.get(i);
1611 if (r == null) continue;
1612 StatusBarNotification sbn = r.sbn;
1613 if (!isVisibleToListener(sbn, info)) continue;
1614 StatusBarNotification sbnToSend =
1615 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
1616 list.add(sbnToSend);
1618 return new ParceledListSlice<StatusBarNotification>(list);
1623 public void requestHintsFromListener(INotificationListener token, int hints) {
1624 final long identity = Binder.clearCallingIdentity();
1626 synchronized (mNotificationList) {
1627 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1628 final boolean disableEffects = (hints & HINT_HOST_DISABLE_EFFECTS) != 0;
1629 if (disableEffects) {
1630 mListenersDisablingEffects.add(info);
1632 mListenersDisablingEffects.remove(info);
1634 updateListenerHintsLocked();
1635 updateEffectsSuppressorLocked();
1638 Binder.restoreCallingIdentity(identity);
1643 public int getHintsFromListener(INotificationListener token) {
1644 synchronized (mNotificationList) {
1645 return mListenerHints;
1650 public void requestInterruptionFilterFromListener(INotificationListener token,
1651 int interruptionFilter) throws RemoteException {
1652 final long identity = Binder.clearCallingIdentity();
1654 synchronized (mNotificationList) {
1655 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1656 mZenModeHelper.requestFromListener(info.component, interruptionFilter);
1657 updateInterruptionFilterLocked();
1660 Binder.restoreCallingIdentity(identity);
1665 public int getInterruptionFilterFromListener(INotificationListener token)
1666 throws RemoteException {
1667 synchronized (mNotificationLight) {
1668 return mInterruptionFilter;
1673 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
1674 throws RemoteException {
1675 synchronized (mNotificationList) {
1676 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1677 if (info == null) return;
1678 mListeners.setOnNotificationPostedTrimLocked(info, trim);
1683 public int getZenMode() {
1684 return mZenModeHelper.getZenMode();
1688 public ZenModeConfig getZenModeConfig() {
1689 enforceSystemOrSystemUIOrVolume("INotificationManager.getZenModeConfig");
1690 return mZenModeHelper.getConfig();
1694 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
1695 enforceSystemOrSystemUIOrVolume("INotificationManager.setZenMode");
1696 final long identity = Binder.clearCallingIdentity();
1698 mZenModeHelper.setManualZenMode(mode, conditionId, reason);
1700 Binder.restoreCallingIdentity(identity);
1705 public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
1706 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
1707 return mZenModeHelper.getZenRules();
1711 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
1712 Preconditions.checkNotNull(id, "Id is null");
1713 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
1714 return mZenModeHelper.getAutomaticZenRule(id);
1718 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
1719 throws RemoteException {
1720 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
1721 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
1722 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
1723 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
1724 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
1726 return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
1727 "addAutomaticZenRule");
1731 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
1732 throws RemoteException {
1733 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
1734 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
1735 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
1736 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
1737 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
1739 return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
1740 "updateAutomaticZenRule");
1744 public boolean removeAutomaticZenRule(String id) throws RemoteException {
1745 Preconditions.checkNotNull(id, "Id is null");
1746 // Verify that they can modify zen rules.
1747 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
1749 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
1753 public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
1754 Preconditions.checkNotNull(packageName, "Package name is null");
1755 enforceSystemOrSystemUI("removeAutomaticZenRules");
1757 return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
1761 public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
1762 Preconditions.checkNotNull(owner, "Owner is null");
1763 enforceSystemOrSystemUI("getRuleInstanceCount");
1765 return mZenModeHelper.getCurrentInstanceCount(owner);
1769 public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
1770 enforcePolicyAccess(pkg, "setInterruptionFilter");
1771 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
1772 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
1773 final long identity = Binder.clearCallingIdentity();
1775 mZenModeHelper.setManualZenMode(zen, null, "setInterruptionFilter");
1777 Binder.restoreCallingIdentity(identity);
1782 public void notifyConditions(final String pkg, IConditionProvider provider,
1783 final Condition[] conditions) {
1784 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
1785 checkCallerIsSystemOrSameApp(pkg);
1786 mHandler.post(new Runnable() {
1789 mConditionProviders.notifyConditions(pkg, info, conditions);
1794 private void enforceSystemOrSystemUIOrVolume(String message) {
1795 if (mAudioManagerInternal != null) {
1796 final int vcuid = mAudioManagerInternal.getVolumeControllerUid();
1797 if (vcuid > 0 && Binder.getCallingUid() == vcuid) {
1801 enforceSystemOrSystemUI(message);
1804 private void enforceSystemOrSystemUI(String message) {
1805 if (isCallerSystem()) return;
1806 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
1810 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
1812 checkCallerIsSystemOrSameApp(pkg);
1813 } catch (SecurityException e) {
1814 getContext().enforceCallingPermission(
1815 android.Manifest.permission.STATUS_BAR_SERVICE,
1820 private void enforcePolicyAccess(int uid, String method) {
1821 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
1822 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
1825 boolean accessAllowed = false;
1826 String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
1827 final int packageCount = packages.length;
1828 for (int i = 0; i < packageCount; i++) {
1829 if (checkPolicyAccess(packages[i])) {
1830 accessAllowed = true;
1833 if (!accessAllowed) {
1834 Slog.w(TAG, "Notification policy access denied calling " + method);
1835 throw new SecurityException("Notification policy access denied");
1839 private void enforcePolicyAccess(String pkg, String method) {
1840 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
1841 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
1844 if (!checkPolicyAccess(pkg)) {
1845 Slog.w(TAG, "Notification policy access denied calling " + method);
1846 throw new SecurityException("Notification policy access denied");
1850 private boolean checkPackagePolicyAccess(String pkg) {
1851 return mPolicyAccess.isPackageGranted(pkg);
1854 private boolean checkPolicyAccess(String pkg) {
1855 return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
1859 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1860 if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1861 != PackageManager.PERMISSION_GRANTED) {
1862 pw.println("Permission Denial: can't dump NotificationManager from pid="
1863 + Binder.getCallingPid()
1864 + ", uid=" + Binder.getCallingUid());
1868 final DumpFilter filter = DumpFilter.parseFromArguments(args);
1869 if (filter != null && filter.stats) {
1870 dumpJson(pw, filter);
1872 dumpImpl(pw, filter);
1877 public ComponentName getEffectsSuppressor() {
1878 enforceSystemOrSystemUIOrVolume("INotificationManager.getEffectsSuppressor");
1879 return mEffectsSuppressor;
1883 public boolean matchesCallFilter(Bundle extras) {
1884 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
1885 return mZenModeHelper.matchesCallFilter(
1886 Binder.getCallingUserHandle(),
1888 mRankingHelper.findExtractor(ValidateNotificationPeople.class),
1889 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
1890 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
1894 public boolean isSystemConditionProviderEnabled(String path) {
1895 enforceSystemOrSystemUIOrVolume("INotificationManager.isSystemConditionProviderEnabled");
1896 return mConditionProviders.isSystemProviderEnabled(path);
1899 // Backup/restore interface
1901 public byte[] getBackupPayload(int user) {
1902 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
1903 //TODO: http://b/22388012
1904 if (user != UserHandle.USER_SYSTEM) {
1905 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
1908 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
1910 writePolicyXml(baos, true /*forBackup*/);
1911 return baos.toByteArray();
1912 } catch (IOException e) {
1913 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
1919 public void applyRestore(byte[] payload, int user) {
1920 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
1921 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
1922 if (payload == null) {
1923 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
1926 //TODO: http://b/22388012
1927 if (user != UserHandle.USER_SYSTEM) {
1928 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
1931 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
1933 readPolicyXml(bais, true /*forRestore*/);
1935 } catch (NumberFormatException | XmlPullParserException | IOException e) {
1936 Slog.w(TAG, "applyRestore: error reading payload", e);
1941 public boolean isNotificationPolicyAccessGranted(String pkg) {
1942 return checkPolicyAccess(pkg);
1946 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
1947 enforceSystemOrSystemUIOrSamePackage(pkg,
1948 "request policy access status for another package");
1949 return checkPackagePolicyAccess(pkg);
1953 public String[] getPackagesRequestingNotificationPolicyAccess()
1954 throws RemoteException {
1955 enforceSystemOrSystemUI("request policy access packages");
1956 final long identity = Binder.clearCallingIdentity();
1958 return mPolicyAccess.getRequestingPackages();
1960 Binder.restoreCallingIdentity(identity);
1965 public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
1966 throws RemoteException {
1967 enforceSystemOrSystemUI("grant notification policy access");
1968 final long identity = Binder.clearCallingIdentity();
1970 synchronized (mNotificationList) {
1971 mPolicyAccess.put(pkg, granted);
1974 Binder.restoreCallingIdentity(identity);
1979 public Policy getNotificationPolicy(String pkg) {
1980 enforcePolicyAccess(pkg, "getNotificationPolicy");
1981 final long identity = Binder.clearCallingIdentity();
1983 return mZenModeHelper.getNotificationPolicy();
1985 Binder.restoreCallingIdentity(identity);
1990 public void setNotificationPolicy(String pkg, Policy policy) {
1991 enforcePolicyAccess(pkg, "setNotificationPolicy");
1992 final long identity = Binder.clearCallingIdentity();
1994 mZenModeHelper.setNotificationPolicy(policy);
1996 Binder.restoreCallingIdentity(identity);
2001 public void setImportanceFromRankerService(INotificationListener token, String key,
2002 int importance, CharSequence explanation) throws RemoteException {
2003 if (importance == IMPORTANCE_NONE) {
2004 throw new IllegalArgumentException("blocking not allowed: key=" + key);
2006 final long identity = Binder.clearCallingIdentity();
2008 synchronized (mNotificationList) {
2009 mRankerServices.checkServiceTokenLocked(token);
2010 NotificationRecord n = mNotificationsByKey.get(key);
2011 n.setImportance(importance, explanation);
2012 mRankingHandler.requestSort();
2015 Binder.restoreCallingIdentity(identity);
2020 private String disableNotificationEffects(NotificationRecord record) {
2021 if (mDisableNotificationEffects) {
2022 return "booleanState";
2024 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
2025 return "listenerHints";
2027 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
2033 private void dumpJson(PrintWriter pw, DumpFilter filter) {
2034 JSONObject dump = new JSONObject();
2036 dump.put("service", "Notification Manager");
2037 JSONArray bans = new JSONArray();
2039 ArrayMap<Integer, ArrayList<String>> packageBans = getPackageBans(filter);
2040 for (Integer userId : packageBans.keySet()) {
2041 for (String packageName : packageBans.get(userId)) {
2042 JSONObject ban = new JSONObject();
2043 ban.put("userId", userId);
2044 ban.put("packageName", packageName);
2048 } catch (NameNotFoundException e) {
2051 dump.put("bans", bans);
2052 dump.put("stats", mUsageStats.dumpJson(filter));
2053 } catch (JSONException e) {
2054 e.printStackTrace();
2059 void dumpImpl(PrintWriter pw, DumpFilter filter) {
2060 pw.print("Current Notification Manager state");
2061 if (filter.filtered) {
2062 pw.print(" (filtered to "); pw.print(filter); pw.print(")");
2066 final boolean zenOnly = filter.filtered && filter.zen;
2069 synchronized (mToastQueue) {
2070 N = mToastQueue.size();
2072 pw.println(" Toast Queue:");
2073 for (int i=0; i<N; i++) {
2074 mToastQueue.get(i).dump(pw, " ", filter);
2081 synchronized (mNotificationList) {
2083 N = mNotificationList.size();
2085 pw.println(" Notification List:");
2086 for (int i=0; i<N; i++) {
2087 final NotificationRecord nr = mNotificationList.get(i);
2088 if (filter.filtered && !filter.matches(nr.sbn)) continue;
2089 nr.dump(pw, " ", getContext(), filter.redact);
2094 if (!filter.filtered) {
2097 pw.println(" Lights List:");
2098 for (int i=0; i<N; i++) {
2104 pw.println(mLights.get(i));
2108 pw.println(" mUseAttentionLight=" + mUseAttentionLight);
2109 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled);
2110 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey);
2111 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey);
2112 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects);
2113 pw.println(" mCallState=" + callStateToString(mCallState));
2114 pw.println(" mSystemReady=" + mSystemReady);
2116 pw.println(" mArchive=" + mArchive.toString());
2117 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
2119 while (iter.hasNext()) {
2120 final StatusBarNotification sbn = iter.next();
2121 if (filter != null && !filter.matches(sbn)) continue;
2122 pw.println(" " + sbn);
2124 if (iter.hasNext()) pw.println(" ...");
2131 pw.println("\n Usage Stats:");
2132 mUsageStats.dump(pw, " ", filter);
2135 if (!filter.filtered || zenOnly) {
2136 pw.println("\n Zen Mode:");
2137 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter);
2138 mZenModeHelper.dump(pw, " ");
2140 pw.println("\n Zen Log:");
2141 ZenLog.dump(pw, " ");
2145 pw.println("\n Ranking Config:");
2146 mRankingHelper.dump(pw, " ", filter);
2148 pw.println("\n Notification listeners:");
2149 mListeners.dump(pw, filter);
2150 pw.print(" mListenerHints: "); pw.println(mListenerHints);
2151 pw.print(" mListenersDisablingEffects: (");
2152 N = mListenersDisablingEffects.size();
2153 for (int i = 0; i < N; i++) {
2154 final ManagedServiceInfo listener = mListenersDisablingEffects.valueAt(i);
2155 if (i > 0) pw.print(',');
2156 pw.print(listener.component);
2159 pw.println("\n mRankerServicePackageName: " + mRankerServicePackageName);
2160 pw.println("\n Notification ranker services:");
2161 mRankerServices.dump(pw, filter);
2163 pw.println("\n Policy access:");
2164 pw.print(" mPolicyAccess: "); pw.println(mPolicyAccess);
2166 pw.println("\n Condition providers:");
2167 mConditionProviders.dump(pw, filter);
2169 pw.println("\n Group summaries:");
2170 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
2171 NotificationRecord r = entry.getValue();
2172 pw.println(" " + entry.getKey() + " -> " + r.getKey());
2173 if (mNotificationsByKey.get(r.getKey()) != r) {
2174 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
2175 r.dump(pw, " ", getContext(), filter.redact);
2180 pw.println("\n Banned Packages:");
2181 ArrayMap<Integer, ArrayList<String>> packageBans = getPackageBans(filter);
2182 for (Integer userId : packageBans.keySet()) {
2183 for (String packageName : packageBans.get(userId)) {
2184 pw.println(" " + userId + ": " + packageName);
2187 } catch (NameNotFoundException e) {
2193 private ArrayMap<Integer, ArrayList<String>> getPackageBans(DumpFilter filter)
2194 throws NameNotFoundException {
2195 ArrayMap<Integer, ArrayList<String>> packageBans = new ArrayMap<>();
2196 ArrayList<String> packageNames = new ArrayList<>();
2197 for (UserInfo user : UserManager.get(getContext()).getUsers()) {
2198 final int userId = user.getUserHandle().getIdentifier();
2199 final PackageManager packageManager = getContext().getPackageManager();
2200 List<PackageInfo> packages = packageManager.getInstalledPackagesAsUser(0, userId);
2201 final int packageCount = packages.size();
2202 for (int p = 0; p < packageCount; p++) {
2203 final String packageName = packages.get(p).packageName;
2204 if (filter == null || filter.matches(packageName)) {
2205 final int uid = packageManager.getPackageUidAsUser(packageName, userId);
2206 if (!checkNotificationOp(packageName, uid)) {
2207 packageNames.add(packageName);
2211 if (!packageNames.isEmpty()) {
2212 packageBans.put(userId, packageNames);
2213 packageNames = new ArrayList<>();
2220 * The private API only accessible to the system process.
2222 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
2224 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
2225 String tag, int id, Notification notification, int[] idReceived, int userId) {
2226 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
2227 idReceived, userId);
2231 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
2233 checkCallerIsSystem();
2234 synchronized (mNotificationList) {
2235 int i = indexOfNotificationLocked(pkg, null, notificationId, userId);
2237 Log.d(TAG, "stripForegroundServiceFlag: Could not find notification with "
2238 + "pkg=" + pkg + " / id=" + notificationId + " / userId=" + userId);
2241 NotificationRecord r = mNotificationList.get(i);
2242 StatusBarNotification sbn = r.sbn;
2243 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
2244 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove FLAG_FOREGROUND_SERVICE,
2245 // we have to revert to the flags we received initially *and* force remove
2246 // FLAG_FOREGROUND_SERVICE.
2247 sbn.getNotification().flags =
2248 (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
2249 mRankingHelper.sort(mNotificationList);
2250 mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
2255 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
2256 final int callingPid, final String tag, final int id, final Notification notification,
2257 int[] idOut, int incomingUserId) {
2259 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
2260 + " notification=" + notification);
2262 checkCallerIsSystemOrSameApp(pkg);
2263 final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg));
2264 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
2266 final int userId = ActivityManager.handleIncomingUser(callingPid,
2267 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
2268 final UserHandle user = new UserHandle(userId);
2270 // Limit the number of notifications that any given package except the android
2271 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
2272 if (!isSystemNotification && !isNotificationFromListener) {
2273 synchronized (mNotificationList) {
2275 final int N = mNotificationList.size();
2276 for (int i=0; i<N; i++) {
2277 final NotificationRecord r = mNotificationList.get(i);
2278 if (r.sbn.getPackageName().equals(pkg) && r.sbn.getUserId() == userId) {
2279 if (r.sbn.getId() == id && TextUtils.equals(r.sbn.getTag(), tag)) {
2280 break; // Allow updating existing notification
2283 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
2284 Slog.e(TAG, "Package has already posted " + count
2285 + " notifications. Not showing more. package=" + pkg);
2293 if (pkg == null || notification == null) {
2294 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
2295 + " id=" + id + " notification=" + notification);
2299 notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN,
2300 Notification.PRIORITY_MAX);
2301 if (notification.extras != null) {
2302 // If the remote side sent us bad parcelables, they won't get the
2303 // results they want, which is their loss.
2304 notification.extras.setDefusable(true);
2307 // setup local book-keeping
2308 final StatusBarNotification n = new StatusBarNotification(
2309 pkg, opPkg, id, tag, callingUid, callingPid, 0, notification,
2311 final NotificationRecord r = new NotificationRecord(getContext(), n);
2312 mHandler.post(new EnqueueNotificationRunnable(userId, r));
2317 private class EnqueueNotificationRunnable implements Runnable {
2318 private final NotificationRecord r;
2319 private final int userId;
2321 EnqueueNotificationRunnable(int userId, NotificationRecord r) {
2322 this.userId = userId;
2329 synchronized (mNotificationList) {
2330 final StatusBarNotification n = r.sbn;
2331 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
2332 NotificationRecord old = mNotificationsByKey.get(n.getKey());
2334 // Retain ranking information from previous record
2335 r.copyRankingInformation(old);
2338 final int callingUid = n.getUid();
2339 final int callingPid = n.getInitialPid();
2340 final Notification notification = n.getNotification();
2341 final String pkg = n.getPackageName();
2342 final int id = n.getId();
2343 final String tag = n.getTag();
2344 final boolean isSystemNotification = isUidSystem(callingUid) ||
2345 ("android".equals(pkg));
2347 // Handle grouped notifications and bail out early if we
2348 // can to avoid extracting signals.
2349 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
2350 boolean ignoreNotification =
2351 removeUnusedGroupedNotificationLocked(r, old, callingUid, callingPid);
2352 if (DBG) Slog.d(TAG, "ignoreNotification is " + ignoreNotification);
2354 // This conditional is a dirty hack to limit the logging done on
2355 // behalf of the download manager without affecting other apps.
2356 if (!pkg.equals("com.android.providers.downloads")
2357 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
2358 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
2359 if (ignoreNotification) {
2360 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_IGNORED;
2361 } else if (old != null) {
2362 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
2364 EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
2365 pkg, id, tag, userId, notification.toString(),
2369 if (ignoreNotification) {
2373 mRankingHelper.extractSignals(r);
2375 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
2378 if (r.getImportance() == NotificationListenerService.Ranking.IMPORTANCE_NONE
2379 || !noteNotificationOp(pkg, callingUid) || isPackageSuspended) {
2380 if (!isSystemNotification) {
2381 if (isPackageSuspended) {
2382 Slog.e(TAG, "Suppressing notification from package due to package "
2383 + "suspended by administrator.");
2384 mUsageStats.registerSuspendedByAdmin(r);
2386 Slog.e(TAG, "Suppressing notification from package by user request.");
2387 mUsageStats.registerBlocked(r);
2393 // tell the ranker service about the notification
2394 if (mRankerServices.isEnabled()) {
2395 mRankerServices.onNotificationEnqueued(r);
2396 // TODO delay the code below here for 100ms or until there is an answer
2400 int index = indexOfNotificationLocked(n.getKey());
2402 mNotificationList.add(r);
2403 mUsageStats.registerPostedByApp(r);
2405 old = mNotificationList.get(index);
2406 mNotificationList.set(index, r);
2407 mUsageStats.registerUpdatedByApp(r, old);
2408 // Make sure we don't lose the foreground service state.
2409 notification.flags |=
2410 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
2414 mNotificationsByKey.put(n.getKey(), r);
2416 // Ensure if this is a foreground service that the proper additional
2418 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
2419 notification.flags |= Notification.FLAG_ONGOING_EVENT
2420 | Notification.FLAG_NO_CLEAR;
2423 applyZenModeLocked(r);
2424 mRankingHelper.sort(mNotificationList);
2426 if (notification.getSmallIcon() != null) {
2427 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
2428 mListeners.notifyPostedLocked(n, oldSbn);
2430 Slog.e(TAG, "Not posting notification without small icon: " + notification);
2431 if (old != null && !old.isCanceled) {
2432 mListeners.notifyRemovedLocked(n);
2434 // ATTENTION: in a future release we will bail out here
2435 // so that we do not play sounds, show lights, etc. for invalid
2437 Slog.e(TAG, "WARNING: In a future release this will crash the app: "
2438 + n.getPackageName());
2441 buzzBeepBlinkLocked(r);
2447 * Ensures that grouped notification receive their special treatment.
2449 * <p>Cancels group children if the new notification causes a group to lose
2452 * <p>Updates mSummaryByGroupKey.</p>
2454 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
2455 int callingUid, int callingPid) {
2456 StatusBarNotification sbn = r.sbn;
2457 Notification n = sbn.getNotification();
2458 String group = sbn.getGroupKey();
2459 boolean isSummary = n.isGroupSummary();
2461 Notification oldN = old != null ? old.sbn.getNotification() : null;
2462 String oldGroup = old != null ? old.sbn.getGroupKey() : null;
2463 boolean oldIsSummary = old != null && oldN.isGroupSummary();
2466 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
2467 if (removedSummary != old) {
2469 removedSummary != null ? removedSummary.getKey() : "<null>";
2470 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
2471 ", removed=" + removedKey);
2475 mSummaryByGroupKey.put(group, r);
2478 // Clear out group children of the old notification if the update
2479 // causes the group summary to go away. This happens when the old
2480 // notification was a summary and the new one isn't, or when the old
2481 // notification was a summary and its group key changed.
2482 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
2483 cancelGroupChildrenLocked(old, callingUid, callingPid, null,
2484 REASON_GROUP_SUMMARY_CANCELED);
2489 * Performs group notification optimizations if SysUI is the only active
2490 * notification listener and returns whether the given notification should
2493 * <p>Returns true if the given notification is a child of a group with a
2494 * summary, which means that SysUI will never show it, and hence the new
2495 * notification can be safely ignored. Also cancels any previous instance
2496 * of the ignored notification.</p>
2498 * <p>For summaries, cancels all children of that group, as SysUI will
2499 * never show them anymore.</p>
2501 * @return true if the given notification can be ignored as an optimization
2503 private boolean removeUnusedGroupedNotificationLocked(NotificationRecord r,
2504 NotificationRecord old, int callingUid, int callingPid) {
2505 if (!ENABLE_CHILD_NOTIFICATIONS) {
2506 // No optimizations are possible if listeners want groups.
2507 if (mListeners.notificationGroupsDesired()) {
2511 StatusBarNotification sbn = r.sbn;
2512 String group = sbn.getGroupKey();
2513 boolean isSummary = sbn.getNotification().isGroupSummary();
2514 boolean isChild = sbn.getNotification().isGroupChild();
2516 NotificationRecord summary = mSummaryByGroupKey.get(group);
2517 if (isChild && summary != null) {
2518 // Child with an active summary -> ignore
2520 Slog.d(TAG, "Ignoring group child " + sbn.getKey() + " due to existing summary "
2521 + summary.getKey());
2523 // Make sure we don't leave an old version of the notification around.
2526 Slog.d(TAG, "Canceling old version of ignored group child " + sbn.getKey());
2528 cancelNotificationLocked(old, false, REASON_GROUP_OPTIMIZATION);
2531 } else if (isSummary) {
2532 // Summary -> cancel children
2533 cancelGroupChildrenLocked(r, callingUid, callingPid, null,
2534 REASON_GROUP_OPTIMIZATION);
2540 private void buzzBeepBlinkLocked(NotificationRecord record) {
2541 boolean buzz = false;
2542 boolean beep = false;
2543 boolean blink = false;
2545 final Notification notification = record.sbn.getNotification();
2547 // Should this notification make noise, vibe, or use the LED?
2548 final boolean aboveThreshold = record.getImportance() >= IMPORTANCE_DEFAULT;
2549 final boolean canInterrupt = aboveThreshold && !record.isIntercepted();
2550 if (DBG || record.isIntercepted())
2552 "pkg=" + record.sbn.getPackageName() + " canInterrupt=" + canInterrupt +
2553 " intercept=" + record.isIntercepted()
2556 final int currentUser;
2557 final long token = Binder.clearCallingIdentity();
2559 currentUser = ActivityManager.getCurrentUser();
2561 Binder.restoreCallingIdentity(token);
2564 // If we're not supposed to beep, vibrate, etc. then don't.
2565 final String disableEffects = disableNotificationEffects(record);
2566 if (disableEffects != null) {
2567 ZenLog.traceDisableEffects(record, disableEffects);
2569 if (disableEffects == null
2570 && (!(record.isUpdate
2571 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
2572 && (record.getUserId() == UserHandle.USER_ALL ||
2573 record.getUserId() == currentUser ||
2574 mUserProfiles.isCurrentProfile(record.getUserId()))
2577 && mAudioManager != null) {
2578 if (DBG) Slog.v(TAG, "Interrupting!");
2580 sendAccessibilityEvent(notification, record.sbn.getPackageName());
2584 // should we use the default notification sound? (indicated either by
2585 // DEFAULT_SOUND or because notification.sound is pointing at
2586 // Settings.System.NOTIFICATION_SOUND)
2587 final boolean useDefaultSound =
2588 (notification.defaults & Notification.DEFAULT_SOUND) != 0 ||
2589 Settings.System.DEFAULT_NOTIFICATION_URI
2590 .equals(notification.sound);
2592 Uri soundUri = null;
2593 boolean hasValidSound = false;
2595 if (useDefaultSound) {
2596 soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
2598 // check to see if the default notification sound is silent
2599 ContentResolver resolver = getContext().getContentResolver();
2600 hasValidSound = Settings.System.getString(resolver,
2601 Settings.System.NOTIFICATION_SOUND) != null;
2602 } else if (notification.sound != null) {
2603 soundUri = notification.sound;
2604 hasValidSound = (soundUri != null);
2607 if (hasValidSound) {
2609 (notification.flags & Notification.FLAG_INSISTENT) != 0;
2610 AudioAttributes audioAttributes = audioAttributesForNotification(notification);
2611 mSoundNotificationKey = record.getKey();
2612 // do not play notifications if stream volume is 0 (typically because
2613 // ringer mode is silent) or if there is a user of exclusive audio focus
2614 if ((mAudioManager.getStreamVolume(
2615 AudioAttributes.toLegacyStreamType(audioAttributes)) != 0)
2616 && !mAudioManager.isAudioFocusExclusive()) {
2617 final long identity = Binder.clearCallingIdentity();
2619 final IRingtonePlayer player =
2620 mAudioManager.getRingtonePlayer();
2621 if (player != null) {
2622 if (DBG) Slog.v(TAG, "Playing sound " + soundUri
2623 + " with attributes " + audioAttributes);
2624 player.playAsync(soundUri, record.sbn.getUser(), looping,
2628 } catch (RemoteException e) {
2630 Binder.restoreCallingIdentity(identity);
2636 // Does the notification want to specify its own vibration?
2637 final boolean hasCustomVibrate = notification.vibrate != null;
2639 // new in 4.2: if there was supposed to be a sound and we're in vibrate
2640 // mode, and no other vibration is specified, we fall back to vibration
2641 final boolean convertSoundToVibration =
2644 && (mAudioManager.getRingerModeInternal()
2645 == AudioManager.RINGER_MODE_VIBRATE);
2647 // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
2648 final boolean useDefaultVibrate =
2649 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
2651 if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate)
2652 && !(mAudioManager.getRingerModeInternal()
2653 == AudioManager.RINGER_MODE_SILENT)) {
2654 mVibrateNotificationKey = record.getKey();
2656 if (useDefaultVibrate || convertSoundToVibration) {
2657 // Escalate privileges so we can use the vibrator even if the
2658 // notifying app does not have the VIBRATE permission.
2659 long identity = Binder.clearCallingIdentity();
2661 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
2662 useDefaultVibrate ? mDefaultVibrationPattern
2663 : mFallbackVibrationPattern,
2664 ((notification.flags & Notification.FLAG_INSISTENT) != 0)
2665 ? 0: -1, audioAttributesForNotification(notification));
2668 Binder.restoreCallingIdentity(identity);
2670 } else if (notification.vibrate.length > 1) {
2671 // If you want your own vibration pattern, you need the VIBRATE
2673 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
2674 notification.vibrate,
2675 ((notification.flags & Notification.FLAG_INSISTENT) != 0)
2676 ? 0: -1, audioAttributesForNotification(notification));
2683 // release the light
2684 boolean wasShowLights = mLights.remove(record.getKey());
2685 if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold
2686 && ((record.getSuppressedVisualEffects()
2687 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
2688 mLights.add(record.getKey());
2689 updateLightsLocked();
2690 if (mUseAttentionLight) {
2691 mAttentionLight.pulse();
2694 } else if (wasShowLights) {
2695 updateLightsLocked();
2697 if (buzz || beep || blink) {
2698 if (((record.getSuppressedVisualEffects()
2699 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) != 0)) {
2700 if (DBG) Slog.v(TAG, "Suppressed SystemUI from triggering screen on");
2702 EventLogTags.writeNotificationAlert(record.getKey(),
2703 buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
2704 mHandler.post(mBuzzBeepBlinked);
2709 private static AudioAttributes audioAttributesForNotification(Notification n) {
2710 if (n.audioAttributes != null
2711 && !Notification.AUDIO_ATTRIBUTES_DEFAULT.equals(n.audioAttributes)) {
2712 // the audio attributes are set and different from the default, use them
2713 return n.audioAttributes;
2714 } else if (n.audioStreamType >= 0 && n.audioStreamType < AudioSystem.getNumStreamTypes()) {
2715 // the stream type is valid, use it
2716 return new AudioAttributes.Builder()
2717 .setInternalLegacyStreamType(n.audioStreamType)
2719 } else if (n.audioStreamType == AudioSystem.STREAM_DEFAULT) {
2720 return Notification.AUDIO_ATTRIBUTES_DEFAULT;
2722 Log.w(TAG, String.format("Invalid stream type: %d", n.audioStreamType));
2723 return Notification.AUDIO_ATTRIBUTES_DEFAULT;
2727 void showNextToastLocked() {
2728 ToastRecord record = mToastQueue.get(0);
2729 while (record != null) {
2730 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
2732 record.callback.show();
2733 scheduleTimeoutLocked(record);
2735 } catch (RemoteException e) {
2736 Slog.w(TAG, "Object died trying to show notification " + record.callback
2737 + " in package " + record.pkg);
2738 // remove it from the list and let the process die
2739 int index = mToastQueue.indexOf(record);
2741 mToastQueue.remove(index);
2743 keepProcessAliveLocked(record.pid);
2744 if (mToastQueue.size() > 0) {
2745 record = mToastQueue.get(0);
2753 void cancelToastLocked(int index) {
2754 ToastRecord record = mToastQueue.get(index);
2756 record.callback.hide();
2757 } catch (RemoteException e) {
2758 Slog.w(TAG, "Object died trying to hide notification " + record.callback
2759 + " in package " + record.pkg);
2760 // don't worry about this, we're about to remove it from
2763 mToastQueue.remove(index);
2764 keepProcessAliveLocked(record.pid);
2765 if (mToastQueue.size() > 0) {
2766 // Show the next one. If the callback fails, this will remove
2767 // it from the list, so don't assume that the list hasn't changed
2768 // after this point.
2769 showNextToastLocked();
2773 private void scheduleTimeoutLocked(ToastRecord r)
2775 mHandler.removeCallbacksAndMessages(r);
2776 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
2777 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
2778 mHandler.sendMessageDelayed(m, delay);
2781 private void handleTimeout(ToastRecord record)
2783 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
2784 synchronized (mToastQueue) {
2785 int index = indexOfToastLocked(record.pkg, record.callback);
2787 cancelToastLocked(index);
2792 // lock on mToastQueue
2793 int indexOfToastLocked(String pkg, ITransientNotification callback)
2795 IBinder cbak = callback.asBinder();
2796 ArrayList<ToastRecord> list = mToastQueue;
2797 int len = list.size();
2798 for (int i=0; i<len; i++) {
2799 ToastRecord r = list.get(i);
2800 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
2807 // lock on mToastQueue
2808 void keepProcessAliveLocked(int pid)
2810 int toastCount = 0; // toasts from this pid
2811 ArrayList<ToastRecord> list = mToastQueue;
2812 int N = list.size();
2813 for (int i=0; i<N; i++) {
2814 ToastRecord r = list.get(i);
2820 mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
2821 } catch (RemoteException e) {
2822 // Shouldn't happen.
2826 private void handleRankingReconsideration(Message message) {
2827 if (!(message.obj instanceof RankingReconsideration)) return;
2828 RankingReconsideration recon = (RankingReconsideration) message.obj;
2831 synchronized (mNotificationList) {
2832 final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
2833 if (record == null) {
2836 int indexBefore = findNotificationRecordIndexLocked(record);
2837 boolean interceptBefore = record.isIntercepted();
2838 int visibilityBefore = record.getPackageVisibilityOverride();
2839 recon.applyChangesLocked(record);
2840 applyZenModeLocked(record);
2841 mRankingHelper.sort(mNotificationList);
2842 int indexAfter = findNotificationRecordIndexLocked(record);
2843 boolean interceptAfter = record.isIntercepted();
2844 int visibilityAfter = record.getPackageVisibilityOverride();
2845 changed = indexBefore != indexAfter || interceptBefore != interceptAfter
2846 || visibilityBefore != visibilityAfter;
2847 if (interceptBefore && !interceptAfter) {
2848 buzzBeepBlinkLocked(record);
2852 scheduleSendRankingUpdate();
2856 private void handleRankingSort() {
2857 synchronized (mNotificationList) {
2858 final int N = mNotificationList.size();
2859 ArrayList<String> orderBefore = new ArrayList<String>(N);
2860 int[] visibilities = new int[N];
2861 int [] importances = new int[N];
2862 for (int i = 0; i < N; i++) {
2863 final NotificationRecord r = mNotificationList.get(i);
2864 orderBefore.add(r.getKey());
2865 visibilities[i] = r.getPackageVisibilityOverride();
2866 importances[i] = r.getImportance();
2867 mRankingHelper.extractSignals(r);
2869 mRankingHelper.sort(mNotificationList);
2870 for (int i = 0; i < N; i++) {
2871 final NotificationRecord r = mNotificationList.get(i);
2872 if (!orderBefore.get(i).equals(r.getKey())
2873 || visibilities[i] != r.getPackageVisibilityOverride()
2874 || importances[i] != r.getImportance()) {
2875 scheduleSendRankingUpdate();
2882 // let zen mode evaluate this record
2883 private void applyZenModeLocked(NotificationRecord record) {
2884 record.setIntercepted(mZenModeHelper.shouldIntercept(record));
2885 if (record.isIntercepted()) {
2886 int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
2887 ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
2888 | (mZenModeHelper.shouldSuppressWhenScreenOn()
2889 ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
2890 record.setSuppressedVisualEffects(suppressed);
2894 // lock on mNotificationList
2895 private int findNotificationRecordIndexLocked(NotificationRecord target) {
2896 return mRankingHelper.indexOf(mNotificationList, target);
2899 private void scheduleSendRankingUpdate() {
2900 mHandler.removeMessages(MESSAGE_SEND_RANKING_UPDATE);
2901 Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE);
2902 mHandler.sendMessage(m);
2905 private void handleSendRankingUpdate() {
2906 synchronized (mNotificationList) {
2907 mListeners.notifyRankingUpdateLocked();
2911 private void scheduleListenerHintsChanged(int state) {
2912 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
2913 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
2916 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
2917 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
2918 mHandler.obtainMessage(
2919 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
2920 listenerInterruptionFilter,
2924 private void handleListenerHintsChanged(int hints) {
2925 synchronized (mNotificationList) {
2926 mListeners.notifyListenerHintsChangedLocked(hints);
2930 private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
2931 synchronized (mNotificationList) {
2932 mListeners.notifyInterruptionFilterChanged(interruptionFilter);
2936 private final class WorkerHandler extends Handler
2939 public void handleMessage(Message msg)
2943 case MESSAGE_TIMEOUT:
2944 handleTimeout((ToastRecord)msg.obj);
2946 case MESSAGE_SAVE_POLICY_FILE:
2947 handleSavePolicyFile();
2949 case MESSAGE_SEND_RANKING_UPDATE:
2950 handleSendRankingUpdate();
2952 case MESSAGE_LISTENER_HINTS_CHANGED:
2953 handleListenerHintsChanged(msg.arg1);
2955 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
2956 handleListenerInterruptionFilterChanged(msg.arg1);
2963 private final class RankingHandlerWorker extends Handler implements RankingHandler
2965 public RankingHandlerWorker(Looper looper) {
2970 public void handleMessage(Message msg) {
2972 case MESSAGE_RECONSIDER_RANKING:
2973 handleRankingReconsideration(msg);
2975 case MESSAGE_RANKING_SORT:
2976 handleRankingSort();
2981 public void requestSort() {
2982 removeMessages(MESSAGE_RANKING_SORT);
2983 sendEmptyMessage(MESSAGE_RANKING_SORT);
2986 public void requestReconsideration(RankingReconsideration recon) {
2987 Message m = Message.obtain(this,
2988 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
2989 long delay = recon.getDelay(TimeUnit.MILLISECONDS);
2990 sendMessageDelayed(m, delay);
2995 // ============================================================================
2996 static int clamp(int x, int low, int high) {
2997 return (x < low) ? low : ((x > high) ? high : x);
3000 void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
3001 AccessibilityManager manager = AccessibilityManager.getInstance(getContext());
3002 if (!manager.isEnabled()) {
3006 AccessibilityEvent event =
3007 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
3008 event.setPackageName(packageName);
3009 event.setClassName(Notification.class.getName());
3010 event.setParcelableData(notification);
3011 CharSequence tickerText = notification.tickerText;
3012 if (!TextUtils.isEmpty(tickerText)) {
3013 event.getText().add(tickerText);
3016 manager.sendAccessibilityEvent(event);
3019 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) {
3022 if (r.getNotification().deleteIntent != null) {
3024 r.getNotification().deleteIntent.send();
3025 } catch (PendingIntent.CanceledException ex) {
3026 // do nothing - there's no relevant way to recover, and
3027 // no reason to let this propagate
3028 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
3034 if (r.getNotification().getSmallIcon() != null) {
3035 r.isCanceled = true;
3036 mListeners.notifyRemovedLocked(r.sbn);
3039 final String canceledKey = r.getKey();
3042 if (canceledKey.equals(mSoundNotificationKey)) {
3043 mSoundNotificationKey = null;
3044 final long identity = Binder.clearCallingIdentity();
3046 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
3047 if (player != null) {
3050 } catch (RemoteException e) {
3052 Binder.restoreCallingIdentity(identity);
3057 if (canceledKey.equals(mVibrateNotificationKey)) {
3058 mVibrateNotificationKey = null;
3059 long identity = Binder.clearCallingIdentity();
3064 Binder.restoreCallingIdentity(identity);
3069 mLights.remove(canceledKey);
3071 // Record usage stats
3073 case REASON_DELEGATE_CANCEL:
3074 case REASON_DELEGATE_CANCEL_ALL:
3075 case REASON_LISTENER_CANCEL:
3076 case REASON_LISTENER_CANCEL_ALL:
3077 mUsageStats.registerDismissedByUser(r);
3079 case REASON_APP_CANCEL:
3080 case REASON_APP_CANCEL_ALL:
3081 mUsageStats.registerRemovedByApp(r);
3085 mNotificationsByKey.remove(r.sbn.getKey());
3086 String groupKey = r.getGroupKey();
3087 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
3088 if (groupSummary != null && groupSummary.getKey().equals(r.getKey())) {
3089 mSummaryByGroupKey.remove(groupKey);
3092 // Save it for users of getHistoricalNotifications()
3093 mArchive.record(r.sbn);
3095 final long now = System.currentTimeMillis();
3096 EventLogTags.writeNotificationCanceled(canceledKey, reason,
3097 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
3101 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
3102 * and none of the {@code mustNotHaveFlags}.
3104 void cancelNotification(final int callingUid, final int callingPid,
3105 final String pkg, final String tag, final int id,
3106 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
3107 final int userId, final int reason, final ManagedServiceInfo listener) {
3108 // In enqueueNotificationInternal notifications are added by scheduling the
3109 // work on the worker handler. Hence, we also schedule the cancel on this
3110 // handler to avoid a scenario where an add notification call followed by a
3111 // remove notification call ends up in not removing the notification.
3112 mHandler.post(new Runnable() {
3115 String listenerName = listener == null ? null : listener.component.toShortString();
3116 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
3117 userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
3119 synchronized (mNotificationList) {
3120 int index = indexOfNotificationLocked(pkg, tag, id, userId);
3122 NotificationRecord r = mNotificationList.get(index);
3124 // Ideally we'd do this in the caller of this method. However, that would
3125 // require the caller to also find the notification.
3126 if (reason == REASON_DELEGATE_CLICK) {
3127 mUsageStats.registerClickedByUser(r);
3130 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
3133 if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
3137 mNotificationList.remove(index);
3139 cancelNotificationLocked(r, sendDelete, reason);
3140 cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
3141 REASON_GROUP_SUMMARY_CANCELED);
3142 updateLightsLocked();
3150 * Determine whether the userId applies to the notification in question, either because
3151 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
3153 private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
3155 // looking for USER_ALL notifications? match everything
3156 userId == UserHandle.USER_ALL
3157 // a notification sent to USER_ALL matches any query
3158 || r.getUserId() == UserHandle.USER_ALL
3159 // an exact user match
3160 || r.getUserId() == userId;
3164 * Determine whether the userId applies to the notification in question, either because
3165 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
3166 * because it matches one of the users profiles.
3168 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
3169 return notificationMatchesUserId(r, userId)
3170 || mUserProfiles.isCurrentProfile(r.getUserId());
3174 * Cancels all notifications from a given package that have all of the
3175 * {@code mustHaveFlags}.
3177 boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags,
3178 int mustNotHaveFlags, boolean doit, int userId, int reason,
3179 ManagedServiceInfo listener) {
3180 String listenerName = listener == null ? null : listener.component.toShortString();
3181 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
3182 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
3185 synchronized (mNotificationList) {
3186 final int N = mNotificationList.size();
3187 ArrayList<NotificationRecord> canceledNotifications = null;
3188 for (int i = N-1; i >= 0; --i) {
3189 NotificationRecord r = mNotificationList.get(i);
3190 if (!notificationMatchesUserId(r, userId)) {
3193 // Don't remove notifications to all, if there's no package name specified
3194 if (r.getUserId() == UserHandle.USER_ALL && pkg == null) {
3197 if ((r.getFlags() & mustHaveFlags) != mustHaveFlags) {
3200 if ((r.getFlags() & mustNotHaveFlags) != 0) {
3203 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
3206 if (canceledNotifications == null) {
3207 canceledNotifications = new ArrayList<>();
3209 canceledNotifications.add(r);
3213 mNotificationList.remove(i);
3214 cancelNotificationLocked(r, false, reason);
3216 if (doit && canceledNotifications != null) {
3217 final int M = canceledNotifications.size();
3218 for (int i = 0; i < M; i++) {
3219 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
3220 listenerName, REASON_GROUP_SUMMARY_CANCELED);
3223 if (canceledNotifications != null) {
3224 updateLightsLocked();
3226 return canceledNotifications != null;
3230 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
3231 ManagedServiceInfo listener, boolean includeCurrentProfiles) {
3232 String listenerName = listener == null ? null : listener.component.toShortString();
3233 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
3234 null, userId, 0, 0, reason, listenerName);
3236 ArrayList<NotificationRecord> canceledNotifications = null;
3237 final int N = mNotificationList.size();
3238 for (int i=N-1; i>=0; i--) {
3239 NotificationRecord r = mNotificationList.get(i);
3240 if (includeCurrentProfiles) {
3241 if (!notificationMatchesCurrentProfiles(r, userId)) {
3245 if (!notificationMatchesUserId(r, userId)) {
3250 if ((r.getFlags() & (Notification.FLAG_ONGOING_EVENT
3251 | Notification.FLAG_NO_CLEAR)) == 0) {
3252 mNotificationList.remove(i);
3253 cancelNotificationLocked(r, true, reason);
3254 // Make a note so we can cancel children later.
3255 if (canceledNotifications == null) {
3256 canceledNotifications = new ArrayList<>();
3258 canceledNotifications.add(r);
3261 int M = canceledNotifications != null ? canceledNotifications.size() : 0;
3262 for (int i = 0; i < M; i++) {
3263 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
3264 listenerName, REASON_GROUP_SUMMARY_CANCELED);
3266 updateLightsLocked();
3269 // Warning: The caller is responsible for invoking updateLightsLocked().
3270 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
3271 String listenerName, int reason) {
3272 Notification n = r.getNotification();
3273 if (!n.isGroupSummary()) {
3277 String pkg = r.sbn.getPackageName();
3278 int userId = r.getUserId();
3281 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
3285 final int N = mNotificationList.size();
3286 for (int i = N - 1; i >= 0; i--) {
3287 NotificationRecord childR = mNotificationList.get(i);
3288 StatusBarNotification childSbn = childR.sbn;
3289 if (childR.getNotification().isGroupChild() &&
3290 childR.getGroupKey().equals(r.getGroupKey())) {
3291 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
3292 childSbn.getTag(), userId, 0, 0, reason, listenerName);
3293 mNotificationList.remove(i);
3294 cancelNotificationLocked(childR, false, reason);
3299 // lock on mNotificationList
3300 void updateLightsLocked()
3302 // handle notification lights
3303 NotificationRecord ledNotification = null;
3304 while (ledNotification == null && !mLights.isEmpty()) {
3305 final String owner = mLights.get(mLights.size() - 1);
3306 ledNotification = mNotificationsByKey.get(owner);
3307 if (ledNotification == null) {
3308 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
3309 mLights.remove(owner);
3313 // Don't flash while we are in a call or screen is on
3314 if (ledNotification == null || mInCall || mScreenOn) {
3315 mNotificationLight.turnOff();
3316 if (mStatusBar != null) {
3317 mStatusBar.notificationLightOff();
3320 final Notification ledno = ledNotification.sbn.getNotification();
3321 int ledARGB = ledno.ledARGB;
3322 int ledOnMS = ledno.ledOnMS;
3323 int ledOffMS = ledno.ledOffMS;
3324 if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0) {
3325 ledARGB = mDefaultNotificationColor;
3326 ledOnMS = mDefaultNotificationLedOn;
3327 ledOffMS = mDefaultNotificationLedOff;
3329 if (mNotificationPulseEnabled) {
3331 mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED,
3334 if (mStatusBar != null) {
3335 // let SystemUI make an independent decision
3336 mStatusBar.notificationLightPulse(ledARGB, ledOnMS, ledOffMS);
3341 // lock on mNotificationList
3342 int indexOfNotificationLocked(String pkg, String tag, int id, int userId)
3344 ArrayList<NotificationRecord> list = mNotificationList;
3345 final int len = list.size();
3346 for (int i=0; i<len; i++) {
3347 NotificationRecord r = list.get(i);
3348 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
3349 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
3356 // lock on mNotificationList
3357 int indexOfNotificationLocked(String key) {
3358 final int N = mNotificationList.size();
3359 for (int i = 0; i < N; i++) {
3360 if (key.equals(mNotificationList.get(i).getKey())) {
3367 private void updateNotificationPulse() {
3368 synchronized (mNotificationList) {
3369 updateLightsLocked();
3373 private static boolean isUidSystem(int uid) {
3374 final int appid = UserHandle.getAppId(uid);
3375 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
3378 private static boolean isCallerSystem() {
3379 return isUidSystem(Binder.getCallingUid());
3382 private static void checkCallerIsSystem() {
3383 if (isCallerSystem()) {
3386 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
3389 private static void checkCallerIsSystemOrSameApp(String pkg) {
3390 if (isCallerSystem()) {
3393 final int uid = Binder.getCallingUid();
3395 ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
3396 pkg, 0, UserHandle.getCallingUserId());
3398 throw new SecurityException("Unknown package " + pkg);
3400 if (!UserHandle.isSameApp(ai.uid, uid)) {
3401 throw new SecurityException("Calling uid " + uid + " gave package"
3402 + pkg + " which is owned by uid " + ai.uid);
3404 } catch (RemoteException re) {
3405 throw new SecurityException("Unknown package " + pkg + "\n" + re);
3409 private static String callStateToString(int state) {
3411 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
3412 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
3413 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
3414 default: return "CALL_STATE_UNKNOWN_" + state;
3418 private void listenForCallState() {
3419 TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
3421 public void onCallStateChanged(int state, String incomingNumber) {
3422 if (mCallState == state) return;
3423 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
3426 }, PhoneStateListener.LISTEN_CALL_STATE);
3430 * Generates a NotificationRankingUpdate from 'sbns', considering only
3431 * notifications visible to the given listener.
3433 * <p>Caller must hold a lock on mNotificationList.</p>
3435 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
3436 final int N = mNotificationList.size();
3437 ArrayList<String> keys = new ArrayList<String>(N);
3438 ArrayList<String> interceptedKeys = new ArrayList<String>(N);
3439 ArrayList<Integer> importance = new ArrayList<>(N);
3440 Bundle visibilityOverrides = new Bundle();
3441 Bundle suppressedVisualEffects = new Bundle();
3442 Bundle explanation = new Bundle();
3443 for (int i = 0; i < N; i++) {
3444 NotificationRecord record = mNotificationList.get(i);
3445 if (!isVisibleToListener(record.sbn, info)) {
3448 final String key = record.sbn.getKey();
3450 importance.add(record.getImportance());
3451 if (record.getImportanceExplanation() != null) {
3452 explanation.putCharSequence(key, record.getImportanceExplanation());
3454 if (record.isIntercepted()) {
3455 interceptedKeys.add(key);
3458 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
3459 if (record.getPackageVisibilityOverride()
3460 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
3461 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
3464 final int M = keys.size();
3465 String[] keysAr = keys.toArray(new String[M]);
3466 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
3467 int[] importanceAr = new int[M];
3468 for (int i = 0; i < M; i++) {
3469 importanceAr[i] = importance.get(i);
3471 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
3472 suppressedVisualEffects, importanceAr, explanation);
3475 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
3476 if (!listener.enabledAndUserMatches(sbn.getUserId())) {
3479 // TODO: remove this for older listeners.
3483 private boolean isPackageSuspendedForUser(String pkg, int uid) {
3484 int userId = UserHandle.getUserId(uid);
3486 return AppGlobals.getPackageManager().isPackageSuspendedForUser(pkg, userId);
3487 } catch (RemoteException re) {
3488 throw new SecurityException("Could not talk to package manager service");
3492 private class TrimCache {
3493 StatusBarNotification heavy;
3494 StatusBarNotification sbnClone;
3495 StatusBarNotification sbnCloneLight;
3497 TrimCache(StatusBarNotification sbn) {
3501 StatusBarNotification ForListener(ManagedServiceInfo info) {
3502 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
3503 if (sbnCloneLight == null) {
3504 sbnCloneLight = heavy.cloneLight();
3506 return sbnCloneLight;
3508 if (sbnClone == null) {
3509 sbnClone = heavy.clone();
3516 public class NotificationRankers extends ManagedServices {
3518 public NotificationRankers() {
3519 super(getContext(), mHandler, mNotificationList, mUserProfiles);
3523 protected Config getConfig() {
3524 Config c = new Config();
3525 c.caption = "notification ranker service";
3526 c.serviceInterface = NotificationRankerService.SERVICE_INTERFACE;
3527 c.secureSettingName = null;
3528 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_RANKER_SERVICE;
3529 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
3530 c.clientLabel = R.string.notification_ranker_binding_label;
3535 protected IInterface asInterface(IBinder binder) {
3536 return INotificationListener.Stub.asInterface(binder);
3540 protected boolean checkType(IInterface service) {
3541 return service instanceof INotificationListener;
3545 protected void onServiceAdded(ManagedServiceInfo info) {
3546 mListeners.registerGuestService(info);
3550 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
3551 mListeners.unregisterService(removed.service, removed.userid);
3554 public void onNotificationEnqueued(final NotificationRecord r) {
3555 final StatusBarNotification sbn = r.sbn;
3556 TrimCache trimCache = new TrimCache(sbn);
3558 // mServices is the list inside ManagedServices of all the rankers,
3559 // There should be only one, but it's a list, so while we enforce
3560 // singularity elsewhere, we keep it general here, to avoid surprises.
3561 for (final ManagedServiceInfo info : NotificationRankers.this.mServices) {
3562 boolean sbnVisible = isVisibleToListener(sbn, info);
3567 final int importance = r.getImportance();
3568 final boolean fromUser = r.isImportanceFromUser();
3569 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
3570 mHandler.post(new Runnable() {
3573 notifyEnqueued(info, sbnToPost, importance, fromUser);
3579 private void notifyEnqueued(final ManagedServiceInfo info,
3580 final StatusBarNotification sbn, int importance, boolean fromUser) {
3581 final INotificationListener ranker = (INotificationListener) info.service;
3582 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
3584 ranker.onNotificationEnqueued(sbnHolder, importance, fromUser);
3585 } catch (RemoteException ex) {
3586 Log.e(TAG, "unable to notify ranker (enqueued): " + ranker, ex);
3590 public boolean isEnabled() {
3591 return !mServices.isEmpty();
3595 public void onUserSwitched(int user) {
3596 for (ManagedServiceInfo info : mServices) {
3597 unregisterService(info.service, info.userid);
3603 public void onPackagesChanged(boolean queryReplace, String[] pkgList) {
3604 if (DEBUG) Slog.d(TAG, "onPackagesChanged queryReplace=" + queryReplace
3605 + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList)));
3607 if (pkgList != null && (pkgList.length > 0)) {
3608 for (String pkgName : pkgList) {
3609 if (mRankerServicePackageName.equals(pkgName)) {
3616 protected void registerRanker() {
3617 // Find the updatable ranker and register it.
3618 Set<ComponentName> rankerComponents = queryPackageForServices(
3619 mRankerServicePackageName, UserHandle.USER_SYSTEM, null);
3620 Iterator<ComponentName> iterator = rankerComponents.iterator();
3621 if (iterator.hasNext()) {
3622 ComponentName rankerComponent = iterator.next();
3623 if (iterator.hasNext()) {
3624 Slog.e(TAG, "found multiple ranker services:" + rankerComponents);
3626 registerSystemService(rankerComponent, UserHandle.USER_SYSTEM);
3629 Slog.w(TAG, "could not start ranker service: none found");
3634 public class NotificationListeners extends ManagedServices {
3636 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
3637 private boolean mNotificationGroupsDesired;
3639 public NotificationListeners() {
3640 super(getContext(), mHandler, mNotificationList, mUserProfiles);
3644 protected Config getConfig() {
3645 Config c = new Config();
3646 c.caption = "notification listener";
3647 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
3648 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
3649 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
3650 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
3651 c.clientLabel = R.string.notification_listener_binding_label;
3656 protected IInterface asInterface(IBinder binder) {
3657 return INotificationListener.Stub.asInterface(binder);
3661 protected boolean checkType(IInterface service) {
3662 return service instanceof INotificationListener;
3666 public void onServiceAdded(ManagedServiceInfo info) {
3667 final INotificationListener listener = (INotificationListener) info.service;
3668 final NotificationRankingUpdate update;
3669 synchronized (mNotificationList) {
3670 updateNotificationGroupsDesiredLocked();
3671 update = makeRankingUpdateLocked(info);
3674 listener.onListenerConnected(update);
3675 } catch (RemoteException e) {
3681 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
3682 if (mListenersDisablingEffects.remove(removed)) {
3683 updateListenerHintsLocked();
3684 updateEffectsSuppressorLocked();
3686 mLightTrimListeners.remove(removed);
3687 updateNotificationGroupsDesiredLocked();
3690 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
3691 if (trim == TRIM_LIGHT) {
3692 mLightTrimListeners.add(info);
3694 mLightTrimListeners.remove(info);
3698 public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
3699 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
3703 * asynchronously notify all listeners about a new notification
3706 * Also takes care of removing a notification that has been visible to a listener before,
3707 * but isn't anymore.
3709 public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
3710 // Lazily initialized snapshots of the notification.
3711 TrimCache trimCache = new TrimCache(sbn);
3713 for (final ManagedServiceInfo info : mServices) {
3714 boolean sbnVisible = isVisibleToListener(sbn, info);
3715 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
3716 // This notification hasn't been and still isn't visible -> ignore.
3717 if (!oldSbnVisible && !sbnVisible) {
3720 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
3722 // This notification became invisible -> remove the old one.
3723 if (oldSbnVisible && !sbnVisible) {
3724 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
3725 mHandler.post(new Runnable() {
3728 notifyRemoved(info, oldSbnLightClone, update);
3734 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
3735 mHandler.post(new Runnable() {
3738 notifyPosted(info, sbnToPost, update);
3745 * asynchronously notify all listeners about a removed notification
3747 public void notifyRemovedLocked(StatusBarNotification sbn) {
3748 // make a copy in case changes are made to the underlying Notification object
3749 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
3751 final StatusBarNotification sbnLight = sbn.cloneLight();
3752 for (final ManagedServiceInfo info : mServices) {
3753 if (!isVisibleToListener(sbn, info)) {
3756 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
3757 mHandler.post(new Runnable() {
3760 notifyRemoved(info, sbnLight, update);
3767 * asynchronously notify all listeners about a reordering of notifications
3769 public void notifyRankingUpdateLocked() {
3770 for (final ManagedServiceInfo serviceInfo : mServices) {
3771 if (!serviceInfo.isEnabledForCurrentProfiles()) {
3774 final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
3775 mHandler.post(new Runnable() {
3778 notifyRankingUpdate(serviceInfo, update);
3784 public void notifyListenerHintsChangedLocked(final int hints) {
3785 for (final ManagedServiceInfo serviceInfo : mServices) {
3786 if (!serviceInfo.isEnabledForCurrentProfiles()) {
3789 mHandler.post(new Runnable() {
3792 notifyListenerHintsChanged(serviceInfo, hints);
3798 public void notifyInterruptionFilterChanged(final int interruptionFilter) {
3799 for (final ManagedServiceInfo serviceInfo : mServices) {
3800 if (!serviceInfo.isEnabledForCurrentProfiles()) {
3803 mHandler.post(new Runnable() {
3806 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
3812 private void notifyPosted(final ManagedServiceInfo info,
3813 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
3814 final INotificationListener listener = (INotificationListener)info.service;
3815 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
3817 listener.onNotificationPosted(sbnHolder, rankingUpdate);
3818 } catch (RemoteException ex) {
3819 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
3823 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
3824 NotificationRankingUpdate rankingUpdate) {
3825 if (!info.enabledAndUserMatches(sbn.getUserId())) {
3828 final INotificationListener listener = (INotificationListener) info.service;
3829 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
3831 listener.onNotificationRemoved(sbnHolder, rankingUpdate);
3832 } catch (RemoteException ex) {
3833 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
3837 private void notifyRankingUpdate(ManagedServiceInfo info,
3838 NotificationRankingUpdate rankingUpdate) {
3839 final INotificationListener listener = (INotificationListener) info.service;
3841 listener.onNotificationRankingUpdate(rankingUpdate);
3842 } catch (RemoteException ex) {
3843 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
3847 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
3848 final INotificationListener listener = (INotificationListener) info.service;
3850 listener.onListenerHintsChanged(hints);
3851 } catch (RemoteException ex) {
3852 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
3856 private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
3857 int interruptionFilter) {
3858 final INotificationListener listener = (INotificationListener) info.service;
3860 listener.onInterruptionFilterChanged(interruptionFilter);
3861 } catch (RemoteException ex) {
3862 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
3866 private boolean isListenerPackage(String packageName) {
3867 if (packageName == null) {
3870 // TODO: clean up locking object later
3871 synchronized (mNotificationList) {
3872 for (final ManagedServiceInfo serviceInfo : mServices) {
3873 if (packageName.equals(serviceInfo.component.getPackageName())) {
3882 * Returns whether any of the currently registered listeners wants to receive notification
3885 * <p>Currently we assume groups are desired by non-SystemUI listeners.</p>
3887 public boolean notificationGroupsDesired() {
3888 return mNotificationGroupsDesired;
3891 private void updateNotificationGroupsDesiredLocked() {
3892 mNotificationGroupsDesired = true;
3893 // No listeners, no groups.
3894 if (mServices.isEmpty()) {
3895 mNotificationGroupsDesired = false;
3898 // One listener: Check whether it's SysUI.
3899 if (mServices.size() == 1 &&
3900 mServices.get(0).component.getPackageName().equals("com.android.systemui")) {
3901 mNotificationGroupsDesired = false;
3907 public static final class DumpFilter {
3908 public boolean filtered = false;
3909 public String pkgFilter;
3912 public boolean stats;
3913 public boolean redact = true;
3915 public static DumpFilter parseFromArguments(String[] args) {
3916 final DumpFilter filter = new DumpFilter();
3917 for (int ai = 0; ai < args.length; ai++) {
3918 final String a = args[ai];
3919 if ("--noredact".equals(a) || "--reveal".equals(a)) {
3920 filter.redact = false;
3921 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
3922 if (ai < args.length-1) {
3924 filter.pkgFilter = args[ai].trim().toLowerCase();
3925 if (filter.pkgFilter.isEmpty()) {
3926 filter.pkgFilter = null;
3928 filter.filtered = true;
3931 } else if ("--zen".equals(a) || "zen".equals(a)) {
3932 filter.filtered = true;
3934 } else if ("--stats".equals(a)) {
3935 filter.stats = true;
3936 if (ai < args.length-1) {
3938 filter.since = Long.valueOf(args[ai]);
3947 public boolean matches(StatusBarNotification sbn) {
3948 if (!filtered) return true;
3949 return zen ? true : sbn != null
3950 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
3953 public boolean matches(ComponentName component) {
3954 if (!filtered) return true;
3955 return zen ? true : component != null && matches(component.getPackageName());
3958 public boolean matches(String pkg) {
3959 if (!filtered) return true;
3960 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
3964 public String toString() {
3965 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
3970 * Wrapper for a StatusBarNotification object that allows transfer across a oneway
3971 * binder without sending large amounts of data over a oneway transaction.
3973 private static final class StatusBarNotificationHolder
3974 extends IStatusBarNotificationHolder.Stub {
3975 private StatusBarNotification mValue;
3977 public StatusBarNotificationHolder(StatusBarNotification value) {
3981 /** Get the held value and clear it. This function should only be called once per holder */
3983 public StatusBarNotification get() {
3984 StatusBarNotification value = mValue;
3990 private final class PolicyAccess {
3991 private static final String SEPARATOR = ":";
3992 private final String[] PERM = {
3993 android.Manifest.permission.ACCESS_NOTIFICATION_POLICY
3996 public boolean isPackageGranted(String pkg) {
3997 return pkg != null && getGrantedPackages().contains(pkg);
4000 public void put(String pkg, boolean granted) {
4001 if (pkg == null) return;
4002 final ArraySet<String> pkgs = getGrantedPackages();
4005 changed = pkgs.add(pkg);
4007 changed = pkgs.remove(pkg);
4009 if (!changed) return;
4010 final String setting = TextUtils.join(SEPARATOR, pkgs);
4011 final int currentUser = ActivityManager.getCurrentUser();
4012 Settings.Secure.putStringForUser(getContext().getContentResolver(),
4013 Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
4016 getContext().sendBroadcastAsUser(new Intent(NotificationManager
4017 .ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
4019 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), new UserHandle(currentUser), null);
4022 public ArraySet<String> getGrantedPackages() {
4023 final ArraySet<String> pkgs = new ArraySet<>();
4025 long identity = Binder.clearCallingIdentity();
4027 final String setting = Settings.Secure.getStringForUser(
4028 getContext().getContentResolver(),
4029 Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
4030 ActivityManager.getCurrentUser());
4031 if (setting != null) {
4032 final String[] tokens = setting.split(SEPARATOR);
4033 for (int i = 0; i < tokens.length; i++) {
4034 String token = tokens[i];
4035 if (token != null) {
4036 token = token.trim();
4038 if (TextUtils.isEmpty(token)) {
4045 Binder.restoreCallingIdentity(identity);
4050 public String[] getRequestingPackages() throws RemoteException {
4051 final ParceledListSlice list = AppGlobals.getPackageManager()
4052 .getPackagesHoldingPermissions(PERM, 0 /*flags*/,
4053 ActivityManager.getCurrentUser());
4054 final List<PackageInfo> pkgs = list.getList();
4055 if (pkgs == null || pkgs.isEmpty()) return new String[0];
4056 final int N = pkgs.size();
4057 final String[] rt = new String[N];
4058 for (int i = 0; i < N; i++) {
4059 rt[i] = pkgs.get(i).packageName;