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_SUMMARY_CANCELED;
26 import static android.service.notification.NotificationRankerService.REASON_LISTENER_CANCEL;
27 import static android.service.notification.NotificationRankerService.REASON_LISTENER_CANCEL_ALL;
28 import static android.service.notification.NotificationRankerService.REASON_PACKAGE_BANNED;
29 import static android.service.notification.NotificationRankerService.REASON_PACKAGE_CHANGED;
30 import static android.service.notification.NotificationRankerService.REASON_PACKAGE_SUSPENDED;
31 import static android.service.notification.NotificationRankerService.REASON_PROFILE_TURNED_OFF;
32 import static android.service.notification.NotificationRankerService.REASON_UNAUTOBUNDLED;
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.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
36 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
37 import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
38 import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
39 import static android.service.notification.NotificationListenerService.TRIM_FULL;
40 import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
41 import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_DEFAULT;
42 import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_NONE;
44 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
46 import android.Manifest;
47 import android.annotation.Nullable;
48 import android.app.ActivityManager;
49 import android.app.ActivityManagerInternal;
50 import android.app.ActivityManagerNative;
51 import android.app.AppGlobals;
52 import android.app.AppOpsManager;
53 import android.app.AutomaticZenRule;
54 import android.app.IActivityManager;
55 import android.app.INotificationManager;
56 import android.app.ITransientNotification;
57 import android.app.Notification;
58 import android.app.NotificationManager;
59 import android.app.NotificationManager.Policy;
60 import android.app.PendingIntent;
61 import android.app.RemoteInput;
62 import android.app.StatusBarManager;
63 import android.app.backup.BackupManager;
64 import android.app.usage.UsageEvents;
65 import android.app.usage.UsageStatsManagerInternal;
66 import android.content.BroadcastReceiver;
67 import android.content.ComponentName;
68 import android.content.ContentResolver;
69 import android.content.Context;
70 import android.content.Intent;
71 import android.content.IntentFilter;
72 import android.content.pm.ApplicationInfo;
73 import android.content.pm.IPackageManager;
74 import android.content.pm.PackageInfo;
75 import android.content.pm.PackageManager;
76 import android.content.pm.PackageManager.NameNotFoundException;
77 import android.content.pm.ParceledListSlice;
78 import android.content.pm.UserInfo;
79 import android.content.res.Resources;
80 import android.database.ContentObserver;
81 import android.media.AudioAttributes;
82 import android.media.AudioManager;
83 import android.media.AudioManagerInternal;
84 import android.media.AudioSystem;
85 import android.media.IRingtonePlayer;
86 import android.net.Uri;
87 import android.os.Binder;
88 import android.os.Bundle;
89 import android.os.Environment;
90 import android.os.Handler;
91 import android.os.HandlerThread;
92 import android.os.IBinder;
93 import android.os.IInterface;
94 import android.os.Looper;
95 import android.os.Message;
96 import android.os.Parcelable;
97 import android.os.Process;
98 import android.os.RemoteException;
99 import android.os.SystemClock;
100 import android.os.SystemProperties;
101 import android.os.UserHandle;
102 import android.os.UserManager;
103 import android.os.Vibrator;
104 import android.provider.Settings;
105 import android.service.notification.Adjustment;
106 import android.service.notification.Condition;
107 import android.service.notification.IConditionProvider;
108 import android.service.notification.INotificationListener;
109 import android.service.notification.IStatusBarNotificationHolder;
110 import android.service.notification.NotificationRankerService;
111 import android.service.notification.NotificationListenerService;
112 import android.service.notification.NotificationRankingUpdate;
113 import android.service.notification.StatusBarNotification;
114 import android.service.notification.ZenModeConfig;
115 import android.telephony.PhoneStateListener;
116 import android.telephony.TelephonyManager;
117 import android.text.TextUtils;
118 import android.util.ArrayMap;
119 import android.util.ArraySet;
120 import android.util.AtomicFile;
121 import android.util.Log;
122 import android.util.Slog;
123 import android.util.SparseArray;
124 import android.util.Xml;
125 import android.view.accessibility.AccessibilityEvent;
126 import android.view.accessibility.AccessibilityManager;
127 import android.widget.Toast;
129 import com.android.internal.R;
130 import com.android.internal.annotations.VisibleForTesting;
131 import com.android.internal.statusbar.NotificationVisibility;
132 import com.android.internal.util.FastXmlSerializer;
133 import com.android.internal.util.Preconditions;
134 import com.android.server.DeviceIdleController;
135 import com.android.server.EventLogTags;
136 import com.android.server.LocalServices;
137 import com.android.server.SystemService;
138 import com.android.server.lights.Light;
139 import com.android.server.lights.LightsManager;
140 import com.android.server.notification.ManagedServices.ManagedServiceInfo;
141 import com.android.server.statusbar.StatusBarManagerInternal;
142 import com.android.server.vr.VrManagerInternal;
143 import com.android.server.notification.ManagedServices.UserProfiles;
145 import libcore.io.IoUtils;
147 import org.json.JSONException;
148 import org.json.JSONObject;
149 import org.xmlpull.v1.XmlPullParser;
150 import org.xmlpull.v1.XmlPullParserException;
151 import org.xmlpull.v1.XmlSerializer;
153 import java.io.ByteArrayInputStream;
154 import java.io.ByteArrayOutputStream;
156 import java.io.FileDescriptor;
157 import java.io.FileInputStream;
158 import java.io.FileNotFoundException;
159 import java.io.FileOutputStream;
160 import java.io.IOException;
161 import java.io.InputStream;
162 import java.io.OutputStream;
163 import java.io.PrintWriter;
164 import java.nio.charset.StandardCharsets;
165 import java.util.ArrayDeque;
166 import java.util.ArrayList;
167 import java.util.Arrays;
168 import java.util.Iterator;
169 import java.util.List;
170 import java.util.Map;
171 import java.util.Map.Entry;
172 import java.util.Set;
173 import java.util.concurrent.TimeUnit;
176 public class NotificationManagerService extends SystemService {
177 static final String TAG = "NotificationService";
178 static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
179 public static final boolean ENABLE_CHILD_NOTIFICATIONS
180 = SystemProperties.getBoolean("debug.child_notifs", true);
182 static final int MAX_PACKAGE_NOTIFICATIONS = 50;
183 static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 50f;
186 static final int MESSAGE_TIMEOUT = 2;
187 static final int MESSAGE_SAVE_POLICY_FILE = 3;
188 static final int MESSAGE_SEND_RANKING_UPDATE = 4;
189 static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
190 static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
192 // ranking thread messages
193 private static final int MESSAGE_RECONSIDER_RANKING = 1000;
194 private static final int MESSAGE_RANKING_SORT = 1001;
196 static final int LONG_DELAY = 3500; // 3.5 seconds
197 static final int SHORT_DELAY = 2000; // 2 seconds
199 static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
201 static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
203 static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
205 static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true;
206 static final boolean ENABLE_BLOCKED_TOASTS = true;
208 // When #matchesCallFilter is called from the ringer, wait at most
209 // 3s to resolve the contacts. This timeout is required since
210 // ContactsProvider might take a long time to start up.
212 // Return STARRED_CONTACT when the timeout is hit in order to avoid
213 // missed calls in ZEN mode "Important".
214 static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
215 static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
216 ValidateNotificationPeople.STARRED_CONTACT;
218 /** notification_enqueue status value for a newly enqueued notification. */
219 private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
221 /** notification_enqueue status value for an existing notification. */
222 private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
224 /** notification_enqueue status value for an ignored notification. */
225 private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
226 private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
227 private String mRankerServicePackageName;
229 private IActivityManager mAm;
230 AudioManager mAudioManager;
231 AudioManagerInternal mAudioManagerInternal;
232 @Nullable StatusBarManagerInternal mStatusBar;
234 private VrManagerInternal mVrManagerInternal;
236 final IBinder mForegroundToken = new Binder();
237 private Handler mHandler;
238 private final HandlerThread mRankingThread = new HandlerThread("ranker",
239 Process.THREAD_PRIORITY_BACKGROUND);
241 private Light mNotificationLight;
242 Light mAttentionLight;
243 private int mDefaultNotificationColor;
244 private int mDefaultNotificationLedOn;
246 private int mDefaultNotificationLedOff;
247 private long[] mDefaultVibrationPattern;
249 private long[] mFallbackVibrationPattern;
250 private boolean mUseAttentionLight;
251 boolean mSystemReady;
253 private boolean mDisableNotificationEffects;
254 private int mCallState;
255 private String mSoundNotificationKey;
256 private String mVibrateNotificationKey;
258 private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
259 new SparseArray<ArraySet<ManagedServiceInfo>>();
260 private List<ComponentName> mEffectsSuppressors = new ArrayList<ComponentName>();
261 private int mListenerHints; // right now, all hints are global
262 private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
264 // for enabling and disabling notification pulse behavior
265 private boolean mScreenOn = true;
266 private boolean mInCall = false;
267 private boolean mNotificationPulseEnabled;
269 // used as a mutex for access to all active notifications & listeners
270 final ArrayList<NotificationRecord> mNotificationList =
271 new ArrayList<NotificationRecord>();
272 final ArrayMap<String, NotificationRecord> mNotificationsByKey =
273 new ArrayMap<String, NotificationRecord>();
274 final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
275 final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();
276 final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
277 final PolicyAccess mPolicyAccess = new PolicyAccess();
279 // The last key in this list owns the hardware.
280 ArrayList<String> mLights = new ArrayList<>();
282 private AppOpsManager mAppOps;
283 private UsageStatsManagerInternal mAppUsageStats;
285 private Archive mArchive;
287 // Persistent storage for notification policy
288 private AtomicFile mPolicyFile;
290 private static final int DB_VERSION = 1;
292 private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
293 private static final String ATTR_VERSION = "version";
295 private RankingHelper mRankingHelper;
297 private final UserProfiles mUserProfiles = new UserProfiles();
298 private NotificationListeners mListeners;
299 private NotificationRankers mRankerServices;
300 private ConditionProviders mConditionProviders;
301 private NotificationUsageStats mUsageStats;
303 private static final int MY_UID = Process.myUid();
304 private static final int MY_PID = Process.myPid();
305 private RankingHandler mRankingHandler;
306 private long mLastOverRateLogTime;
307 private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
308 private String mSystemNotificationSound;
310 private static class Archive {
311 final int mBufferSize;
312 final ArrayDeque<StatusBarNotification> mBuffer;
314 public Archive(int size) {
316 mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
319 public String toString() {
320 final StringBuilder sb = new StringBuilder();
321 final int N = mBuffer.size();
322 sb.append("Archive (");
324 sb.append(" notification");
325 sb.append((N==1)?")":"s)");
326 return sb.toString();
329 public void record(StatusBarNotification nr) {
330 if (mBuffer.size() == mBufferSize) {
331 mBuffer.removeFirst();
334 // We don't want to store the heavy bits of the notification in the archive,
335 // but other clients in the system process might be using the object, so we
336 // store a (lightened) copy.
337 mBuffer.addLast(nr.cloneLight());
340 public Iterator<StatusBarNotification> descendingIterator() {
341 return mBuffer.descendingIterator();
344 public StatusBarNotification[] getArray(int count) {
345 if (count == 0) count = mBufferSize;
346 final StatusBarNotification[] a
347 = new StatusBarNotification[Math.min(count, mBuffer.size())];
348 Iterator<StatusBarNotification> iter = descendingIterator();
350 while (iter.hasNext() && i < count) {
351 a[i++] = iter.next();
358 private void readPolicyXml(InputStream stream, boolean forRestore)
359 throws XmlPullParserException, NumberFormatException, IOException {
360 final XmlPullParser parser = Xml.newPullParser();
361 parser.setInput(stream, StandardCharsets.UTF_8.name());
363 while (parser.next() != END_DOCUMENT) {
364 mZenModeHelper.readXml(parser, forRestore);
365 mRankingHelper.readXml(parser, forRestore);
369 private void loadPolicyFile() {
370 if (DBG) Slog.d(TAG, "loadPolicyFile");
371 synchronized(mPolicyFile) {
373 FileInputStream infile = null;
375 infile = mPolicyFile.openRead();
376 readPolicyXml(infile, false /*forRestore*/);
377 } catch (FileNotFoundException e) {
379 } catch (IOException e) {
380 Log.wtf(TAG, "Unable to read notification policy", e);
381 } catch (NumberFormatException e) {
382 Log.wtf(TAG, "Unable to parse notification policy", e);
383 } catch (XmlPullParserException e) {
384 Log.wtf(TAG, "Unable to parse notification policy", e);
386 IoUtils.closeQuietly(infile);
391 public void savePolicyFile() {
392 mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
393 mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
396 private void handleSavePolicyFile() {
397 if (DBG) Slog.d(TAG, "handleSavePolicyFile");
398 synchronized (mPolicyFile) {
399 final FileOutputStream stream;
401 stream = mPolicyFile.startWrite();
402 } catch (IOException e) {
403 Slog.w(TAG, "Failed to save policy file", e);
408 writePolicyXml(stream, false /*forBackup*/);
409 mPolicyFile.finishWrite(stream);
410 } catch (IOException e) {
411 Slog.w(TAG, "Failed to save policy file, restoring backup", e);
412 mPolicyFile.failWrite(stream);
415 BackupManager.dataChanged(getContext().getPackageName());
418 private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
419 final XmlSerializer out = new FastXmlSerializer();
420 out.setOutput(stream, StandardCharsets.UTF_8.name());
421 out.startDocument(null, true);
422 out.startTag(null, TAG_NOTIFICATION_POLICY);
423 out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
424 mZenModeHelper.writeXml(out, forBackup);
425 mRankingHelper.writeXml(out, forBackup);
426 out.endTag(null, TAG_NOTIFICATION_POLICY);
430 /** Use this when you actually want to post a notification or toast.
432 * Unchecked. Not exposed via Binder, but can be called in the course of enqueue*().
434 private boolean noteNotificationOp(String pkg, int uid) {
435 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
436 != AppOpsManager.MODE_ALLOWED) {
437 Slog.v(TAG, "notifications are disabled by AppOps for " + pkg);
443 /** Use this to check if a package can post a notification or toast. */
444 private boolean checkNotificationOp(String pkg, int uid) {
445 return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
446 == AppOpsManager.MODE_ALLOWED && !isPackageSuspendedForUser(pkg, uid);
449 private static final class ToastRecord
453 final ITransientNotification callback;
456 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration)
460 this.callback = callback;
461 this.duration = duration;
464 void update(int duration) {
465 this.duration = duration;
468 void dump(PrintWriter pw, String prefix, DumpFilter filter) {
469 if (filter != null && !filter.matches(pkg)) return;
470 pw.println(prefix + this);
474 public final String toString()
476 return "ToastRecord{"
477 + Integer.toHexString(System.identityHashCode(this))
479 + " callback=" + callback
480 + " duration=" + duration;
484 private final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
487 public void onSetDisabled(int status) {
488 synchronized (mNotificationList) {
489 mDisableNotificationEffects =
490 (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
491 if (disableNotificationEffects(null) != null) {
492 // cancel whatever's going on
493 long identity = Binder.clearCallingIdentity();
495 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
496 if (player != null) {
499 } catch (RemoteException e) {
501 Binder.restoreCallingIdentity(identity);
504 identity = Binder.clearCallingIdentity();
508 Binder.restoreCallingIdentity(identity);
515 public void onClearAll(int callingUid, int callingPid, int userId) {
516 synchronized (mNotificationList) {
517 cancelAllLocked(callingUid, callingPid, userId, REASON_DELEGATE_CANCEL_ALL, null,
518 /*includeCurrentProfiles*/ true);
523 public void onNotificationClick(int callingUid, int callingPid, String key) {
524 synchronized (mNotificationList) {
525 NotificationRecord r = mNotificationsByKey.get(key);
527 Log.w(TAG, "No notification with key: " + key);
530 final long now = System.currentTimeMillis();
531 EventLogTags.writeNotificationClicked(key,
532 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
534 StatusBarNotification sbn = r.sbn;
535 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
536 sbn.getId(), Notification.FLAG_AUTO_CANCEL,
537 Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
538 REASON_DELEGATE_CLICK, null);
543 public void onNotificationActionClick(int callingUid, int callingPid, String key,
545 synchronized (mNotificationList) {
546 NotificationRecord r = mNotificationsByKey.get(key);
548 Log.w(TAG, "No notification with key: " + key);
551 final long now = System.currentTimeMillis();
552 EventLogTags.writeNotificationActionClicked(key, actionIndex,
553 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
554 // TODO: Log action click via UsageStats.
559 public void onNotificationClear(int callingUid, int callingPid,
560 String pkg, String tag, int id, int userId) {
561 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
562 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
563 true, userId, REASON_DELEGATE_CANCEL, null);
567 public void onPanelRevealed(boolean clearEffects, int items) {
568 EventLogTags.writeNotificationPanelRevealed(items);
575 public void onPanelHidden() {
576 EventLogTags.writeNotificationPanelHidden();
580 public void clearEffects() {
581 synchronized (mNotificationList) {
582 if (DBG) Slog.d(TAG, "clearEffects");
584 clearVibrateLocked();
590 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
591 int uid, int initialPid, String message, int userId) {
592 Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
593 + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
594 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
595 REASON_DELEGATE_ERROR, null);
596 long ident = Binder.clearCallingIdentity();
598 ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg,
599 "Bad notification posted from package " + pkg
601 } catch (RemoteException e) {
603 Binder.restoreCallingIdentity(ident);
607 public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
608 NotificationVisibility[] noLongerVisibleKeys) {
609 synchronized (mNotificationList) {
610 for (NotificationVisibility nv : newlyVisibleKeys) {
611 NotificationRecord r = mNotificationsByKey.get(nv.key);
612 if (r == null) continue;
613 r.setVisibility(true, nv.rank);
616 // Note that we might receive this event after notifications
617 // have already left the system, e.g. after dismissing from the
618 // shade. Hence not finding notifications in
619 // mNotificationsByKey is not an exceptional condition.
620 for (NotificationVisibility nv : noLongerVisibleKeys) {
621 NotificationRecord r = mNotificationsByKey.get(nv.key);
622 if (r == null) continue;
623 r.setVisibility(false, nv.rank);
630 public void onNotificationExpansionChanged(String key,
631 boolean userAction, boolean expanded) {
632 synchronized (mNotificationList) {
633 NotificationRecord r = mNotificationsByKey.get(key);
635 r.stats.onExpansionChanged(userAction, expanded);
636 final long now = System.currentTimeMillis();
637 EventLogTags.writeNotificationExpansion(key,
638 userAction ? 1 : 0, expanded ? 1 : 0,
639 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
645 private void clearSoundLocked() {
646 mSoundNotificationKey = null;
647 long identity = Binder.clearCallingIdentity();
649 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
650 if (player != null) {
653 } catch (RemoteException e) {
655 Binder.restoreCallingIdentity(identity);
659 private void clearVibrateLocked() {
660 mVibrateNotificationKey = null;
661 long identity = Binder.clearCallingIdentity();
665 Binder.restoreCallingIdentity(identity);
669 private void clearLightsLocked() {
672 updateLightsLocked();
675 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
677 public void onReceive(Context context, Intent intent) {
678 String action = intent.getAction();
679 if (action == null) {
683 boolean queryRestart = false;
684 boolean queryRemove = false;
685 boolean packageChanged = false;
686 boolean cancelNotifications = true;
687 int reason = REASON_PACKAGE_CHANGED;
689 if (action.equals(Intent.ACTION_PACKAGE_ADDED)
690 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
691 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
692 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
693 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
694 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
695 || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
696 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
697 UserHandle.USER_ALL);
698 String pkgList[] = null;
699 boolean queryReplace = queryRemove &&
700 intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
701 if (DBG) Slog.i(TAG, "action=" + action + " queryReplace=" + queryReplace);
702 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
703 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
704 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
705 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
706 reason = REASON_PACKAGE_SUSPENDED;
707 } else if (queryRestart) {
708 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
710 Uri uri = intent.getData();
714 String pkgName = uri.getSchemeSpecificPart();
715 if (pkgName == null) {
718 if (packageChanged) {
719 // We cancel notifications for packages which have just been disabled
721 final IPackageManager pm = AppGlobals.getPackageManager();
722 final int enabled = pm.getApplicationEnabledSetting(pkgName,
723 changeUserId != UserHandle.USER_ALL ? changeUserId :
724 UserHandle.USER_SYSTEM);
725 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
726 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
727 cancelNotifications = false;
729 } catch (IllegalArgumentException e) {
730 // Package doesn't exist; probably racing with uninstall.
731 // cancelNotifications is already true, so nothing to do here.
733 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
735 } catch (RemoteException e) {
736 // Failed to talk to PackageManagerService Should never happen!
739 pkgList = new String[]{pkgName};
742 if (pkgList != null && (pkgList.length > 0)) {
743 for (String pkgName : pkgList) {
744 if (cancelNotifications) {
745 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart,
746 changeUserId, reason, null);
750 mListeners.onPackagesChanged(queryReplace, pkgList);
751 mRankerServices.onPackagesChanged(queryReplace, pkgList);
752 mConditionProviders.onPackagesChanged(queryReplace, pkgList);
753 mRankingHelper.onPackagesChanged(queryReplace, pkgList);
758 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
760 public void onReceive(Context context, Intent intent) {
761 String action = intent.getAction();
763 if (action.equals(Intent.ACTION_SCREEN_ON)) {
764 // Keep track of screen on/off state, but do not turn off the notification light
765 // until user passes through the lock screen or views the notification.
767 updateNotificationPulse();
768 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
770 updateNotificationPulse();
771 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
772 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
773 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
774 updateNotificationPulse();
775 } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
776 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
777 if (userHandle >= 0) {
778 cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
779 REASON_USER_STOPPED, null);
781 } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
782 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
783 if (userHandle >= 0) {
784 cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
785 REASON_PROFILE_TURNED_OFF, null);
787 } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
788 // turn off LED when user passes through lock screen
789 mNotificationLight.turnOff();
790 if (mStatusBar != null) {
791 mStatusBar.notificationLightOff();
793 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
794 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
795 // reload per-user settings
796 mSettingsObserver.update(null);
797 mUserProfiles.updateCache(context);
798 // Refresh managed services
799 mConditionProviders.onUserSwitched(user);
800 mListeners.onUserSwitched(user);
801 mRankerServices.onUserSwitched(user);
802 mZenModeHelper.onUserSwitched(user);
803 } else if (action.equals(Intent.ACTION_USER_ADDED)) {
804 mUserProfiles.updateCache(context);
805 } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
806 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
807 mZenModeHelper.onUserRemoved(user);
808 } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
809 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
810 mConditionProviders.onUserUnlocked(user);
811 mListeners.onUserUnlocked(user);
812 mRankerServices.onUserUnlocked(user);
813 mZenModeHelper.onUserUnlocked(user);
818 private final class SettingsObserver extends ContentObserver {
819 private final Uri NOTIFICATION_LIGHT_PULSE_URI
820 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
821 private final Uri NOTIFICATION_SOUND_URI
822 = Settings.System.getUriFor(Settings.System.NOTIFICATION_SOUND);
823 private final Uri NOTIFICATION_RATE_LIMIT_URI
824 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
826 SettingsObserver(Handler handler) {
831 ContentResolver resolver = getContext().getContentResolver();
832 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
833 false, this, UserHandle.USER_ALL);
834 resolver.registerContentObserver(NOTIFICATION_SOUND_URI,
835 false, this, UserHandle.USER_ALL);
836 resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
837 false, this, UserHandle.USER_ALL);
841 @Override public void onChange(boolean selfChange, Uri uri) {
845 public void update(Uri uri) {
846 ContentResolver resolver = getContext().getContentResolver();
847 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
848 boolean pulseEnabled = Settings.System.getInt(resolver,
849 Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
850 if (mNotificationPulseEnabled != pulseEnabled) {
851 mNotificationPulseEnabled = pulseEnabled;
852 updateNotificationPulse();
855 if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
856 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
857 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
859 if (uri == null || NOTIFICATION_SOUND_URI.equals(uri)) {
860 mSystemNotificationSound = Settings.System.getString(resolver,
861 Settings.System.NOTIFICATION_SOUND);
866 private SettingsObserver mSettingsObserver;
867 private ZenModeHelper mZenModeHelper;
869 private final Runnable mBuzzBeepBlinked = new Runnable() {
872 if (mStatusBar != null) {
873 mStatusBar.buzzBeepBlinked();
878 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
879 int[] ar = r.getIntArray(resid);
883 final int len = ar.length > maxlen ? maxlen : ar.length;
884 long[] out = new long[len];
885 for (int i=0; i<len; i++) {
891 public NotificationManagerService(Context context) {
896 void setAudioManager(AudioManager audioMananger) {
897 mAudioManager = audioMananger;
901 void setVibrator(Vibrator vibrator) {
902 mVibrator = vibrator;
906 void setSystemReady(boolean systemReady) {
907 mSystemReady = systemReady;
911 void setHandler(Handler handler) {
916 void setSystemNotificationSound(String systemNotificationSound) {
917 mSystemNotificationSound = systemNotificationSound;
921 public void onStart() {
922 Resources resources = getContext().getResources();
924 mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
925 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
926 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
928 mAm = ActivityManagerNative.getDefault();
929 mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
930 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
931 mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
933 // This is the package that contains the AOSP framework update.
934 mRankerServicePackageName = getContext().getPackageManager()
935 .getServicesSystemSharedLibraryPackageName();
937 mHandler = new WorkerHandler();
938 mRankingThread.start();
939 String[] extractorNames;
941 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
942 } catch (Resources.NotFoundException e) {
943 extractorNames = new String[0];
945 mUsageStats = new NotificationUsageStats(getContext());
946 mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
947 mRankingHelper = new RankingHelper(getContext(),
951 mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles);
952 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
953 mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
955 public void onConfigChanged() {
960 void onZenModeChanged() {
961 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
962 getContext().sendBroadcastAsUser(
963 new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
964 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
965 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
966 synchronized(mNotificationList) {
967 updateInterruptionFilterLocked();
972 void onPolicyChanged() {
973 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
976 final File systemDir = new File(Environment.getDataDirectory(), "system");
977 mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
981 // This is a MangedServices object that keeps track of the listeners.
982 mListeners = new NotificationListeners();
984 // This is a MangedServices object that keeps track of the ranker.
985 mRankerServices = new NotificationRankers();
986 // Find the updatable ranker and register it.
987 mRankerServices.registerRanker();
989 mStatusBar = getLocalService(StatusBarManagerInternal.class);
990 if (mStatusBar != null) {
991 mStatusBar.setNotificationDelegate(mNotificationDelegate);
994 final LightsManager lights = getLocalService(LightsManager.class);
995 mNotificationLight = lights.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
996 mAttentionLight = lights.getLight(LightsManager.LIGHT_ID_ATTENTION);
998 mDefaultNotificationColor = resources.getColor(
999 R.color.config_defaultNotificationColor);
1000 mDefaultNotificationLedOn = resources.getInteger(
1001 R.integer.config_defaultNotificationLedOn);
1002 mDefaultNotificationLedOff = resources.getInteger(
1003 R.integer.config_defaultNotificationLedOff);
1005 mDefaultVibrationPattern = getLongArray(resources,
1006 R.array.config_defaultNotificationVibePattern,
1007 VIBRATE_PATTERN_MAXLEN,
1008 DEFAULT_VIBRATE_PATTERN);
1010 mFallbackVibrationPattern = getLongArray(resources,
1011 R.array.config_notificationFallbackVibePattern,
1012 VIBRATE_PATTERN_MAXLEN,
1013 DEFAULT_VIBRATE_PATTERN);
1015 mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
1017 // Don't start allowing notifications until the setup wizard has run once.
1018 // After that, including subsequent boots, init with notifications turned on.
1019 // This works on the first boot because the setup wizard will toggle this
1020 // flag at least once and we'll go back to 0 after that.
1021 if (0 == Settings.Global.getInt(getContext().getContentResolver(),
1022 Settings.Global.DEVICE_PROVISIONED, 0)) {
1023 mDisableNotificationEffects = true;
1025 mZenModeHelper.initZenMode();
1026 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1028 mUserProfiles.updateCache(getContext());
1029 listenForCallState();
1031 // register for various Intents
1032 IntentFilter filter = new IntentFilter();
1033 filter.addAction(Intent.ACTION_SCREEN_ON);
1034 filter.addAction(Intent.ACTION_SCREEN_OFF);
1035 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
1036 filter.addAction(Intent.ACTION_USER_PRESENT);
1037 filter.addAction(Intent.ACTION_USER_STOPPED);
1038 filter.addAction(Intent.ACTION_USER_SWITCHED);
1039 filter.addAction(Intent.ACTION_USER_ADDED);
1040 filter.addAction(Intent.ACTION_USER_REMOVED);
1041 filter.addAction(Intent.ACTION_USER_UNLOCKED);
1042 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
1043 getContext().registerReceiver(mIntentReceiver, filter);
1045 IntentFilter pkgFilter = new IntentFilter();
1046 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
1047 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1048 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
1049 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1050 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1051 pkgFilter.addDataScheme("package");
1052 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1055 IntentFilter suspendedPkgFilter = new IntentFilter();
1056 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
1057 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1058 suspendedPkgFilter, null, null);
1060 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
1061 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1064 mSettingsObserver = new SettingsObserver(mHandler);
1066 mArchive = new Archive(resources.getInteger(
1067 R.integer.config_notificationServiceArchiveSize));
1069 publishBinderService(Context.NOTIFICATION_SERVICE, mService);
1070 publishLocalService(NotificationManagerInternal.class, mInternalService);
1073 private void sendRegisteredOnlyBroadcast(String action) {
1074 getContext().sendBroadcastAsUser(new Intent(action)
1075 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
1079 * Make sure the XML config and the the AppOps system agree about blocks.
1081 private void syncBlockDb() {
1084 // sync bans from ranker into app opps
1085 Map<Integer, String> packageBans = mRankingHelper.getPackageBans();
1086 for(Entry<Integer, String> ban : packageBans.entrySet()) {
1087 final int uid = ban.getKey();
1088 final String packageName = ban.getValue();
1089 setNotificationsEnabledForPackageImpl(packageName, uid, false);
1092 // sync bans from app opps into ranker
1093 packageBans.clear();
1094 for (UserInfo user : UserManager.get(getContext()).getUsers()) {
1095 final int userId = user.getUserHandle().getIdentifier();
1096 final PackageManager packageManager = getContext().getPackageManager();
1097 List<PackageInfo> packages = packageManager.getInstalledPackagesAsUser(0, userId);
1098 final int packageCount = packages.size();
1099 for (int p = 0; p < packageCount; p++) {
1100 final String packageName = packages.get(p).packageName;
1102 final int uid = packageManager.getPackageUidAsUser(packageName, userId);
1103 if (!checkNotificationOp(packageName, uid)) {
1104 packageBans.put(uid, packageName);
1106 } catch (NameNotFoundException e) {
1111 for (Entry<Integer, String> ban : packageBans.entrySet()) {
1112 mRankingHelper.setImportance(ban.getValue(), ban.getKey(), IMPORTANCE_NONE);
1119 public void onBootPhase(int phase) {
1120 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1121 // no beeping until we're basically done booting
1122 mSystemReady = true;
1124 // Grab our optional AudioService
1125 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
1126 mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
1127 mVrManagerInternal = getLocalService(VrManagerInternal.class);
1128 mZenModeHelper.onSystemReady();
1129 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1130 // This observer will force an update when observe is called, causing us to
1131 // bind to listener services.
1132 mSettingsObserver.observe();
1133 mListeners.onBootPhaseAppsCanStart();
1134 mRankerServices.onBootPhaseAppsCanStart();
1135 mConditionProviders.onBootPhaseAppsCanStart();
1139 void setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled) {
1140 Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
1142 mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
1143 enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
1145 // Now, cancel any outstanding notifications that are part of a just-disabled app
1146 if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
1147 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true, UserHandle.getUserId(uid),
1148 REASON_PACKAGE_BANNED, null);
1152 private void updateListenerHintsLocked() {
1153 final int hints = calculateHints();
1154 if (hints == mListenerHints) return;
1155 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
1156 mListenerHints = hints;
1157 scheduleListenerHintsChanged(hints);
1160 private void updateEffectsSuppressorLocked() {
1161 final long updatedSuppressedEffects = calculateSuppressedEffects();
1162 if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1163 final List<ComponentName> suppressors = getSuppressors();
1164 ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1165 mEffectsSuppressors = suppressors;
1166 mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
1167 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
1170 private ArrayList<ComponentName> getSuppressors() {
1171 ArrayList<ComponentName> names = new ArrayList<ComponentName>();
1172 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1173 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1175 for (ManagedServiceInfo info : serviceInfoList) {
1176 names.add(info.component);
1183 private boolean removeDisabledHints(ManagedServiceInfo info) {
1184 return removeDisabledHints(info, 0);
1187 private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
1188 boolean removed = false;
1190 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1191 final int hint = mListenersDisablingEffects.keyAt(i);
1192 final ArraySet<ManagedServiceInfo> listeners =
1193 mListenersDisablingEffects.valueAt(i);
1195 if (hints == 0 || (hint & hints) == hint) {
1196 removed = removed || listeners.remove(info);
1203 private void addDisabledHints(ManagedServiceInfo info, int hints) {
1204 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1205 addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
1208 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1209 addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1212 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1213 addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
1217 private void addDisabledHint(ManagedServiceInfo info, int hint) {
1218 if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
1219 mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
1222 ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
1223 hintListeners.add(info);
1226 private int calculateHints() {
1228 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1229 int hint = mListenersDisablingEffects.keyAt(i);
1230 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1232 if (!serviceInfoList.isEmpty()) {
1240 private long calculateSuppressedEffects() {
1241 int hints = calculateHints();
1242 long suppressedEffects = 0;
1244 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1245 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
1248 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1249 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
1252 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1253 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
1256 return suppressedEffects;
1259 private void updateInterruptionFilterLocked() {
1260 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1261 if (interruptionFilter == mInterruptionFilter) return;
1262 mInterruptionFilter = interruptionFilter;
1263 scheduleInterruptionFilterChanged(interruptionFilter);
1266 private final IBinder mService = new INotificationManager.Stub() {
1268 // ============================================================================
1271 public void enqueueToast(String pkg, ITransientNotification callback, int duration)
1274 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1275 + " duration=" + duration);
1278 if (pkg == null || callback == null) {
1279 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1283 final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg));
1284 final boolean isPackageSuspended =
1285 isPackageSuspendedForUser(pkg, Binder.getCallingUid());
1287 if (ENABLE_BLOCKED_TOASTS && (!noteNotificationOp(pkg, Binder.getCallingUid())
1288 || isPackageSuspended)) {
1289 if (!isSystemToast) {
1290 Slog.e(TAG, "Suppressing toast from package " + pkg
1291 + (isPackageSuspended
1292 ? " due to package suspended by administrator."
1293 : " by user request."));
1298 synchronized (mToastQueue) {
1299 int callingPid = Binder.getCallingPid();
1300 long callingId = Binder.clearCallingIdentity();
1303 int index = indexOfToastLocked(pkg, callback);
1304 // If it's already in the queue, we update it in place, we don't
1305 // move it to the end of the queue.
1307 record = mToastQueue.get(index);
1308 record.update(duration);
1310 // Limit the number of toasts that any given package except the android
1311 // package can enqueue. Prevents DOS attacks and deals with leaks.
1312 if (!isSystemToast) {
1314 final int N = mToastQueue.size();
1315 for (int i=0; i<N; i++) {
1316 final ToastRecord r = mToastQueue.get(i);
1317 if (r.pkg.equals(pkg)) {
1319 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
1320 Slog.e(TAG, "Package has already posted " + count
1321 + " toasts. Not showing more. Package=" + pkg);
1328 record = new ToastRecord(callingPid, pkg, callback, duration);
1329 mToastQueue.add(record);
1330 index = mToastQueue.size() - 1;
1331 keepProcessAliveLocked(callingPid);
1333 // If it's at index 0, it's the current toast. It doesn't matter if it's
1334 // new or just been updated. Call back and tell it to show itself.
1335 // If the callback fails, this will remove it from the list, so don't
1336 // assume that it's valid after this.
1338 showNextToastLocked();
1341 Binder.restoreCallingIdentity(callingId);
1347 public void cancelToast(String pkg, ITransientNotification callback) {
1348 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
1350 if (pkg == null || callback == null) {
1351 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
1355 synchronized (mToastQueue) {
1356 long callingId = Binder.clearCallingIdentity();
1358 int index = indexOfToastLocked(pkg, callback);
1360 cancelToastLocked(index);
1362 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
1363 + " callback=" + callback);
1366 Binder.restoreCallingIdentity(callingId);
1372 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
1373 Notification notification, int[] idOut, int userId) throws RemoteException {
1374 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
1375 Binder.getCallingPid(), tag, id, notification, idOut, userId);
1379 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
1380 checkCallerIsSystemOrSameApp(pkg);
1381 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1382 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
1383 // Don't allow client applications to cancel foreground service notis or autobundled
1385 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
1386 (Binder.getCallingUid() == Process.SYSTEM_UID
1387 ? 0 : Notification.FLAG_FOREGROUND_SERVICE)
1388 | (Binder.getCallingUid() == Process.SYSTEM_UID
1389 ? 0 : Notification.FLAG_AUTOGROUP_SUMMARY), false, userId,
1390 REASON_APP_CANCEL, null);
1394 public void cancelAllNotifications(String pkg, int userId) {
1395 checkCallerIsSystemOrSameApp(pkg);
1397 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1398 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
1400 // Calling from user space, don't allow the canceling of actively
1401 // running foreground services.
1402 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
1403 pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
1404 REASON_APP_CANCEL_ALL, null);
1408 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
1409 checkCallerIsSystem();
1411 setNotificationsEnabledForPackageImpl(pkg, uid, enabled);
1412 mRankingHelper.setEnabled(pkg, uid, enabled);
1417 * Use this when you just want to know if notifications are OK for this package.
1420 public boolean areNotificationsEnabled(String pkg) {
1421 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
1425 * Use this when you just want to know if notifications are OK for this package.
1428 public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
1429 checkCallerIsSystemOrSameApp(pkg);
1430 return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
1431 == AppOpsManager.MODE_ALLOWED) && !isPackageSuspendedForUser(pkg, uid);
1435 public void setPriority(String pkg, int uid, int priority) {
1436 checkCallerIsSystem();
1437 mRankingHelper.setPriority(pkg, uid, priority);
1442 public int getPriority(String pkg, int uid) {
1443 checkCallerIsSystem();
1444 return mRankingHelper.getPriority(pkg, uid);
1448 public void setVisibilityOverride(String pkg, int uid, int visibility) {
1449 checkCallerIsSystem();
1450 mRankingHelper.setVisibilityOverride(pkg, uid, visibility);
1455 public int getVisibilityOverride(String pkg, int uid) {
1456 checkCallerIsSystem();
1457 return mRankingHelper.getVisibilityOverride(pkg, uid);
1461 public void setImportance(String pkg, int uid, int importance) {
1462 enforceSystemOrSystemUI("Caller not system or systemui");
1463 setNotificationsEnabledForPackageImpl(pkg, uid,
1464 importance != NotificationListenerService.Ranking.IMPORTANCE_NONE);
1465 mRankingHelper.setImportance(pkg, uid, importance);
1470 public int getPackageImportance(String pkg) {
1471 checkCallerIsSystemOrSameApp(pkg);
1472 return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
1476 public int getImportance(String pkg, int uid) {
1477 enforceSystemOrSystemUI("Caller not system or systemui");
1478 return mRankingHelper.getImportance(pkg, uid);
1482 * System-only API for getting a list of current (i.e. not cleared) notifications.
1484 * Requires ACCESS_NOTIFICATIONS which is signature|system.
1485 * @returns A list of all the notifications, in natural order.
1488 public StatusBarNotification[] getActiveNotifications(String callingPkg) {
1489 // enforce() will ensure the calling uid has the correct permission
1490 getContext().enforceCallingOrSelfPermission(
1491 android.Manifest.permission.ACCESS_NOTIFICATIONS,
1492 "NotificationManagerService.getActiveNotifications");
1494 StatusBarNotification[] tmp = null;
1495 int uid = Binder.getCallingUid();
1497 // noteOp will check to make sure the callingPkg matches the uid
1498 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1499 == AppOpsManager.MODE_ALLOWED) {
1500 synchronized (mNotificationList) {
1501 tmp = new StatusBarNotification[mNotificationList.size()];
1502 final int N = mNotificationList.size();
1503 for (int i=0; i<N; i++) {
1504 tmp[i] = mNotificationList.get(i).sbn;
1512 * Public API for getting a list of current notifications for the calling package/uid.
1514 * @returns A list of all the package's notifications, in natural order.
1517 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
1518 int incomingUserId) {
1519 checkCallerIsSystemOrSameApp(pkg);
1520 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1521 Binder.getCallingUid(), incomingUserId, true, false,
1522 "getAppActiveNotifications", pkg);
1524 final ArrayList<StatusBarNotification> list
1525 = new ArrayList<StatusBarNotification>(mNotificationList.size());
1527 synchronized (mNotificationList) {
1528 final int N = mNotificationList.size();
1529 for (int i = 0; i < N; i++) {
1530 final StatusBarNotification sbn = mNotificationList.get(i).sbn;
1531 if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId
1532 && (sbn.getNotification().flags
1533 & Notification.FLAG_AUTOGROUP_SUMMARY) == 0) {
1534 // We could pass back a cloneLight() but clients might get confused and
1535 // try to send this thing back to notify() again, which would not work
1537 final StatusBarNotification sbnOut = new StatusBarNotification(
1538 sbn.getPackageName(),
1540 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
1541 0, // hide score from apps
1542 sbn.getNotification().clone(),
1543 sbn.getUser(), sbn.getPostTime());
1549 return new ParceledListSlice<StatusBarNotification>(list);
1553 * System-only API for getting a list of recent (cleared, no longer shown) notifications.
1555 * Requires ACCESS_NOTIFICATIONS which is signature|system.
1558 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
1559 // enforce() will ensure the calling uid has the correct permission
1560 getContext().enforceCallingOrSelfPermission(
1561 android.Manifest.permission.ACCESS_NOTIFICATIONS,
1562 "NotificationManagerService.getHistoricalNotifications");
1564 StatusBarNotification[] tmp = null;
1565 int uid = Binder.getCallingUid();
1567 // noteOp will check to make sure the callingPkg matches the uid
1568 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1569 == AppOpsManager.MODE_ALLOWED) {
1570 synchronized (mArchive) {
1571 tmp = mArchive.getArray(count);
1578 * Register a listener binder directly with the notification manager.
1580 * Only works with system callers. Apps should extend
1581 * {@link android.service.notification.NotificationListenerService}.
1584 public void registerListener(final INotificationListener listener,
1585 final ComponentName component, final int userid) {
1586 enforceSystemOrSystemUI("INotificationManager.registerListener");
1587 mListeners.registerService(listener, component, userid);
1591 * Remove a listener binder directly
1594 public void unregisterListener(INotificationListener token, int userid) {
1595 mListeners.unregisterService(token, userid);
1599 * Allow an INotificationListener to simulate a "clear all" operation.
1601 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
1603 * @param token The binder for the listener, to check that the caller is allowed
1606 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
1607 final int callingUid = Binder.getCallingUid();
1608 final int callingPid = Binder.getCallingPid();
1609 long identity = Binder.clearCallingIdentity();
1611 synchronized (mNotificationList) {
1612 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1614 final int N = keys.length;
1615 for (int i = 0; i < N; i++) {
1616 NotificationRecord r = mNotificationsByKey.get(keys[i]);
1617 if (r == null) continue;
1618 final int userId = r.sbn.getUserId();
1619 if (userId != info.userid && userId != UserHandle.USER_ALL &&
1620 !mUserProfiles.isCurrentProfile(userId)) {
1621 throw new SecurityException("Disallowed call from listener: "
1624 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
1625 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
1629 cancelAllLocked(callingUid, callingPid, info.userid,
1630 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
1634 Binder.restoreCallingIdentity(identity);
1639 * Handle request from an approved listener to re-enable itself.
1641 * @param component The componenet to be re-enabled, caller must match package.
1644 public void requestBindListener(ComponentName component) {
1645 checkCallerIsSystemOrSameApp(component.getPackageName());
1646 long identity = Binder.clearCallingIdentity();
1648 ManagedServices manager =
1649 mRankerServices.isComponentEnabledForCurrentProfiles(component)
1652 manager.setComponentState(component, true);
1654 Binder.restoreCallingIdentity(identity);
1659 public void requestUnbindListener(INotificationListener token) {
1660 long identity = Binder.clearCallingIdentity();
1662 // allow bound services to disable themselves
1663 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1664 info.getOwner().setComponentState(info.component, false);
1666 Binder.restoreCallingIdentity(identity);
1671 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
1672 long identity = Binder.clearCallingIdentity();
1674 synchronized (mNotificationList) {
1675 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1677 final int N = keys.length;
1678 for (int i = 0; i < N; i++) {
1679 NotificationRecord r = mNotificationsByKey.get(keys[i]);
1680 if (r == null) continue;
1681 final int userId = r.sbn.getUserId();
1682 if (userId != info.userid && userId != UserHandle.USER_ALL &&
1683 !mUserProfiles.isCurrentProfile(userId)) {
1684 throw new SecurityException("Disallowed call from listener: "
1688 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
1689 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
1690 userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM
1692 UsageEvents.Event.USER_INTERACTION);
1699 Binder.restoreCallingIdentity(identity);
1703 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
1704 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
1705 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
1706 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
1708 userId, REASON_LISTENER_CANCEL, info);
1712 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
1714 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
1716 * @param token The binder for the listener, to check that the caller is allowed
1719 public void cancelNotificationFromListener(INotificationListener token, String pkg,
1720 String tag, int id) {
1721 final int callingUid = Binder.getCallingUid();
1722 final int callingPid = Binder.getCallingPid();
1723 long identity = Binder.clearCallingIdentity();
1725 synchronized (mNotificationList) {
1726 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1727 if (info.supportsProfiles()) {
1728 Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
1729 + "from " + info.component
1730 + " use cancelNotification(key) instead.");
1732 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
1733 pkg, tag, id, info.userid);
1737 Binder.restoreCallingIdentity(identity);
1742 * Allow an INotificationListener to request the list of outstanding notifications seen by
1743 * the current user. Useful when starting up, after which point the listener callbacks
1746 * @param token The binder for the listener, to check that the caller is allowed
1747 * @param keys An array of notification keys to fetch, or null to fetch everything
1748 * @returns The return value will contain the notifications specified in keys, in that
1749 * order, or if keys is null, all the notifications, in natural order.
1752 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
1753 INotificationListener token, String[] keys, int trim) {
1754 synchronized (mNotificationList) {
1755 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1756 final boolean getKeys = keys != null;
1757 final int N = getKeys ? keys.length : mNotificationList.size();
1758 final ArrayList<StatusBarNotification> list
1759 = new ArrayList<StatusBarNotification>(N);
1760 for (int i=0; i<N; i++) {
1761 final NotificationRecord r = getKeys
1762 ? mNotificationsByKey.get(keys[i])
1763 : mNotificationList.get(i);
1764 if (r == null) continue;
1765 StatusBarNotification sbn = r.sbn;
1766 if (!isVisibleToListener(sbn, info)) continue;
1767 StatusBarNotification sbnToSend =
1768 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
1769 list.add(sbnToSend);
1771 return new ParceledListSlice<StatusBarNotification>(list);
1776 public void requestHintsFromListener(INotificationListener token, int hints) {
1777 final long identity = Binder.clearCallingIdentity();
1779 synchronized (mNotificationList) {
1780 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1781 final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
1782 | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
1783 | HINT_HOST_DISABLE_CALL_EFFECTS;
1784 final boolean disableEffects = (hints & disableEffectsMask) != 0;
1785 if (disableEffects) {
1786 addDisabledHints(info, hints);
1788 removeDisabledHints(info, hints);
1790 updateListenerHintsLocked();
1791 updateEffectsSuppressorLocked();
1794 Binder.restoreCallingIdentity(identity);
1799 public int getHintsFromListener(INotificationListener token) {
1800 synchronized (mNotificationList) {
1801 return mListenerHints;
1806 public void requestInterruptionFilterFromListener(INotificationListener token,
1807 int interruptionFilter) throws RemoteException {
1808 final long identity = Binder.clearCallingIdentity();
1810 synchronized (mNotificationList) {
1811 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1812 mZenModeHelper.requestFromListener(info.component, interruptionFilter);
1813 updateInterruptionFilterLocked();
1816 Binder.restoreCallingIdentity(identity);
1821 public int getInterruptionFilterFromListener(INotificationListener token)
1822 throws RemoteException {
1823 synchronized (mNotificationLight) {
1824 return mInterruptionFilter;
1829 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
1830 throws RemoteException {
1831 synchronized (mNotificationList) {
1832 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1833 if (info == null) return;
1834 mListeners.setOnNotificationPostedTrimLocked(info, trim);
1839 public int getZenMode() {
1840 return mZenModeHelper.getZenMode();
1844 public ZenModeConfig getZenModeConfig() {
1845 enforceSystemOrSystemUIOrVolume("INotificationManager.getZenModeConfig");
1846 return mZenModeHelper.getConfig();
1850 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
1851 enforceSystemOrSystemUIOrVolume("INotificationManager.setZenMode");
1852 final long identity = Binder.clearCallingIdentity();
1854 mZenModeHelper.setManualZenMode(mode, conditionId, reason);
1856 Binder.restoreCallingIdentity(identity);
1861 public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
1862 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
1863 return mZenModeHelper.getZenRules();
1867 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
1868 Preconditions.checkNotNull(id, "Id is null");
1869 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
1870 return mZenModeHelper.getAutomaticZenRule(id);
1874 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
1875 throws RemoteException {
1876 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
1877 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
1878 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
1879 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
1880 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
1882 return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
1883 "addAutomaticZenRule");
1887 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
1888 throws RemoteException {
1889 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
1890 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
1891 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
1892 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
1893 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
1895 return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
1896 "updateAutomaticZenRule");
1900 public boolean removeAutomaticZenRule(String id) throws RemoteException {
1901 Preconditions.checkNotNull(id, "Id is null");
1902 // Verify that they can modify zen rules.
1903 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
1905 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
1909 public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
1910 Preconditions.checkNotNull(packageName, "Package name is null");
1911 enforceSystemOrSystemUI("removeAutomaticZenRules");
1913 return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
1917 public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
1918 Preconditions.checkNotNull(owner, "Owner is null");
1919 enforceSystemOrSystemUI("getRuleInstanceCount");
1921 return mZenModeHelper.getCurrentInstanceCount(owner);
1925 public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
1926 enforcePolicyAccess(pkg, "setInterruptionFilter");
1927 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
1928 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
1929 final long identity = Binder.clearCallingIdentity();
1931 mZenModeHelper.setManualZenMode(zen, null, "setInterruptionFilter");
1933 Binder.restoreCallingIdentity(identity);
1938 public void notifyConditions(final String pkg, IConditionProvider provider,
1939 final Condition[] conditions) {
1940 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
1941 checkCallerIsSystemOrSameApp(pkg);
1942 mHandler.post(new Runnable() {
1945 mConditionProviders.notifyConditions(pkg, info, conditions);
1950 private void enforceSystemOrSystemUIOrVolume(String message) {
1951 if (mAudioManagerInternal != null) {
1952 final int vcuid = mAudioManagerInternal.getVolumeControllerUid();
1953 if (vcuid > 0 && Binder.getCallingUid() == vcuid) {
1957 enforceSystemOrSystemUI(message);
1960 private void enforceSystemOrSystemUI(String message) {
1961 if (isCallerSystem()) return;
1962 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
1966 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
1968 checkCallerIsSystemOrSameApp(pkg);
1969 } catch (SecurityException e) {
1970 getContext().enforceCallingPermission(
1971 android.Manifest.permission.STATUS_BAR_SERVICE,
1976 private void enforcePolicyAccess(int uid, String method) {
1977 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
1978 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
1981 boolean accessAllowed = false;
1982 String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
1983 final int packageCount = packages.length;
1984 for (int i = 0; i < packageCount; i++) {
1985 if (checkPolicyAccess(packages[i])) {
1986 accessAllowed = true;
1989 if (!accessAllowed) {
1990 Slog.w(TAG, "Notification policy access denied calling " + method);
1991 throw new SecurityException("Notification policy access denied");
1995 private void enforcePolicyAccess(String pkg, String method) {
1996 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
1997 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2000 checkCallerIsSameApp(pkg);
2001 if (!checkPolicyAccess(pkg)) {
2002 Slog.w(TAG, "Notification policy access denied calling " + method);
2003 throw new SecurityException("Notification policy access denied");
2007 private boolean checkPackagePolicyAccess(String pkg) {
2008 return mPolicyAccess.isPackageGranted(pkg);
2011 private boolean checkPolicyAccess(String pkg) {
2013 int uid = getContext().getPackageManager().getPackageUidAsUser(
2014 pkg, UserHandle.getCallingUserId());
2015 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
2016 android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
2020 } catch (NameNotFoundException e) {
2023 return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
2027 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2028 if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2029 != PackageManager.PERMISSION_GRANTED) {
2030 pw.println("Permission Denial: can't dump NotificationManager from pid="
2031 + Binder.getCallingPid()
2032 + ", uid=" + Binder.getCallingUid());
2036 final DumpFilter filter = DumpFilter.parseFromArguments(args);
2037 if (filter != null && filter.stats) {
2038 dumpJson(pw, filter);
2040 dumpImpl(pw, filter);
2045 public ComponentName getEffectsSuppressor() {
2046 enforceSystemOrSystemUIOrVolume("INotificationManager.getEffectsSuppressor");
2047 return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
2051 public boolean matchesCallFilter(Bundle extras) {
2052 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
2053 return mZenModeHelper.matchesCallFilter(
2054 Binder.getCallingUserHandle(),
2056 mRankingHelper.findExtractor(ValidateNotificationPeople.class),
2057 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
2058 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
2062 public boolean isSystemConditionProviderEnabled(String path) {
2063 enforceSystemOrSystemUIOrVolume("INotificationManager.isSystemConditionProviderEnabled");
2064 return mConditionProviders.isSystemProviderEnabled(path);
2067 // Backup/restore interface
2069 public byte[] getBackupPayload(int user) {
2070 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
2071 //TODO: http://b/22388012
2072 if (user != UserHandle.USER_SYSTEM) {
2073 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
2076 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
2078 writePolicyXml(baos, true /*forBackup*/);
2079 return baos.toByteArray();
2080 } catch (IOException e) {
2081 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
2087 public void applyRestore(byte[] payload, int user) {
2088 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
2089 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
2090 if (payload == null) {
2091 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
2094 //TODO: http://b/22388012
2095 if (user != UserHandle.USER_SYSTEM) {
2096 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
2099 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
2101 readPolicyXml(bais, true /*forRestore*/);
2103 } catch (NumberFormatException | XmlPullParserException | IOException e) {
2104 Slog.w(TAG, "applyRestore: error reading payload", e);
2109 public boolean isNotificationPolicyAccessGranted(String pkg) {
2110 return checkPolicyAccess(pkg);
2114 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
2115 enforceSystemOrSystemUIOrSamePackage(pkg,
2116 "request policy access status for another package");
2117 return checkPolicyAccess(pkg);
2121 public String[] getPackagesRequestingNotificationPolicyAccess()
2122 throws RemoteException {
2123 enforceSystemOrSystemUI("request policy access packages");
2124 final long identity = Binder.clearCallingIdentity();
2126 return mPolicyAccess.getRequestingPackages();
2128 Binder.restoreCallingIdentity(identity);
2133 public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
2134 throws RemoteException {
2135 enforceSystemOrSystemUI("grant notification policy access");
2136 final long identity = Binder.clearCallingIdentity();
2138 synchronized (mNotificationList) {
2139 mPolicyAccess.put(pkg, granted);
2142 Binder.restoreCallingIdentity(identity);
2147 public Policy getNotificationPolicy(String pkg) {
2148 enforcePolicyAccess(pkg, "getNotificationPolicy");
2149 final long identity = Binder.clearCallingIdentity();
2151 return mZenModeHelper.getNotificationPolicy();
2153 Binder.restoreCallingIdentity(identity);
2158 public void setNotificationPolicy(String pkg, Policy policy) {
2159 enforcePolicyAccess(pkg, "setNotificationPolicy");
2160 final long identity = Binder.clearCallingIdentity();
2162 mZenModeHelper.setNotificationPolicy(policy);
2164 Binder.restoreCallingIdentity(identity);
2169 public void applyAdjustmentFromRankerService(INotificationListener token,
2170 Adjustment adjustment) throws RemoteException {
2171 final long identity = Binder.clearCallingIdentity();
2173 synchronized (mNotificationList) {
2174 mRankerServices.checkServiceTokenLocked(token);
2175 applyAdjustmentLocked(adjustment);
2177 maybeAddAutobundleSummary(adjustment);
2178 mRankingHandler.requestSort();
2180 Binder.restoreCallingIdentity(identity);
2185 public void applyAdjustmentsFromRankerService(INotificationListener token,
2186 List<Adjustment> adjustments) throws RemoteException {
2188 final long identity = Binder.clearCallingIdentity();
2190 synchronized (mNotificationList) {
2191 mRankerServices.checkServiceTokenLocked(token);
2192 for (Adjustment adjustment : adjustments) {
2193 applyAdjustmentLocked(adjustment);
2196 for (Adjustment adjustment : adjustments) {
2197 maybeAddAutobundleSummary(adjustment);
2199 mRankingHandler.requestSort();
2201 Binder.restoreCallingIdentity(identity);
2206 private void applyAdjustmentLocked(Adjustment adjustment) {
2207 maybeClearAutobundleSummaryLocked(adjustment);
2208 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2212 if (adjustment.getImportance() != IMPORTANCE_NONE) {
2213 n.setImportance(adjustment.getImportance(), adjustment.getExplanation());
2215 if (adjustment.getSignals() != null) {
2216 Bundle.setDefusable(adjustment.getSignals(), true);
2217 final String autoGroupKey = adjustment.getSignals().getString(
2218 Adjustment.GROUP_KEY_OVERRIDE_KEY, null);
2219 if (autoGroupKey == null) {
2220 EventLogTags.writeNotificationUnautogrouped(adjustment.getKey());
2222 EventLogTags.writeNotificationAutogrouped(adjustment.getKey());
2224 n.sbn.setOverrideGroupKey(autoGroupKey);
2228 // Clears the 'fake' auto-bunding summary.
2229 private void maybeClearAutobundleSummaryLocked(Adjustment adjustment) {
2230 if (adjustment.getSignals() != null) {
2231 Bundle.setDefusable(adjustment.getSignals(), true);
2232 if (adjustment.getSignals().containsKey(Adjustment.NEEDS_AUTOGROUPING_KEY)
2233 && !adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) {
2234 ArrayMap<String, String> summaries =
2235 mAutobundledSummaries.get(adjustment.getUser());
2236 if (summaries != null && summaries.containsKey(adjustment.getPackage())) {
2238 final NotificationRecord removed = mNotificationsByKey.get(
2239 summaries.remove(adjustment.getPackage()));
2240 if (removed != null) {
2241 mNotificationList.remove(removed);
2242 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED);
2249 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
2250 private void maybeAddAutobundleSummary(Adjustment adjustment) {
2251 if (adjustment.getSignals() != null) {
2252 Bundle.setDefusable(adjustment.getSignals(), true);
2253 if (adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) {
2254 final String newAutoBundleKey =
2255 adjustment.getSignals().getString(Adjustment.GROUP_KEY_OVERRIDE_KEY, null);
2257 NotificationRecord summaryRecord = null;
2258 synchronized (mNotificationList) {
2259 NotificationRecord notificationRecord =
2260 mNotificationsByKey.get(adjustment.getKey());
2261 if (notificationRecord == null) {
2262 // The notification could have been cancelled again already. A successive
2263 // adjustment will post a summary if needed.
2266 final StatusBarNotification adjustedSbn = notificationRecord.sbn;
2267 userId = adjustedSbn.getUser().getIdentifier();
2268 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
2269 if (summaries == null) {
2270 summaries = new ArrayMap<>();
2272 mAutobundledSummaries.put(userId, summaries);
2273 if (!summaries.containsKey(adjustment.getPackage())
2274 && newAutoBundleKey != null) {
2276 final ApplicationInfo appInfo =
2277 adjustedSbn.getNotification().extras.getParcelable(
2278 Notification.EXTRA_BUILDER_APPLICATION_INFO);
2279 final Bundle extras = new Bundle();
2280 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
2281 final Notification summaryNotification =
2282 new Notification.Builder(getContext()).setSmallIcon(
2283 adjustedSbn.getNotification().getSmallIcon())
2284 .setGroupSummary(true)
2285 .setGroup(newAutoBundleKey)
2286 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
2287 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
2288 .setColor(adjustedSbn.getNotification().color)
2290 summaryNotification.extras.putAll(extras);
2291 Intent appIntent = getContext().getPackageManager()
2292 .getLaunchIntentForPackage(adjustment.getPackage());
2293 if (appIntent != null) {
2294 summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
2295 getContext(), 0, appIntent, 0, null,
2296 UserHandle.of(userId));
2298 final StatusBarNotification summarySbn =
2299 new StatusBarNotification(adjustedSbn.getPackageName(),
2300 adjustedSbn.getOpPkg(),
2301 Integer.MAX_VALUE, Adjustment.GROUP_KEY_OVERRIDE_KEY,
2302 adjustedSbn.getUid(), adjustedSbn.getInitialPid(),
2303 summaryNotification, adjustedSbn.getUser(),
2305 System.currentTimeMillis());
2306 summaryRecord = new NotificationRecord(getContext(), summarySbn);
2307 summaries.put(adjustment.getPackage(), summarySbn.getKey());
2310 if (summaryRecord != null) {
2311 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
2317 private String disableNotificationEffects(NotificationRecord record) {
2318 if (mDisableNotificationEffects) {
2319 return "booleanState";
2321 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
2322 return "listenerHints";
2324 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
2330 private void dumpJson(PrintWriter pw, DumpFilter filter) {
2331 JSONObject dump = new JSONObject();
2333 dump.put("service", "Notification Manager");
2334 dump.put("bans", mRankingHelper.dumpBansJson(filter));
2335 dump.put("ranking", mRankingHelper.dumpJson(filter));
2336 dump.put("stats", mUsageStats.dumpJson(filter));
2337 } catch (JSONException e) {
2338 e.printStackTrace();
2343 void dumpImpl(PrintWriter pw, DumpFilter filter) {
2344 pw.print("Current Notification Manager state");
2345 if (filter.filtered) {
2346 pw.print(" (filtered to "); pw.print(filter); pw.print(")");
2350 final boolean zenOnly = filter.filtered && filter.zen;
2353 synchronized (mToastQueue) {
2354 N = mToastQueue.size();
2356 pw.println(" Toast Queue:");
2357 for (int i=0; i<N; i++) {
2358 mToastQueue.get(i).dump(pw, " ", filter);
2365 synchronized (mNotificationList) {
2367 N = mNotificationList.size();
2369 pw.println(" Notification List:");
2370 for (int i=0; i<N; i++) {
2371 final NotificationRecord nr = mNotificationList.get(i);
2372 if (filter.filtered && !filter.matches(nr.sbn)) continue;
2373 nr.dump(pw, " ", getContext(), filter.redact);
2378 if (!filter.filtered) {
2381 pw.println(" Lights List:");
2382 for (int i=0; i<N; i++) {
2388 pw.println(mLights.get(i));
2392 pw.println(" mUseAttentionLight=" + mUseAttentionLight);
2393 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled);
2394 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey);
2395 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey);
2396 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects);
2397 pw.println(" mCallState=" + callStateToString(mCallState));
2398 pw.println(" mSystemReady=" + mSystemReady);
2399 pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
2401 pw.println(" mArchive=" + mArchive.toString());
2402 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
2404 while (iter.hasNext()) {
2405 final StatusBarNotification sbn = iter.next();
2406 if (filter != null && !filter.matches(sbn)) continue;
2407 pw.println(" " + sbn);
2409 if (iter.hasNext()) pw.println(" ...");
2416 pw.println("\n Usage Stats:");
2417 mUsageStats.dump(pw, " ", filter);
2420 if (!filter.filtered || zenOnly) {
2421 pw.println("\n Zen Mode:");
2422 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter);
2423 mZenModeHelper.dump(pw, " ");
2425 pw.println("\n Zen Log:");
2426 ZenLog.dump(pw, " ");
2430 pw.println("\n Ranking Config:");
2431 mRankingHelper.dump(pw, " ", filter);
2433 pw.println("\n Notification listeners:");
2434 mListeners.dump(pw, filter);
2435 pw.print(" mListenerHints: "); pw.println(mListenerHints);
2436 pw.print(" mListenersDisablingEffects: (");
2437 N = mListenersDisablingEffects.size();
2438 for (int i = 0; i < N; i++) {
2439 final int hint = mListenersDisablingEffects.keyAt(i);
2440 if (i > 0) pw.print(';');
2441 pw.print("hint[" + hint + "]:");
2443 final ArraySet<ManagedServiceInfo> listeners =
2444 mListenersDisablingEffects.valueAt(i);
2445 final int listenerSize = listeners.size();
2447 for (int j = 0; j < listenerSize; j++) {
2448 if (i > 0) pw.print(',');
2449 final ManagedServiceInfo listener = listeners.valueAt(i);
2450 pw.print(listener.component);
2454 pw.println("\n mRankerServicePackageName: " + mRankerServicePackageName);
2455 pw.println("\n Notification ranker services:");
2456 mRankerServices.dump(pw, filter);
2458 pw.println("\n Policy access:");
2459 pw.print(" mPolicyAccess: "); pw.println(mPolicyAccess);
2461 pw.println("\n Condition providers:");
2462 mConditionProviders.dump(pw, filter);
2464 pw.println("\n Group summaries:");
2465 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
2466 NotificationRecord r = entry.getValue();
2467 pw.println(" " + entry.getKey() + " -> " + r.getKey());
2468 if (mNotificationsByKey.get(r.getKey()) != r) {
2469 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
2470 r.dump(pw, " ", getContext(), filter.redact);
2477 * The private API only accessible to the system process.
2479 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
2481 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
2482 String tag, int id, Notification notification, int[] idReceived, int userId) {
2483 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
2484 idReceived, userId);
2488 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
2490 checkCallerIsSystem();
2491 synchronized (mNotificationList) {
2492 int i = indexOfNotificationLocked(pkg, null, notificationId, userId);
2494 Log.d(TAG, "stripForegroundServiceFlag: Could not find notification with "
2495 + "pkg=" + pkg + " / id=" + notificationId + " / userId=" + userId);
2498 NotificationRecord r = mNotificationList.get(i);
2499 StatusBarNotification sbn = r.sbn;
2500 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
2501 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove FLAG_FOREGROUND_SERVICE,
2502 // we have to revert to the flags we received initially *and* force remove
2503 // FLAG_FOREGROUND_SERVICE.
2504 sbn.getNotification().flags =
2505 (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
2506 mRankingHelper.sort(mNotificationList);
2507 mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
2512 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
2513 final int callingPid, final String tag, final int id, final Notification notification,
2514 int[] idOut, int incomingUserId) {
2516 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
2517 + " notification=" + notification);
2519 checkCallerIsSystemOrSameApp(pkg);
2520 final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg));
2521 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
2523 final int userId = ActivityManager.handleIncomingUser(callingPid,
2524 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
2525 final UserHandle user = new UserHandle(userId);
2527 // Fix the notification as best we can.
2529 final ApplicationInfo ai = getContext().getPackageManager().getApplicationInfoAsUser(
2530 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
2531 (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
2532 Notification.addFieldsFromContext(ai, userId, notification);
2533 } catch (NameNotFoundException e) {
2534 Slog.e(TAG, "Cannot create a context for sending app", e);
2538 mUsageStats.registerEnqueuedByApp(pkg);
2540 // Limit the number of notifications that any given package except the android
2541 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
2542 if (!isSystemNotification && !isNotificationFromListener) {
2543 synchronized (mNotificationList) {
2544 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
2545 if (appEnqueueRate > mMaxPackageEnqueueRate) {
2546 mUsageStats.registerOverRateQuota(pkg);
2547 final long now = SystemClock.elapsedRealtime();
2548 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
2549 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
2550 + ". Shedding events. package=" + pkg);
2551 mLastOverRateLogTime = now;
2557 final int N = mNotificationList.size();
2558 for (int i=0; i<N; i++) {
2559 final NotificationRecord r = mNotificationList.get(i);
2560 if (r.sbn.getPackageName().equals(pkg) && r.sbn.getUserId() == userId) {
2561 if (r.sbn.getId() == id && TextUtils.equals(r.sbn.getTag(), tag)) {
2562 break; // Allow updating existing notification
2565 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
2566 mUsageStats.registerOverCountQuota(pkg);
2567 Slog.e(TAG, "Package has already posted " + count
2568 + " notifications. Not showing more. package=" + pkg);
2576 if (pkg == null || notification == null) {
2577 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
2578 + " id=" + id + " notification=" + notification);
2581 // Whitelist pending intents.
2582 if (notification.allPendingIntents != null) {
2583 final int intentCount = notification.allPendingIntents.size();
2584 if (intentCount > 0) {
2585 final ActivityManagerInternal am = LocalServices
2586 .getService(ActivityManagerInternal.class);
2587 final long duration = LocalServices.getService(
2588 DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
2589 for (int i = 0; i < intentCount; i++) {
2590 PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
2591 if (pendingIntent != null) {
2592 am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(), duration);
2599 notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN,
2600 Notification.PRIORITY_MAX);
2602 // setup local book-keeping
2603 final StatusBarNotification n = new StatusBarNotification(
2604 pkg, opPkg, id, tag, callingUid, callingPid, 0, notification,
2606 final NotificationRecord r = new NotificationRecord(getContext(), n);
2607 mHandler.post(new EnqueueNotificationRunnable(userId, r));
2612 private class EnqueueNotificationRunnable implements Runnable {
2613 private final NotificationRecord r;
2614 private final int userId;
2616 EnqueueNotificationRunnable(int userId, NotificationRecord r) {
2617 this.userId = userId;
2624 synchronized (mNotificationList) {
2625 final StatusBarNotification n = r.sbn;
2626 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
2627 NotificationRecord old = mNotificationsByKey.get(n.getKey());
2629 // Retain ranking information from previous record
2630 r.copyRankingInformation(old);
2633 final int callingUid = n.getUid();
2634 final int callingPid = n.getInitialPid();
2635 final Notification notification = n.getNotification();
2636 final String pkg = n.getPackageName();
2637 final int id = n.getId();
2638 final String tag = n.getTag();
2639 final boolean isSystemNotification = isUidSystem(callingUid) ||
2640 ("android".equals(pkg));
2642 // Handle grouped notifications and bail out early if we
2643 // can to avoid extracting signals.
2644 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
2646 // This conditional is a dirty hack to limit the logging done on
2647 // behalf of the download manager without affecting other apps.
2648 if (!pkg.equals("com.android.providers.downloads")
2649 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
2650 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
2652 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
2654 EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
2655 pkg, id, tag, userId, notification.toString(),
2659 mRankingHelper.extractSignals(r);
2661 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
2664 if (r.getImportance() == NotificationListenerService.Ranking.IMPORTANCE_NONE
2665 || !noteNotificationOp(pkg, callingUid) || isPackageSuspended) {
2666 if (!isSystemNotification) {
2667 if (isPackageSuspended) {
2668 Slog.e(TAG, "Suppressing notification from package due to package "
2669 + "suspended by administrator.");
2670 mUsageStats.registerSuspendedByAdmin(r);
2672 Slog.e(TAG, "Suppressing notification from package by user request.");
2673 mUsageStats.registerBlocked(r);
2679 // tell the ranker service about the notification
2680 if (mRankerServices.isEnabled()) {
2681 mRankerServices.onNotificationEnqueued(r);
2682 // TODO delay the code below here for 100ms or until there is an answer
2686 int index = indexOfNotificationLocked(n.getKey());
2688 mNotificationList.add(r);
2689 mUsageStats.registerPostedByApp(r);
2691 old = mNotificationList.get(index);
2692 mNotificationList.set(index, r);
2693 mUsageStats.registerUpdatedByApp(r, old);
2694 // Make sure we don't lose the foreground service state.
2695 notification.flags |=
2696 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
2700 mNotificationsByKey.put(n.getKey(), r);
2702 // Ensure if this is a foreground service that the proper additional
2704 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
2705 notification.flags |= Notification.FLAG_ONGOING_EVENT
2706 | Notification.FLAG_NO_CLEAR;
2709 applyZenModeLocked(r);
2710 mRankingHelper.sort(mNotificationList);
2712 if (notification.getSmallIcon() != null) {
2713 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
2714 mListeners.notifyPostedLocked(n, oldSbn);
2716 Slog.e(TAG, "Not posting notification without small icon: " + notification);
2717 if (old != null && !old.isCanceled) {
2718 mListeners.notifyRemovedLocked(n);
2720 // ATTENTION: in a future release we will bail out here
2721 // so that we do not play sounds, show lights, etc. for invalid
2723 Slog.e(TAG, "WARNING: In a future release this will crash the app: "
2724 + n.getPackageName());
2727 buzzBeepBlinkLocked(r);
2733 * Ensures that grouped notification receive their special treatment.
2735 * <p>Cancels group children if the new notification causes a group to lose
2738 * <p>Updates mSummaryByGroupKey.</p>
2740 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
2741 int callingUid, int callingPid) {
2742 StatusBarNotification sbn = r.sbn;
2743 Notification n = sbn.getNotification();
2744 if (n.isGroupSummary() && !sbn.isAppGroup()) {
2745 // notifications without a group shouldn't be a summary, otherwise autobundling can
2747 n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
2750 String group = sbn.getGroupKey();
2751 boolean isSummary = n.isGroupSummary();
2753 Notification oldN = old != null ? old.sbn.getNotification() : null;
2754 String oldGroup = old != null ? old.sbn.getGroupKey() : null;
2755 boolean oldIsSummary = old != null && oldN.isGroupSummary();
2758 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
2759 if (removedSummary != old) {
2761 removedSummary != null ? removedSummary.getKey() : "<null>";
2762 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
2763 ", removed=" + removedKey);
2767 mSummaryByGroupKey.put(group, r);
2770 // Clear out group children of the old notification if the update
2771 // causes the group summary to go away. This happens when the old
2772 // notification was a summary and the new one isn't, or when the old
2773 // notification was a summary and its group key changed.
2774 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
2775 cancelGroupChildrenLocked(old, callingUid, callingPid, null,
2776 REASON_GROUP_SUMMARY_CANCELED, false /* sendDelete */);
2781 void buzzBeepBlinkLocked(NotificationRecord record) {
2782 boolean buzz = false;
2783 boolean beep = false;
2784 boolean blink = false;
2786 final Notification notification = record.sbn.getNotification();
2787 final String key = record.getKey();
2789 // Should this notification make noise, vibe, or use the LED?
2790 final boolean aboveThreshold = record.getImportance() >= IMPORTANCE_DEFAULT;
2791 final boolean canInterrupt = aboveThreshold && !record.isIntercepted();
2792 if (DBG || record.isIntercepted())
2794 "pkg=" + record.sbn.getPackageName() + " canInterrupt=" + canInterrupt +
2795 " intercept=" + record.isIntercepted()
2798 final int currentUser;
2799 final long token = Binder.clearCallingIdentity();
2801 currentUser = ActivityManager.getCurrentUser();
2803 Binder.restoreCallingIdentity(token);
2806 // If we're not supposed to beep, vibrate, etc. then don't.
2807 final String disableEffects = disableNotificationEffects(record);
2808 if (disableEffects != null) {
2809 ZenLog.traceDisableEffects(record, disableEffects);
2812 // Remember if this notification already owns the notification channels.
2813 boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
2814 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
2816 // These are set inside the conditional if the notification is allowed to make noise.
2817 boolean hasValidVibrate = false;
2818 boolean hasValidSound = false;
2819 if (disableEffects == null
2820 && (record.getUserId() == UserHandle.USER_ALL ||
2821 record.getUserId() == currentUser ||
2822 mUserProfiles.isCurrentProfile(record.getUserId()))
2825 && mAudioManager != null) {
2826 if (DBG) Slog.v(TAG, "Interrupting!");
2828 // should we use the default notification sound? (indicated either by
2829 // DEFAULT_SOUND or because notification.sound is pointing at
2830 // Settings.System.NOTIFICATION_SOUND)
2831 final boolean useDefaultSound =
2832 (notification.defaults & Notification.DEFAULT_SOUND) != 0 ||
2833 Settings.System.DEFAULT_NOTIFICATION_URI
2834 .equals(notification.sound);
2836 Uri soundUri = null;
2837 if (useDefaultSound) {
2838 soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
2840 // check to see if the default notification sound is silent
2841 hasValidSound = mSystemNotificationSound != null;
2842 } else if (notification.sound != null) {
2843 soundUri = notification.sound;
2844 hasValidSound = (soundUri != null);
2847 // Does the notification want to specify its own vibration?
2848 final boolean hasCustomVibrate = notification.vibrate != null;
2850 // new in 4.2: if there was supposed to be a sound and we're in vibrate
2851 // mode, and no other vibration is specified, we fall back to vibration
2852 final boolean convertSoundToVibration =
2855 && (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE);
2857 // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
2858 final boolean useDefaultVibrate =
2859 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
2861 hasValidVibrate = useDefaultVibrate || convertSoundToVibration ||
2864 // We can alert, and we're allowed to alert, but if the developer asked us to only do
2865 // it once, and we already have, then don't.
2866 if (!(record.isUpdate
2867 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0)) {
2869 sendAccessibilityEvent(notification, record.sbn.getPackageName());
2871 if (hasValidSound) {
2873 (notification.flags & Notification.FLAG_INSISTENT) != 0;
2874 AudioAttributes audioAttributes = audioAttributesForNotification(notification);
2875 mSoundNotificationKey = key;
2876 // do not play notifications if stream volume is 0 (typically because
2877 // ringer mode is silent) or if there is a user of exclusive audio focus
2878 if ((mAudioManager.getStreamVolume(
2879 AudioAttributes.toLegacyStreamType(audioAttributes)) != 0)
2880 && !mAudioManager.isAudioFocusExclusive()) {
2881 final long identity = Binder.clearCallingIdentity();
2883 final IRingtonePlayer player =
2884 mAudioManager.getRingtonePlayer();
2885 if (player != null) {
2886 if (DBG) Slog.v(TAG, "Playing sound " + soundUri
2887 + " with attributes " + audioAttributes);
2888 player.playAsync(soundUri, record.sbn.getUser(), looping,
2892 } catch (RemoteException e) {
2894 Binder.restoreCallingIdentity(identity);
2899 if (hasValidVibrate && !(mAudioManager.getRingerModeInternal()
2900 == AudioManager.RINGER_MODE_SILENT)) {
2901 mVibrateNotificationKey = key;
2903 if (useDefaultVibrate || convertSoundToVibration) {
2904 // Escalate privileges so we can use the vibrator even if the
2905 // notifying app does not have the VIBRATE permission.
2906 long identity = Binder.clearCallingIdentity();
2908 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
2909 useDefaultVibrate ? mDefaultVibrationPattern
2910 : mFallbackVibrationPattern,
2911 ((notification.flags & Notification.FLAG_INSISTENT) != 0)
2912 ? 0: -1, audioAttributesForNotification(notification));
2915 Binder.restoreCallingIdentity(identity);
2917 } else if (notification.vibrate.length > 1) {
2918 // If you want your own vibration pattern, you need the VIBRATE
2920 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
2921 notification.vibrate,
2922 ((notification.flags & Notification.FLAG_INSISTENT) != 0)
2923 ? 0: -1, audioAttributesForNotification(notification));
2930 // If a notification is updated to remove the actively playing sound or vibrate,
2931 // cancel that feedback now
2932 if (wasBeep && !hasValidSound) {
2935 if (wasBuzz && !hasValidVibrate) {
2936 clearVibrateLocked();
2940 // release the light
2941 boolean wasShowLights = mLights.remove(key);
2942 if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold
2943 && ((record.getSuppressedVisualEffects()
2944 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
2946 updateLightsLocked();
2947 if (mUseAttentionLight) {
2948 mAttentionLight.pulse();
2951 } else if (wasShowLights) {
2952 updateLightsLocked();
2954 if (buzz || beep || blink) {
2955 if (((record.getSuppressedVisualEffects()
2956 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) != 0)) {
2957 if (DBG) Slog.v(TAG, "Suppressed SystemUI from triggering screen on");
2959 EventLogTags.writeNotificationAlert(key,
2960 buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
2961 mHandler.post(mBuzzBeepBlinked);
2966 private static AudioAttributes audioAttributesForNotification(Notification n) {
2967 if (n.audioAttributes != null
2968 && !Notification.AUDIO_ATTRIBUTES_DEFAULT.equals(n.audioAttributes)) {
2969 // the audio attributes are set and different from the default, use them
2970 return n.audioAttributes;
2971 } else if (n.audioStreamType >= 0 && n.audioStreamType < AudioSystem.getNumStreamTypes()) {
2972 // the stream type is valid, use it
2973 return new AudioAttributes.Builder()
2974 .setInternalLegacyStreamType(n.audioStreamType)
2976 } else if (n.audioStreamType == AudioSystem.STREAM_DEFAULT) {
2977 return Notification.AUDIO_ATTRIBUTES_DEFAULT;
2979 Log.w(TAG, String.format("Invalid stream type: %d", n.audioStreamType));
2980 return Notification.AUDIO_ATTRIBUTES_DEFAULT;
2984 void showNextToastLocked() {
2985 ToastRecord record = mToastQueue.get(0);
2986 while (record != null) {
2987 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
2989 record.callback.show();
2990 scheduleTimeoutLocked(record);
2992 } catch (RemoteException e) {
2993 Slog.w(TAG, "Object died trying to show notification " + record.callback
2994 + " in package " + record.pkg);
2995 // remove it from the list and let the process die
2996 int index = mToastQueue.indexOf(record);
2998 mToastQueue.remove(index);
3000 keepProcessAliveLocked(record.pid);
3001 if (mToastQueue.size() > 0) {
3002 record = mToastQueue.get(0);
3010 void cancelToastLocked(int index) {
3011 ToastRecord record = mToastQueue.get(index);
3013 record.callback.hide();
3014 } catch (RemoteException e) {
3015 Slog.w(TAG, "Object died trying to hide notification " + record.callback
3016 + " in package " + record.pkg);
3017 // don't worry about this, we're about to remove it from
3020 mToastQueue.remove(index);
3021 keepProcessAliveLocked(record.pid);
3022 if (mToastQueue.size() > 0) {
3023 // Show the next one. If the callback fails, this will remove
3024 // it from the list, so don't assume that the list hasn't changed
3025 // after this point.
3026 showNextToastLocked();
3030 private void scheduleTimeoutLocked(ToastRecord r)
3032 mHandler.removeCallbacksAndMessages(r);
3033 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
3034 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
3035 mHandler.sendMessageDelayed(m, delay);
3038 private void handleTimeout(ToastRecord record)
3040 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
3041 synchronized (mToastQueue) {
3042 int index = indexOfToastLocked(record.pkg, record.callback);
3044 cancelToastLocked(index);
3049 // lock on mToastQueue
3050 int indexOfToastLocked(String pkg, ITransientNotification callback)
3052 IBinder cbak = callback.asBinder();
3053 ArrayList<ToastRecord> list = mToastQueue;
3054 int len = list.size();
3055 for (int i=0; i<len; i++) {
3056 ToastRecord r = list.get(i);
3057 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
3064 // lock on mToastQueue
3065 void keepProcessAliveLocked(int pid)
3067 int toastCount = 0; // toasts from this pid
3068 ArrayList<ToastRecord> list = mToastQueue;
3069 int N = list.size();
3070 for (int i=0; i<N; i++) {
3071 ToastRecord r = list.get(i);
3077 mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
3078 } catch (RemoteException e) {
3079 // Shouldn't happen.
3083 private void handleRankingReconsideration(Message message) {
3084 if (!(message.obj instanceof RankingReconsideration)) return;
3085 RankingReconsideration recon = (RankingReconsideration) message.obj;
3088 synchronized (mNotificationList) {
3089 final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
3090 if (record == null) {
3093 int indexBefore = findNotificationRecordIndexLocked(record);
3094 boolean interceptBefore = record.isIntercepted();
3095 int visibilityBefore = record.getPackageVisibilityOverride();
3096 recon.applyChangesLocked(record);
3097 applyZenModeLocked(record);
3098 mRankingHelper.sort(mNotificationList);
3099 int indexAfter = findNotificationRecordIndexLocked(record);
3100 boolean interceptAfter = record.isIntercepted();
3101 int visibilityAfter = record.getPackageVisibilityOverride();
3102 changed = indexBefore != indexAfter || interceptBefore != interceptAfter
3103 || visibilityBefore != visibilityAfter;
3104 if (interceptBefore && !interceptAfter) {
3105 buzzBeepBlinkLocked(record);
3109 scheduleSendRankingUpdate();
3113 private void handleRankingSort() {
3114 synchronized (mNotificationList) {
3115 final int N = mNotificationList.size();
3116 ArrayList<String> orderBefore = new ArrayList<String>(N);
3117 ArrayList<String> groupOverrideBefore = new ArrayList<>(N);
3118 int[] visibilities = new int[N];
3119 int[] importances = new int[N];
3120 for (int i = 0; i < N; i++) {
3121 final NotificationRecord r = mNotificationList.get(i);
3122 orderBefore.add(r.getKey());
3123 groupOverrideBefore.add(r.sbn.getGroupKey());
3124 visibilities[i] = r.getPackageVisibilityOverride();
3125 importances[i] = r.getImportance();
3126 mRankingHelper.extractSignals(r);
3128 mRankingHelper.sort(mNotificationList);
3129 for (int i = 0; i < N; i++) {
3130 final NotificationRecord r = mNotificationList.get(i);
3131 if (!orderBefore.get(i).equals(r.getKey())
3132 || visibilities[i] != r.getPackageVisibilityOverride()
3133 || importances[i] != r.getImportance()
3134 || !groupOverrideBefore.get(i).equals(r.sbn.getGroupKey())) {
3135 scheduleSendRankingUpdate();
3142 // let zen mode evaluate this record
3143 private void applyZenModeLocked(NotificationRecord record) {
3144 record.setIntercepted(mZenModeHelper.shouldIntercept(record));
3145 if (record.isIntercepted()) {
3146 int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
3147 ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
3148 | (mZenModeHelper.shouldSuppressWhenScreenOn()
3149 ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
3150 record.setSuppressedVisualEffects(suppressed);
3154 // lock on mNotificationList
3155 private int findNotificationRecordIndexLocked(NotificationRecord target) {
3156 return mRankingHelper.indexOf(mNotificationList, target);
3159 private void scheduleSendRankingUpdate() {
3160 if (!mHandler.hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
3161 Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE);
3162 mHandler.sendMessage(m);
3166 private void handleSendRankingUpdate() {
3167 synchronized (mNotificationList) {
3168 mListeners.notifyRankingUpdateLocked();
3172 private void scheduleListenerHintsChanged(int state) {
3173 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
3174 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
3177 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
3178 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
3179 mHandler.obtainMessage(
3180 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
3181 listenerInterruptionFilter,
3185 private void handleListenerHintsChanged(int hints) {
3186 synchronized (mNotificationList) {
3187 mListeners.notifyListenerHintsChangedLocked(hints);
3191 private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
3192 synchronized (mNotificationList) {
3193 mListeners.notifyInterruptionFilterChanged(interruptionFilter);
3197 private final class WorkerHandler extends Handler
3200 public void handleMessage(Message msg)
3204 case MESSAGE_TIMEOUT:
3205 handleTimeout((ToastRecord)msg.obj);
3207 case MESSAGE_SAVE_POLICY_FILE:
3208 handleSavePolicyFile();
3210 case MESSAGE_SEND_RANKING_UPDATE:
3211 handleSendRankingUpdate();
3213 case MESSAGE_LISTENER_HINTS_CHANGED:
3214 handleListenerHintsChanged(msg.arg1);
3216 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
3217 handleListenerInterruptionFilterChanged(msg.arg1);
3224 private final class RankingHandlerWorker extends Handler implements RankingHandler
3226 public RankingHandlerWorker(Looper looper) {
3231 public void handleMessage(Message msg) {
3233 case MESSAGE_RECONSIDER_RANKING:
3234 handleRankingReconsideration(msg);
3236 case MESSAGE_RANKING_SORT:
3237 handleRankingSort();
3242 public void requestSort() {
3243 removeMessages(MESSAGE_RANKING_SORT);
3244 sendEmptyMessage(MESSAGE_RANKING_SORT);
3247 public void requestReconsideration(RankingReconsideration recon) {
3248 Message m = Message.obtain(this,
3249 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
3250 long delay = recon.getDelay(TimeUnit.MILLISECONDS);
3251 sendMessageDelayed(m, delay);
3256 // ============================================================================
3257 static int clamp(int x, int low, int high) {
3258 return (x < low) ? low : ((x > high) ? high : x);
3261 void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
3262 AccessibilityManager manager = AccessibilityManager.getInstance(getContext());
3263 if (!manager.isEnabled()) {
3267 AccessibilityEvent event =
3268 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
3269 event.setPackageName(packageName);
3270 event.setClassName(Notification.class.getName());
3271 event.setParcelableData(notification);
3272 CharSequence tickerText = notification.tickerText;
3273 if (!TextUtils.isEmpty(tickerText)) {
3274 event.getText().add(tickerText);
3277 manager.sendAccessibilityEvent(event);
3280 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) {
3283 if (r.getNotification().deleteIntent != null) {
3285 r.getNotification().deleteIntent.send();
3286 } catch (PendingIntent.CanceledException ex) {
3287 // do nothing - there's no relevant way to recover, and
3288 // no reason to let this propagate
3289 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
3295 if (r.getNotification().getSmallIcon() != null) {
3296 r.isCanceled = true;
3297 mListeners.notifyRemovedLocked(r.sbn);
3300 final String canceledKey = r.getKey();
3303 if (canceledKey.equals(mSoundNotificationKey)) {
3304 mSoundNotificationKey = null;
3305 final long identity = Binder.clearCallingIdentity();
3307 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
3308 if (player != null) {
3311 } catch (RemoteException e) {
3313 Binder.restoreCallingIdentity(identity);
3318 if (canceledKey.equals(mVibrateNotificationKey)) {
3319 mVibrateNotificationKey = null;
3320 long identity = Binder.clearCallingIdentity();
3325 Binder.restoreCallingIdentity(identity);
3330 mLights.remove(canceledKey);
3332 // Record usage stats
3333 // TODO: add unbundling stats?
3335 case REASON_DELEGATE_CANCEL:
3336 case REASON_DELEGATE_CANCEL_ALL:
3337 case REASON_LISTENER_CANCEL:
3338 case REASON_LISTENER_CANCEL_ALL:
3339 mUsageStats.registerDismissedByUser(r);
3341 case REASON_APP_CANCEL:
3342 case REASON_APP_CANCEL_ALL:
3343 mUsageStats.registerRemovedByApp(r);
3347 mNotificationsByKey.remove(r.sbn.getKey());
3348 String groupKey = r.getGroupKey();
3349 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
3350 if (groupSummary != null && groupSummary.getKey().equals(r.getKey())) {
3351 mSummaryByGroupKey.remove(groupKey);
3353 final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
3354 if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
3355 summaries.remove(r.sbn.getPackageName());
3358 // Save it for users of getHistoricalNotifications()
3359 mArchive.record(r.sbn);
3361 final long now = System.currentTimeMillis();
3362 EventLogTags.writeNotificationCanceled(canceledKey, reason,
3363 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
3367 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
3368 * and none of the {@code mustNotHaveFlags}.
3370 void cancelNotification(final int callingUid, final int callingPid,
3371 final String pkg, final String tag, final int id,
3372 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
3373 final int userId, final int reason, final ManagedServiceInfo listener) {
3374 // In enqueueNotificationInternal notifications are added by scheduling the
3375 // work on the worker handler. Hence, we also schedule the cancel on this
3376 // handler to avoid a scenario where an add notification call followed by a
3377 // remove notification call ends up in not removing the notification.
3378 mHandler.post(new Runnable() {
3381 String listenerName = listener == null ? null : listener.component.toShortString();
3382 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
3383 userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
3385 synchronized (mNotificationList) {
3386 int index = indexOfNotificationLocked(pkg, tag, id, userId);
3388 NotificationRecord r = mNotificationList.get(index);
3390 // Ideally we'd do this in the caller of this method. However, that would
3391 // require the caller to also find the notification.
3392 if (reason == REASON_DELEGATE_CLICK) {
3393 mUsageStats.registerClickedByUser(r);
3396 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
3399 if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
3403 mNotificationList.remove(index);
3405 cancelNotificationLocked(r, sendDelete, reason);
3406 cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
3407 REASON_GROUP_SUMMARY_CANCELED, sendDelete);
3408 updateLightsLocked();
3416 * Determine whether the userId applies to the notification in question, either because
3417 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
3419 private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
3421 // looking for USER_ALL notifications? match everything
3422 userId == UserHandle.USER_ALL
3423 // a notification sent to USER_ALL matches any query
3424 || r.getUserId() == UserHandle.USER_ALL
3425 // an exact user match
3426 || r.getUserId() == userId;
3430 * Determine whether the userId applies to the notification in question, either because
3431 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
3432 * because it matches one of the users profiles.
3434 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
3435 return notificationMatchesUserId(r, userId)
3436 || mUserProfiles.isCurrentProfile(r.getUserId());
3440 * Cancels all notifications from a given package that have all of the
3441 * {@code mustHaveFlags}.
3443 boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags,
3444 int mustNotHaveFlags, boolean doit, int userId, int reason,
3445 ManagedServiceInfo listener) {
3446 String listenerName = listener == null ? null : listener.component.toShortString();
3447 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
3448 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
3451 synchronized (mNotificationList) {
3452 final int N = mNotificationList.size();
3453 ArrayList<NotificationRecord> canceledNotifications = null;
3454 for (int i = N-1; i >= 0; --i) {
3455 NotificationRecord r = mNotificationList.get(i);
3456 if (!notificationMatchesUserId(r, userId)) {
3459 // Don't remove notifications to all, if there's no package name specified
3460 if (r.getUserId() == UserHandle.USER_ALL && pkg == null) {
3463 if ((r.getFlags() & mustHaveFlags) != mustHaveFlags) {
3466 if ((r.getFlags() & mustNotHaveFlags) != 0) {
3469 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
3472 if (canceledNotifications == null) {
3473 canceledNotifications = new ArrayList<>();
3475 canceledNotifications.add(r);
3479 mNotificationList.remove(i);
3480 cancelNotificationLocked(r, false, reason);
3482 if (doit && canceledNotifications != null) {
3483 final int M = canceledNotifications.size();
3484 for (int i = 0; i < M; i++) {
3485 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
3486 listenerName, REASON_GROUP_SUMMARY_CANCELED, false /* sendDelete */);
3489 if (canceledNotifications != null) {
3490 updateLightsLocked();
3492 return canceledNotifications != null;
3496 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
3497 ManagedServiceInfo listener, boolean includeCurrentProfiles) {
3498 String listenerName = listener == null ? null : listener.component.toShortString();
3499 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
3500 null, userId, 0, 0, reason, listenerName);
3502 ArrayList<NotificationRecord> canceledNotifications = null;
3503 final int N = mNotificationList.size();
3504 for (int i=N-1; i>=0; i--) {
3505 NotificationRecord r = mNotificationList.get(i);
3506 if (includeCurrentProfiles) {
3507 if (!notificationMatchesCurrentProfiles(r, userId)) {
3511 if (!notificationMatchesUserId(r, userId)) {
3516 if ((r.getFlags() & (Notification.FLAG_ONGOING_EVENT
3517 | Notification.FLAG_NO_CLEAR)) == 0) {
3518 mNotificationList.remove(i);
3519 cancelNotificationLocked(r, true, reason);
3520 // Make a note so we can cancel children later.
3521 if (canceledNotifications == null) {
3522 canceledNotifications = new ArrayList<>();
3524 canceledNotifications.add(r);
3527 int M = canceledNotifications != null ? canceledNotifications.size() : 0;
3528 for (int i = 0; i < M; i++) {
3529 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
3530 listenerName, REASON_GROUP_SUMMARY_CANCELED, false /* sendDelete */);
3532 updateLightsLocked();
3535 // Warning: The caller is responsible for invoking updateLightsLocked().
3536 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
3537 String listenerName, int reason, boolean sendDelete) {
3538 Notification n = r.getNotification();
3539 if (!n.isGroupSummary()) {
3543 String pkg = r.sbn.getPackageName();
3544 int userId = r.getUserId();
3547 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
3551 final int N = mNotificationList.size();
3552 for (int i = N - 1; i >= 0; i--) {
3553 NotificationRecord childR = mNotificationList.get(i);
3554 StatusBarNotification childSbn = childR.sbn;
3555 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
3556 childR.getGroupKey().equals(r.getGroupKey())) {
3557 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
3558 childSbn.getTag(), userId, 0, 0, reason, listenerName);
3559 mNotificationList.remove(i);
3560 cancelNotificationLocked(childR, sendDelete, reason);
3565 // lock on mNotificationList
3566 void updateLightsLocked()
3568 // handle notification lights
3569 NotificationRecord ledNotification = null;
3570 while (ledNotification == null && !mLights.isEmpty()) {
3571 final String owner = mLights.get(mLights.size() - 1);
3572 ledNotification = mNotificationsByKey.get(owner);
3573 if (ledNotification == null) {
3574 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
3575 mLights.remove(owner);
3579 // Don't flash while we are in a call or screen is on
3580 if (ledNotification == null || mInCall || mScreenOn) {
3581 mNotificationLight.turnOff();
3582 if (mStatusBar != null) {
3583 mStatusBar.notificationLightOff();
3586 final Notification ledno = ledNotification.sbn.getNotification();
3587 int ledARGB = ledno.ledARGB;
3588 int ledOnMS = ledno.ledOnMS;
3589 int ledOffMS = ledno.ledOffMS;
3590 if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0) {
3591 ledARGB = mDefaultNotificationColor;
3592 ledOnMS = mDefaultNotificationLedOn;
3593 ledOffMS = mDefaultNotificationLedOff;
3595 if (mNotificationPulseEnabled) {
3597 mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED,
3600 if (mStatusBar != null) {
3601 // let SystemUI make an independent decision
3602 mStatusBar.notificationLightPulse(ledARGB, ledOnMS, ledOffMS);
3607 // lock on mNotificationList
3608 int indexOfNotificationLocked(String pkg, String tag, int id, int userId)
3610 ArrayList<NotificationRecord> list = mNotificationList;
3611 final int len = list.size();
3612 for (int i=0; i<len; i++) {
3613 NotificationRecord r = list.get(i);
3614 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
3615 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
3622 // lock on mNotificationList
3623 int indexOfNotificationLocked(String key) {
3624 final int N = mNotificationList.size();
3625 for (int i = 0; i < N; i++) {
3626 if (key.equals(mNotificationList.get(i).getKey())) {
3633 private void updateNotificationPulse() {
3634 synchronized (mNotificationList) {
3635 updateLightsLocked();
3639 private static boolean isUidSystem(int uid) {
3640 final int appid = UserHandle.getAppId(uid);
3641 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
3644 private static boolean isCallerSystem() {
3645 return isUidSystem(Binder.getCallingUid());
3648 private static void checkCallerIsSystem() {
3649 if (isCallerSystem()) {
3652 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
3655 private static void checkCallerIsSystemOrSameApp(String pkg) {
3656 if (isCallerSystem()) {
3659 checkCallerIsSameApp(pkg);
3662 private static void checkCallerIsSameApp(String pkg) {
3663 final int uid = Binder.getCallingUid();
3665 ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
3666 pkg, 0, UserHandle.getCallingUserId());
3668 throw new SecurityException("Unknown package " + pkg);
3670 if (!UserHandle.isSameApp(ai.uid, uid)) {
3671 throw new SecurityException("Calling uid " + uid + " gave package"
3672 + pkg + " which is owned by uid " + ai.uid);
3674 } catch (RemoteException re) {
3675 throw new SecurityException("Unknown package " + pkg + "\n" + re);
3679 private static String callStateToString(int state) {
3681 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
3682 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
3683 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
3684 default: return "CALL_STATE_UNKNOWN_" + state;
3688 private void listenForCallState() {
3689 TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
3691 public void onCallStateChanged(int state, String incomingNumber) {
3692 if (mCallState == state) return;
3693 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
3696 }, PhoneStateListener.LISTEN_CALL_STATE);
3700 * Generates a NotificationRankingUpdate from 'sbns', considering only
3701 * notifications visible to the given listener.
3703 * <p>Caller must hold a lock on mNotificationList.</p>
3705 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
3706 final int N = mNotificationList.size();
3707 ArrayList<String> keys = new ArrayList<String>(N);
3708 ArrayList<String> interceptedKeys = new ArrayList<String>(N);
3709 ArrayList<Integer> importance = new ArrayList<>(N);
3710 Bundle overrideGroupKeys = new Bundle();
3711 Bundle visibilityOverrides = new Bundle();
3712 Bundle suppressedVisualEffects = new Bundle();
3713 Bundle explanation = new Bundle();
3714 for (int i = 0; i < N; i++) {
3715 NotificationRecord record = mNotificationList.get(i);
3716 if (!isVisibleToListener(record.sbn, info)) {
3719 final String key = record.sbn.getKey();
3721 importance.add(record.getImportance());
3722 if (record.getImportanceExplanation() != null) {
3723 explanation.putCharSequence(key, record.getImportanceExplanation());
3725 if (record.isIntercepted()) {
3726 interceptedKeys.add(key);
3729 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
3730 if (record.getPackageVisibilityOverride()
3731 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
3732 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
3734 overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
3736 final int M = keys.size();
3737 String[] keysAr = keys.toArray(new String[M]);
3738 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
3739 int[] importanceAr = new int[M];
3740 for (int i = 0; i < M; i++) {
3741 importanceAr[i] = importance.get(i);
3743 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
3744 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys);
3747 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
3748 if (!listener.enabledAndUserMatches(sbn.getUserId())) {
3751 // TODO: remove this for older listeners.
3755 private boolean isPackageSuspendedForUser(String pkg, int uid) {
3756 int userId = UserHandle.getUserId(uid);
3758 return AppGlobals.getPackageManager().isPackageSuspendedForUser(pkg, userId);
3759 } catch (RemoteException re) {
3760 throw new SecurityException("Could not talk to package manager service");
3761 } catch (IllegalArgumentException ex) {
3762 // Package not found.
3767 private class TrimCache {
3768 StatusBarNotification heavy;
3769 StatusBarNotification sbnClone;
3770 StatusBarNotification sbnCloneLight;
3772 TrimCache(StatusBarNotification sbn) {
3776 StatusBarNotification ForListener(ManagedServiceInfo info) {
3777 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
3778 if (sbnCloneLight == null) {
3779 sbnCloneLight = heavy.cloneLight();
3781 return sbnCloneLight;
3783 if (sbnClone == null) {
3784 sbnClone = heavy.clone();
3791 public class NotificationRankers extends ManagedServices {
3793 public NotificationRankers() {
3794 super(getContext(), mHandler, mNotificationList, mUserProfiles);
3798 protected Config getConfig() {
3799 Config c = new Config();
3800 c.caption = "notification ranker service";
3801 c.serviceInterface = NotificationRankerService.SERVICE_INTERFACE;
3802 c.secureSettingName = null;
3803 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_RANKER_SERVICE;
3804 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
3805 c.clientLabel = R.string.notification_ranker_binding_label;
3810 protected IInterface asInterface(IBinder binder) {
3811 return INotificationListener.Stub.asInterface(binder);
3815 protected boolean checkType(IInterface service) {
3816 return service instanceof INotificationListener;
3820 protected void onServiceAdded(ManagedServiceInfo info) {
3821 mListeners.registerGuestService(info);
3825 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
3826 mListeners.unregisterService(removed.service, removed.userid);
3829 public void onNotificationEnqueued(final NotificationRecord r) {
3830 final StatusBarNotification sbn = r.sbn;
3831 TrimCache trimCache = new TrimCache(sbn);
3833 // mServices is the list inside ManagedServices of all the rankers,
3834 // There should be only one, but it's a list, so while we enforce
3835 // singularity elsewhere, we keep it general here, to avoid surprises.
3836 for (final ManagedServiceInfo info : NotificationRankers.this.mServices) {
3837 boolean sbnVisible = isVisibleToListener(sbn, info);
3842 final int importance = r.getImportance();
3843 final boolean fromUser = r.isImportanceFromUser();
3844 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
3845 mHandler.post(new Runnable() {
3848 notifyEnqueued(info, sbnToPost, importance, fromUser);
3854 private void notifyEnqueued(final ManagedServiceInfo info,
3855 final StatusBarNotification sbn, int importance, boolean fromUser) {
3856 final INotificationListener ranker = (INotificationListener) info.service;
3857 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
3859 ranker.onNotificationEnqueued(sbnHolder, importance, fromUser);
3860 } catch (RemoteException ex) {
3861 Log.e(TAG, "unable to notify ranker (enqueued): " + ranker, ex);
3865 public boolean isEnabled() {
3866 return !mServices.isEmpty();
3870 public void onUserSwitched(int user) {
3871 synchronized (mNotificationList) {
3872 int i = mServices.size()-1;
3874 final ManagedServiceInfo info = mServices.get(i);
3875 unregisterService(info.service, info.userid);
3882 public void onPackagesChanged(boolean queryReplace, String[] pkgList) {
3883 if (DEBUG) Slog.d(TAG, "onPackagesChanged queryReplace=" + queryReplace
3884 + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList)));
3885 if (mRankerServicePackageName == null) {
3889 if (pkgList != null && (pkgList.length > 0)) {
3890 for (String pkgName : pkgList) {
3891 if (mRankerServicePackageName.equals(pkgName)) {
3898 protected void registerRanker() {
3899 // Find the updatable ranker and register it.
3900 if (mRankerServicePackageName == null) {
3901 Slog.w(TAG, "could not start ranker service: no package specified!");
3904 Set<ComponentName> rankerComponents = queryPackageForServices(
3905 mRankerServicePackageName, UserHandle.USER_SYSTEM);
3906 Iterator<ComponentName> iterator = rankerComponents.iterator();
3907 if (iterator.hasNext()) {
3908 ComponentName rankerComponent = iterator.next();
3909 if (iterator.hasNext()) {
3910 Slog.e(TAG, "found multiple ranker services:" + rankerComponents);
3912 registerSystemService(rankerComponent, UserHandle.USER_SYSTEM);
3915 Slog.w(TAG, "could not start ranker service: none found");
3920 public class NotificationListeners extends ManagedServices {
3922 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
3924 public NotificationListeners() {
3925 super(getContext(), mHandler, mNotificationList, mUserProfiles);
3929 protected Config getConfig() {
3930 Config c = new Config();
3931 c.caption = "notification listener";
3932 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
3933 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
3934 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
3935 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
3936 c.clientLabel = R.string.notification_listener_binding_label;
3941 protected IInterface asInterface(IBinder binder) {
3942 return INotificationListener.Stub.asInterface(binder);
3946 protected boolean checkType(IInterface service) {
3947 return service instanceof INotificationListener;
3951 public void onServiceAdded(ManagedServiceInfo info) {
3952 final INotificationListener listener = (INotificationListener) info.service;
3953 final NotificationRankingUpdate update;
3954 synchronized (mNotificationList) {
3955 update = makeRankingUpdateLocked(info);
3958 listener.onListenerConnected(update);
3959 } catch (RemoteException e) {
3965 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
3966 if (removeDisabledHints(removed)) {
3967 updateListenerHintsLocked();
3968 updateEffectsSuppressorLocked();
3970 mLightTrimListeners.remove(removed);
3973 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
3974 if (trim == TRIM_LIGHT) {
3975 mLightTrimListeners.add(info);
3977 mLightTrimListeners.remove(info);
3981 public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
3982 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
3986 * asynchronously notify all listeners about a new notification
3989 * Also takes care of removing a notification that has been visible to a listener before,
3990 * but isn't anymore.
3992 public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
3993 // Lazily initialized snapshots of the notification.
3994 TrimCache trimCache = new TrimCache(sbn);
3996 for (final ManagedServiceInfo info : mServices) {
3997 boolean sbnVisible = isVisibleToListener(sbn, info);
3998 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
3999 // This notification hasn't been and still isn't visible -> ignore.
4000 if (!oldSbnVisible && !sbnVisible) {
4003 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
4005 // This notification became invisible -> remove the old one.
4006 if (oldSbnVisible && !sbnVisible) {
4007 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
4008 mHandler.post(new Runnable() {
4011 notifyRemoved(info, oldSbnLightClone, update);
4017 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
4018 mHandler.post(new Runnable() {
4021 notifyPosted(info, sbnToPost, update);
4028 * asynchronously notify all listeners about a removed notification
4030 public void notifyRemovedLocked(StatusBarNotification sbn) {
4031 // make a copy in case changes are made to the underlying Notification object
4032 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
4034 final StatusBarNotification sbnLight = sbn.cloneLight();
4035 for (final ManagedServiceInfo info : mServices) {
4036 if (!isVisibleToListener(sbn, info)) {
4039 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
4040 mHandler.post(new Runnable() {
4043 notifyRemoved(info, sbnLight, update);
4050 * asynchronously notify all listeners about a reordering of notifications
4052 public void notifyRankingUpdateLocked() {
4053 for (final ManagedServiceInfo serviceInfo : mServices) {
4054 if (!serviceInfo.isEnabledForCurrentProfiles()) {
4057 final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
4058 mHandler.post(new Runnable() {
4061 notifyRankingUpdate(serviceInfo, update);
4067 public void notifyListenerHintsChangedLocked(final int hints) {
4068 for (final ManagedServiceInfo serviceInfo : mServices) {
4069 if (!serviceInfo.isEnabledForCurrentProfiles()) {
4072 mHandler.post(new Runnable() {
4075 notifyListenerHintsChanged(serviceInfo, hints);
4081 public void notifyInterruptionFilterChanged(final int interruptionFilter) {
4082 for (final ManagedServiceInfo serviceInfo : mServices) {
4083 if (!serviceInfo.isEnabledForCurrentProfiles()) {
4086 mHandler.post(new Runnable() {
4089 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
4095 private void notifyPosted(final ManagedServiceInfo info,
4096 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
4097 final INotificationListener listener = (INotificationListener)info.service;
4098 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
4100 listener.onNotificationPosted(sbnHolder, rankingUpdate);
4101 } catch (RemoteException ex) {
4102 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
4106 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
4107 NotificationRankingUpdate rankingUpdate) {
4108 if (!info.enabledAndUserMatches(sbn.getUserId())) {
4111 final INotificationListener listener = (INotificationListener) info.service;
4112 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
4114 listener.onNotificationRemoved(sbnHolder, rankingUpdate);
4115 } catch (RemoteException ex) {
4116 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
4120 private void notifyRankingUpdate(ManagedServiceInfo info,
4121 NotificationRankingUpdate rankingUpdate) {
4122 final INotificationListener listener = (INotificationListener) info.service;
4124 listener.onNotificationRankingUpdate(rankingUpdate);
4125 } catch (RemoteException ex) {
4126 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
4130 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
4131 final INotificationListener listener = (INotificationListener) info.service;
4133 listener.onListenerHintsChanged(hints);
4134 } catch (RemoteException ex) {
4135 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
4139 private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
4140 int interruptionFilter) {
4141 final INotificationListener listener = (INotificationListener) info.service;
4143 listener.onInterruptionFilterChanged(interruptionFilter);
4144 } catch (RemoteException ex) {
4145 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
4149 private boolean isListenerPackage(String packageName) {
4150 if (packageName == null) {
4153 // TODO: clean up locking object later
4154 synchronized (mNotificationList) {
4155 for (final ManagedServiceInfo serviceInfo : mServices) {
4156 if (packageName.equals(serviceInfo.component.getPackageName())) {
4165 public static final class DumpFilter {
4166 public boolean filtered = false;
4167 public String pkgFilter;
4170 public boolean stats;
4171 public boolean redact = true;
4173 public static DumpFilter parseFromArguments(String[] args) {
4174 final DumpFilter filter = new DumpFilter();
4175 for (int ai = 0; ai < args.length; ai++) {
4176 final String a = args[ai];
4177 if ("--noredact".equals(a) || "--reveal".equals(a)) {
4178 filter.redact = false;
4179 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
4180 if (ai < args.length-1) {
4182 filter.pkgFilter = args[ai].trim().toLowerCase();
4183 if (filter.pkgFilter.isEmpty()) {
4184 filter.pkgFilter = null;
4186 filter.filtered = true;
4189 } else if ("--zen".equals(a) || "zen".equals(a)) {
4190 filter.filtered = true;
4192 } else if ("--stats".equals(a)) {
4193 filter.stats = true;
4194 if (ai < args.length-1) {
4196 filter.since = Long.valueOf(args[ai]);
4205 public boolean matches(StatusBarNotification sbn) {
4206 if (!filtered) return true;
4207 return zen ? true : sbn != null
4208 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
4211 public boolean matches(ComponentName component) {
4212 if (!filtered) return true;
4213 return zen ? true : component != null && matches(component.getPackageName());
4216 public boolean matches(String pkg) {
4217 if (!filtered) return true;
4218 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
4222 public String toString() {
4223 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
4228 * Wrapper for a StatusBarNotification object that allows transfer across a oneway
4229 * binder without sending large amounts of data over a oneway transaction.
4231 private static final class StatusBarNotificationHolder
4232 extends IStatusBarNotificationHolder.Stub {
4233 private StatusBarNotification mValue;
4235 public StatusBarNotificationHolder(StatusBarNotification value) {
4239 /** Get the held value and clear it. This function should only be called once per holder */
4241 public StatusBarNotification get() {
4242 StatusBarNotification value = mValue;
4248 private final class PolicyAccess {
4249 private static final String SEPARATOR = ":";
4250 private final String[] PERM = {
4251 android.Manifest.permission.ACCESS_NOTIFICATION_POLICY
4254 public boolean isPackageGranted(String pkg) {
4255 return pkg != null && getGrantedPackages().contains(pkg);
4258 public void put(String pkg, boolean granted) {
4259 if (pkg == null) return;
4260 final ArraySet<String> pkgs = getGrantedPackages();
4263 changed = pkgs.add(pkg);
4265 changed = pkgs.remove(pkg);
4267 if (!changed) return;
4268 final String setting = TextUtils.join(SEPARATOR, pkgs);
4269 final int currentUser = ActivityManager.getCurrentUser();
4270 Settings.Secure.putStringForUser(getContext().getContentResolver(),
4271 Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
4274 getContext().sendBroadcastAsUser(new Intent(NotificationManager
4275 .ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
4277 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), new UserHandle(currentUser), null);
4280 public ArraySet<String> getGrantedPackages() {
4281 final ArraySet<String> pkgs = new ArraySet<>();
4283 long identity = Binder.clearCallingIdentity();
4285 final String setting = Settings.Secure.getStringForUser(
4286 getContext().getContentResolver(),
4287 Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
4288 ActivityManager.getCurrentUser());
4289 if (setting != null) {
4290 final String[] tokens = setting.split(SEPARATOR);
4291 for (int i = 0; i < tokens.length; i++) {
4292 String token = tokens[i];
4293 if (token != null) {
4294 token = token.trim();
4296 if (TextUtils.isEmpty(token)) {
4303 Binder.restoreCallingIdentity(identity);
4308 public String[] getRequestingPackages() throws RemoteException {
4309 final ParceledListSlice list = AppGlobals.getPackageManager()
4310 .getPackagesHoldingPermissions(PERM, 0 /*flags*/,
4311 ActivityManager.getCurrentUser());
4312 final List<PackageInfo> pkgs = list.getList();
4313 if (pkgs == null || pkgs.isEmpty()) return new String[0];
4314 final int N = pkgs.size();
4315 final String[] rt = new String[N];
4316 for (int i = 0; i < N; i++) {
4317 rt[i] = pkgs.get(i).packageName;