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.StatusBarManager;
62 import android.app.backup.BackupManager;
63 import android.app.usage.UsageEvents;
64 import android.app.usage.UsageStatsManagerInternal;
65 import android.content.BroadcastReceiver;
66 import android.content.ComponentName;
67 import android.content.ContentResolver;
68 import android.content.Context;
69 import android.content.Intent;
70 import android.content.IntentFilter;
71 import android.content.pm.ApplicationInfo;
72 import android.content.pm.IPackageManager;
73 import android.content.pm.PackageInfo;
74 import android.content.pm.PackageManager;
75 import android.content.pm.PackageManager.NameNotFoundException;
76 import android.content.pm.ParceledListSlice;
77 import android.content.pm.UserInfo;
78 import android.content.res.Resources;
79 import android.database.ContentObserver;
80 import android.media.AudioAttributes;
81 import android.media.AudioManager;
82 import android.media.AudioManagerInternal;
83 import android.media.AudioSystem;
84 import android.media.IRingtonePlayer;
85 import android.net.Uri;
86 import android.os.Binder;
87 import android.os.Bundle;
88 import android.os.Environment;
89 import android.os.Handler;
90 import android.os.HandlerThread;
91 import android.os.IBinder;
92 import android.os.IInterface;
93 import android.os.Looper;
94 import android.os.Message;
95 import android.os.Process;
96 import android.os.RemoteException;
97 import android.os.SystemClock;
98 import android.os.SystemProperties;
99 import android.os.UserHandle;
100 import android.os.UserManager;
101 import android.os.Vibrator;
102 import android.provider.Settings;
103 import android.service.notification.Adjustment;
104 import android.service.notification.Condition;
105 import android.service.notification.IConditionProvider;
106 import android.service.notification.INotificationListener;
107 import android.service.notification.IStatusBarNotificationHolder;
108 import android.service.notification.NotificationRankerService;
109 import android.service.notification.NotificationListenerService;
110 import android.service.notification.NotificationRankingUpdate;
111 import android.service.notification.StatusBarNotification;
112 import android.service.notification.ZenModeConfig;
113 import android.telephony.PhoneStateListener;
114 import android.telephony.TelephonyManager;
115 import android.text.TextUtils;
116 import android.util.ArrayMap;
117 import android.util.ArraySet;
118 import android.util.AtomicFile;
119 import android.util.Log;
120 import android.util.Slog;
121 import android.util.SparseArray;
122 import android.util.Xml;
123 import android.view.WindowManager;
124 import android.view.WindowManagerInternal;
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.policy.PhoneWindowManager;
142 import com.android.server.statusbar.StatusBarManagerInternal;
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 = 10f;
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 = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
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 WindowManagerInternal mWindowManagerInternal;
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;
457 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
461 this.callback = callback;
462 this.duration = duration;
466 void update(int duration) {
467 this.duration = duration;
470 void dump(PrintWriter pw, String prefix, DumpFilter filter) {
471 if (filter != null && !filter.matches(pkg)) return;
472 pw.println(prefix + this);
476 public final String toString()
478 return "ToastRecord{"
479 + Integer.toHexString(System.identityHashCode(this))
481 + " callback=" + callback
482 + " duration=" + duration;
486 private final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
489 public void onSetDisabled(int status) {
490 synchronized (mNotificationList) {
491 mDisableNotificationEffects =
492 (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
493 if (disableNotificationEffects(null) != null) {
494 // cancel whatever's going on
495 long identity = Binder.clearCallingIdentity();
497 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
498 if (player != null) {
501 } catch (RemoteException e) {
503 Binder.restoreCallingIdentity(identity);
506 identity = Binder.clearCallingIdentity();
510 Binder.restoreCallingIdentity(identity);
517 public void onClearAll(int callingUid, int callingPid, int userId) {
518 synchronized (mNotificationList) {
519 cancelAllLocked(callingUid, callingPid, userId, REASON_DELEGATE_CANCEL_ALL, null,
520 /*includeCurrentProfiles*/ true);
525 public void onNotificationClick(int callingUid, int callingPid, String key) {
526 synchronized (mNotificationList) {
527 NotificationRecord r = mNotificationsByKey.get(key);
529 Log.w(TAG, "No notification with key: " + key);
532 final long now = System.currentTimeMillis();
533 EventLogTags.writeNotificationClicked(key,
534 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
536 StatusBarNotification sbn = r.sbn;
537 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
538 sbn.getId(), Notification.FLAG_AUTO_CANCEL,
539 Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
540 REASON_DELEGATE_CLICK, null);
545 public void onNotificationActionClick(int callingUid, int callingPid, String key,
547 synchronized (mNotificationList) {
548 NotificationRecord r = mNotificationsByKey.get(key);
550 Log.w(TAG, "No notification with key: " + key);
553 final long now = System.currentTimeMillis();
554 EventLogTags.writeNotificationActionClicked(key, actionIndex,
555 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
556 // TODO: Log action click via UsageStats.
561 public void onNotificationClear(int callingUid, int callingPid,
562 String pkg, String tag, int id, int userId) {
563 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
564 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
565 true, userId, REASON_DELEGATE_CANCEL, null);
569 public void onPanelRevealed(boolean clearEffects, int items) {
570 EventLogTags.writeNotificationPanelRevealed(items);
577 public void onPanelHidden() {
578 EventLogTags.writeNotificationPanelHidden();
582 public void clearEffects() {
583 synchronized (mNotificationList) {
584 if (DBG) Slog.d(TAG, "clearEffects");
586 clearVibrateLocked();
592 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
593 int uid, int initialPid, String message, int userId) {
594 Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
595 + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
596 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
597 REASON_DELEGATE_ERROR, null);
598 long ident = Binder.clearCallingIdentity();
600 ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg,
601 "Bad notification posted from package " + pkg
603 } catch (RemoteException e) {
605 Binder.restoreCallingIdentity(ident);
609 public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
610 NotificationVisibility[] noLongerVisibleKeys) {
611 synchronized (mNotificationList) {
612 for (NotificationVisibility nv : newlyVisibleKeys) {
613 NotificationRecord r = mNotificationsByKey.get(nv.key);
614 if (r == null) continue;
615 r.setVisibility(true, nv.rank);
618 // Note that we might receive this event after notifications
619 // have already left the system, e.g. after dismissing from the
620 // shade. Hence not finding notifications in
621 // mNotificationsByKey is not an exceptional condition.
622 for (NotificationVisibility nv : noLongerVisibleKeys) {
623 NotificationRecord r = mNotificationsByKey.get(nv.key);
624 if (r == null) continue;
625 r.setVisibility(false, nv.rank);
632 public void onNotificationExpansionChanged(String key,
633 boolean userAction, boolean expanded) {
634 synchronized (mNotificationList) {
635 NotificationRecord r = mNotificationsByKey.get(key);
637 r.stats.onExpansionChanged(userAction, expanded);
638 final long now = System.currentTimeMillis();
639 EventLogTags.writeNotificationExpansion(key,
640 userAction ? 1 : 0, expanded ? 1 : 0,
641 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
647 private void clearSoundLocked() {
648 mSoundNotificationKey = null;
649 long identity = Binder.clearCallingIdentity();
651 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
652 if (player != null) {
655 } catch (RemoteException e) {
657 Binder.restoreCallingIdentity(identity);
661 private void clearVibrateLocked() {
662 mVibrateNotificationKey = null;
663 long identity = Binder.clearCallingIdentity();
667 Binder.restoreCallingIdentity(identity);
671 private void clearLightsLocked() {
674 updateLightsLocked();
677 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
679 public void onReceive(Context context, Intent intent) {
680 String action = intent.getAction();
681 if (action == null) {
685 boolean queryRestart = false;
686 boolean queryRemove = false;
687 boolean packageChanged = false;
688 boolean cancelNotifications = true;
689 int reason = REASON_PACKAGE_CHANGED;
691 if (action.equals(Intent.ACTION_PACKAGE_ADDED)
692 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
693 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
694 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
695 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
696 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
697 || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
698 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
699 UserHandle.USER_ALL);
700 String pkgList[] = null;
701 boolean removingPackage = queryRemove &&
702 !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
703 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
704 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
705 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
706 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
707 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
708 reason = REASON_PACKAGE_SUSPENDED;
709 } else if (queryRestart) {
710 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
712 Uri uri = intent.getData();
716 String pkgName = uri.getSchemeSpecificPart();
717 if (pkgName == null) {
720 if (packageChanged) {
721 // We cancel notifications for packages which have just been disabled
723 final IPackageManager pm = AppGlobals.getPackageManager();
724 final int enabled = pm.getApplicationEnabledSetting(pkgName,
725 changeUserId != UserHandle.USER_ALL ? changeUserId :
726 UserHandle.USER_SYSTEM);
727 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
728 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
729 cancelNotifications = false;
731 } catch (IllegalArgumentException e) {
732 // Package doesn't exist; probably racing with uninstall.
733 // cancelNotifications is already true, so nothing to do here.
735 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
737 } catch (RemoteException e) {
738 // Failed to talk to PackageManagerService Should never happen!
741 pkgList = new String[]{pkgName};
744 if (pkgList != null && (pkgList.length > 0)) {
745 for (String pkgName : pkgList) {
746 if (cancelNotifications) {
747 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart,
748 changeUserId, reason, null);
752 mListeners.onPackagesChanged(removingPackage, pkgList);
753 mRankerServices.onPackagesChanged(removingPackage, pkgList);
754 mConditionProviders.onPackagesChanged(removingPackage, pkgList);
755 mRankingHelper.onPackagesChanged(removingPackage, pkgList);
760 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
762 public void onReceive(Context context, Intent intent) {
763 String action = intent.getAction();
765 if (action.equals(Intent.ACTION_SCREEN_ON)) {
766 // Keep track of screen on/off state, but do not turn off the notification light
767 // until user passes through the lock screen or views the notification.
769 updateNotificationPulse();
770 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
772 updateNotificationPulse();
773 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
774 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
775 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
776 updateNotificationPulse();
777 } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
778 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
779 if (userHandle >= 0) {
780 cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
781 REASON_USER_STOPPED, null);
783 } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
784 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
785 if (userHandle >= 0) {
786 cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
787 REASON_PROFILE_TURNED_OFF, null);
789 } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
790 // turn off LED when user passes through lock screen
791 mNotificationLight.turnOff();
792 if (mStatusBar != null) {
793 mStatusBar.notificationLightOff();
795 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
796 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
797 // reload per-user settings
798 mSettingsObserver.update(null);
799 mUserProfiles.updateCache(context);
800 // Refresh managed services
801 mConditionProviders.onUserSwitched(user);
802 mListeners.onUserSwitched(user);
803 mRankerServices.onUserSwitched(user);
804 mZenModeHelper.onUserSwitched(user);
805 } else if (action.equals(Intent.ACTION_USER_ADDED)) {
806 mUserProfiles.updateCache(context);
807 } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
808 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
809 mZenModeHelper.onUserRemoved(user);
810 } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
811 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
812 mConditionProviders.onUserUnlocked(user);
813 mListeners.onUserUnlocked(user);
814 mRankerServices.onUserUnlocked(user);
815 mZenModeHelper.onUserUnlocked(user);
820 private final class SettingsObserver extends ContentObserver {
821 private final Uri NOTIFICATION_LIGHT_PULSE_URI
822 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
823 private final Uri NOTIFICATION_SOUND_URI
824 = Settings.System.getUriFor(Settings.System.NOTIFICATION_SOUND);
825 private final Uri NOTIFICATION_RATE_LIMIT_URI
826 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
828 SettingsObserver(Handler handler) {
833 ContentResolver resolver = getContext().getContentResolver();
834 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
835 false, this, UserHandle.USER_ALL);
836 resolver.registerContentObserver(NOTIFICATION_SOUND_URI,
837 false, this, UserHandle.USER_ALL);
838 resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
839 false, this, UserHandle.USER_ALL);
843 @Override public void onChange(boolean selfChange, Uri uri) {
847 public void update(Uri uri) {
848 ContentResolver resolver = getContext().getContentResolver();
849 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
850 boolean pulseEnabled = Settings.System.getInt(resolver,
851 Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
852 if (mNotificationPulseEnabled != pulseEnabled) {
853 mNotificationPulseEnabled = pulseEnabled;
854 updateNotificationPulse();
857 if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
858 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
859 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
861 if (uri == null || NOTIFICATION_SOUND_URI.equals(uri)) {
862 mSystemNotificationSound = Settings.System.getString(resolver,
863 Settings.System.NOTIFICATION_SOUND);
868 private SettingsObserver mSettingsObserver;
869 private ZenModeHelper mZenModeHelper;
871 private final Runnable mBuzzBeepBlinked = new Runnable() {
874 if (mStatusBar != null) {
875 mStatusBar.buzzBeepBlinked();
880 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
881 int[] ar = r.getIntArray(resid);
885 final int len = ar.length > maxlen ? maxlen : ar.length;
886 long[] out = new long[len];
887 for (int i=0; i<len; i++) {
893 public NotificationManagerService(Context context) {
898 void setAudioManager(AudioManager audioMananger) {
899 mAudioManager = audioMananger;
903 void setVibrator(Vibrator vibrator) {
904 mVibrator = vibrator;
908 void setSystemReady(boolean systemReady) {
909 mSystemReady = systemReady;
913 void setHandler(Handler handler) {
918 void setSystemNotificationSound(String systemNotificationSound) {
919 mSystemNotificationSound = systemNotificationSound;
923 public void onStart() {
924 Resources resources = getContext().getResources();
926 mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
927 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
928 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
930 mAm = ActivityManagerNative.getDefault();
931 mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
932 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
933 mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
935 // This is the package that contains the AOSP framework update.
936 mRankerServicePackageName = getContext().getPackageManager()
937 .getServicesSystemSharedLibraryPackageName();
939 mHandler = new WorkerHandler();
940 mRankingThread.start();
941 String[] extractorNames;
943 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
944 } catch (Resources.NotFoundException e) {
945 extractorNames = new String[0];
947 mUsageStats = new NotificationUsageStats(getContext());
948 mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
949 mRankingHelper = new RankingHelper(getContext(),
953 mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles);
954 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
955 mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
957 public void onConfigChanged() {
962 void onZenModeChanged() {
963 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
964 getContext().sendBroadcastAsUser(
965 new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
966 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
967 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
968 synchronized(mNotificationList) {
969 updateInterruptionFilterLocked();
974 void onPolicyChanged() {
975 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
978 final File systemDir = new File(Environment.getDataDirectory(), "system");
979 mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
983 // This is a MangedServices object that keeps track of the listeners.
984 mListeners = new NotificationListeners();
986 // This is a MangedServices object that keeps track of the ranker.
987 mRankerServices = new NotificationRankers();
988 // Find the updatable ranker and register it.
989 mRankerServices.registerRanker();
991 mStatusBar = getLocalService(StatusBarManagerInternal.class);
992 if (mStatusBar != null) {
993 mStatusBar.setNotificationDelegate(mNotificationDelegate);
996 final LightsManager lights = getLocalService(LightsManager.class);
997 mNotificationLight = lights.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
998 mAttentionLight = lights.getLight(LightsManager.LIGHT_ID_ATTENTION);
1000 mDefaultNotificationColor = resources.getColor(
1001 R.color.config_defaultNotificationColor);
1002 mDefaultNotificationLedOn = resources.getInteger(
1003 R.integer.config_defaultNotificationLedOn);
1004 mDefaultNotificationLedOff = resources.getInteger(
1005 R.integer.config_defaultNotificationLedOff);
1007 mDefaultVibrationPattern = getLongArray(resources,
1008 R.array.config_defaultNotificationVibePattern,
1009 VIBRATE_PATTERN_MAXLEN,
1010 DEFAULT_VIBRATE_PATTERN);
1012 mFallbackVibrationPattern = getLongArray(resources,
1013 R.array.config_notificationFallbackVibePattern,
1014 VIBRATE_PATTERN_MAXLEN,
1015 DEFAULT_VIBRATE_PATTERN);
1017 mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
1019 // Don't start allowing notifications until the setup wizard has run once.
1020 // After that, including subsequent boots, init with notifications turned on.
1021 // This works on the first boot because the setup wizard will toggle this
1022 // flag at least once and we'll go back to 0 after that.
1023 if (0 == Settings.Global.getInt(getContext().getContentResolver(),
1024 Settings.Global.DEVICE_PROVISIONED, 0)) {
1025 mDisableNotificationEffects = true;
1027 mZenModeHelper.initZenMode();
1028 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1030 mUserProfiles.updateCache(getContext());
1031 listenForCallState();
1033 // register for various Intents
1034 IntentFilter filter = new IntentFilter();
1035 filter.addAction(Intent.ACTION_SCREEN_ON);
1036 filter.addAction(Intent.ACTION_SCREEN_OFF);
1037 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
1038 filter.addAction(Intent.ACTION_USER_PRESENT);
1039 filter.addAction(Intent.ACTION_USER_STOPPED);
1040 filter.addAction(Intent.ACTION_USER_SWITCHED);
1041 filter.addAction(Intent.ACTION_USER_ADDED);
1042 filter.addAction(Intent.ACTION_USER_REMOVED);
1043 filter.addAction(Intent.ACTION_USER_UNLOCKED);
1044 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
1045 getContext().registerReceiver(mIntentReceiver, filter);
1047 IntentFilter pkgFilter = new IntentFilter();
1048 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
1049 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1050 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
1051 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1052 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1053 pkgFilter.addDataScheme("package");
1054 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1057 IntentFilter suspendedPkgFilter = new IntentFilter();
1058 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
1059 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1060 suspendedPkgFilter, null, null);
1062 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
1063 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1066 mSettingsObserver = new SettingsObserver(mHandler);
1068 mArchive = new Archive(resources.getInteger(
1069 R.integer.config_notificationServiceArchiveSize));
1071 publishBinderService(Context.NOTIFICATION_SERVICE, mService);
1072 publishLocalService(NotificationManagerInternal.class, mInternalService);
1075 private void sendRegisteredOnlyBroadcast(String action) {
1076 getContext().sendBroadcastAsUser(new Intent(action)
1077 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
1081 * Make sure the XML config and the the AppOps system agree about blocks.
1083 private void syncBlockDb() {
1086 // sync bans from ranker into app opps
1087 Map<Integer, String> packageBans = mRankingHelper.getPackageBans();
1088 for(Entry<Integer, String> ban : packageBans.entrySet()) {
1089 final int uid = ban.getKey();
1090 final String packageName = ban.getValue();
1091 setNotificationsEnabledForPackageImpl(packageName, uid, false);
1094 // sync bans from app opps into ranker
1095 packageBans.clear();
1096 for (UserInfo user : UserManager.get(getContext()).getUsers()) {
1097 final int userId = user.getUserHandle().getIdentifier();
1098 final PackageManager packageManager = getContext().getPackageManager();
1099 List<PackageInfo> packages = packageManager.getInstalledPackagesAsUser(0, userId);
1100 final int packageCount = packages.size();
1101 for (int p = 0; p < packageCount; p++) {
1102 final String packageName = packages.get(p).packageName;
1104 final int uid = packageManager.getPackageUidAsUser(packageName, userId);
1105 if (!checkNotificationOp(packageName, uid)) {
1106 packageBans.put(uid, packageName);
1108 } catch (NameNotFoundException e) {
1113 for (Entry<Integer, String> ban : packageBans.entrySet()) {
1114 mRankingHelper.setImportance(ban.getValue(), ban.getKey(), IMPORTANCE_NONE);
1121 public void onBootPhase(int phase) {
1122 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1123 // no beeping until we're basically done booting
1124 mSystemReady = true;
1126 // Grab our optional AudioService
1127 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
1128 mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
1129 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
1130 mZenModeHelper.onSystemReady();
1131 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1132 // This observer will force an update when observe is called, causing us to
1133 // bind to listener services.
1134 mSettingsObserver.observe();
1135 mListeners.onBootPhaseAppsCanStart();
1136 mRankerServices.onBootPhaseAppsCanStart();
1137 mConditionProviders.onBootPhaseAppsCanStart();
1141 void setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled) {
1142 Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
1144 mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
1145 enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
1147 // Now, cancel any outstanding notifications that are part of a just-disabled app
1148 if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
1149 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true, UserHandle.getUserId(uid),
1150 REASON_PACKAGE_BANNED, null);
1154 private void updateListenerHintsLocked() {
1155 final int hints = calculateHints();
1156 if (hints == mListenerHints) return;
1157 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
1158 mListenerHints = hints;
1159 scheduleListenerHintsChanged(hints);
1162 private void updateEffectsSuppressorLocked() {
1163 final long updatedSuppressedEffects = calculateSuppressedEffects();
1164 if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1165 final List<ComponentName> suppressors = getSuppressors();
1166 ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1167 mEffectsSuppressors = suppressors;
1168 mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
1169 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
1172 private ArrayList<ComponentName> getSuppressors() {
1173 ArrayList<ComponentName> names = new ArrayList<ComponentName>();
1174 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1175 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1177 for (ManagedServiceInfo info : serviceInfoList) {
1178 names.add(info.component);
1185 private boolean removeDisabledHints(ManagedServiceInfo info) {
1186 return removeDisabledHints(info, 0);
1189 private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
1190 boolean removed = false;
1192 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1193 final int hint = mListenersDisablingEffects.keyAt(i);
1194 final ArraySet<ManagedServiceInfo> listeners =
1195 mListenersDisablingEffects.valueAt(i);
1197 if (hints == 0 || (hint & hints) == hint) {
1198 removed = removed || listeners.remove(info);
1205 private void addDisabledHints(ManagedServiceInfo info, int hints) {
1206 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1207 addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
1210 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1211 addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1214 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1215 addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
1219 private void addDisabledHint(ManagedServiceInfo info, int hint) {
1220 if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
1221 mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
1224 ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
1225 hintListeners.add(info);
1228 private int calculateHints() {
1230 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1231 int hint = mListenersDisablingEffects.keyAt(i);
1232 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1234 if (!serviceInfoList.isEmpty()) {
1242 private long calculateSuppressedEffects() {
1243 int hints = calculateHints();
1244 long suppressedEffects = 0;
1246 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1247 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
1250 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1251 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
1254 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1255 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
1258 return suppressedEffects;
1261 private void updateInterruptionFilterLocked() {
1262 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1263 if (interruptionFilter == mInterruptionFilter) return;
1264 mInterruptionFilter = interruptionFilter;
1265 scheduleInterruptionFilterChanged(interruptionFilter);
1268 private final IBinder mService = new INotificationManager.Stub() {
1270 // ============================================================================
1273 public void enqueueToast(String pkg, ITransientNotification callback, int duration)
1276 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1277 + " duration=" + duration);
1280 if (pkg == null || callback == null) {
1281 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1285 final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg));
1286 final boolean isPackageSuspended =
1287 isPackageSuspendedForUser(pkg, Binder.getCallingUid());
1289 if (ENABLE_BLOCKED_TOASTS && (!noteNotificationOp(pkg, Binder.getCallingUid())
1290 || isPackageSuspended)) {
1291 if (!isSystemToast) {
1292 Slog.e(TAG, "Suppressing toast from package " + pkg
1293 + (isPackageSuspended
1294 ? " due to package suspended by administrator."
1295 : " by user request."));
1300 synchronized (mToastQueue) {
1301 int callingPid = Binder.getCallingPid();
1302 long callingId = Binder.clearCallingIdentity();
1305 int index = indexOfToastLocked(pkg, callback);
1306 // If it's already in the queue, we update it in place, we don't
1307 // move it to the end of the queue.
1309 record = mToastQueue.get(index);
1310 record.update(duration);
1312 // Limit the number of toasts that any given package except the android
1313 // package can enqueue. Prevents DOS attacks and deals with leaks.
1314 if (!isSystemToast) {
1316 final int N = mToastQueue.size();
1317 for (int i=0; i<N; i++) {
1318 final ToastRecord r = mToastQueue.get(i);
1319 if (r.pkg.equals(pkg)) {
1321 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
1322 Slog.e(TAG, "Package has already posted " + count
1323 + " toasts. Not showing more. Package=" + pkg);
1330 Binder token = new Binder();
1331 mWindowManagerInternal.addWindowToken(token,
1332 WindowManager.LayoutParams.TYPE_TOAST);
1333 record = new ToastRecord(callingPid, pkg, callback, duration, token);
1334 mToastQueue.add(record);
1335 index = mToastQueue.size() - 1;
1336 keepProcessAliveIfNeededLocked(callingPid);
1338 // If it's at index 0, it's the current toast. It doesn't matter if it's
1339 // new or just been updated. Call back and tell it to show itself.
1340 // If the callback fails, this will remove it from the list, so don't
1341 // assume that it's valid after this.
1343 showNextToastLocked();
1346 Binder.restoreCallingIdentity(callingId);
1352 public void cancelToast(String pkg, ITransientNotification callback) {
1353 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
1355 if (pkg == null || callback == null) {
1356 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
1360 synchronized (mToastQueue) {
1361 long callingId = Binder.clearCallingIdentity();
1363 int index = indexOfToastLocked(pkg, callback);
1365 cancelToastLocked(index);
1367 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
1368 + " callback=" + callback);
1371 Binder.restoreCallingIdentity(callingId);
1377 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
1378 Notification notification, int[] idOut, int userId) throws RemoteException {
1379 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
1380 Binder.getCallingPid(), tag, id, notification, idOut, userId);
1384 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
1385 checkCallerIsSystemOrSameApp(pkg);
1386 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1387 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
1388 // Don't allow client applications to cancel foreground service notis or autobundled
1390 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
1391 (Binder.getCallingUid() == Process.SYSTEM_UID
1392 ? 0 : Notification.FLAG_FOREGROUND_SERVICE)
1393 | (Binder.getCallingUid() == Process.SYSTEM_UID
1394 ? 0 : Notification.FLAG_AUTOGROUP_SUMMARY), false, userId,
1395 REASON_APP_CANCEL, null);
1399 public void cancelAllNotifications(String pkg, int userId) {
1400 checkCallerIsSystemOrSameApp(pkg);
1402 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1403 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
1405 // Calling from user space, don't allow the canceling of actively
1406 // running foreground services.
1407 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
1408 pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
1409 REASON_APP_CANCEL_ALL, null);
1413 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
1414 checkCallerIsSystem();
1416 setNotificationsEnabledForPackageImpl(pkg, uid, enabled);
1417 mRankingHelper.setEnabled(pkg, uid, enabled);
1422 * Use this when you just want to know if notifications are OK for this package.
1425 public boolean areNotificationsEnabled(String pkg) {
1426 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
1430 * Use this when you just want to know if notifications are OK for this package.
1433 public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
1434 checkCallerIsSystemOrSameApp(pkg);
1435 if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) {
1436 getContext().enforceCallingPermission(
1437 android.Manifest.permission.INTERACT_ACROSS_USERS,
1438 "canNotifyAsPackage for uid " + uid);
1441 return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
1442 == AppOpsManager.MODE_ALLOWED) && !isPackageSuspendedForUser(pkg, uid);
1446 public void setPriority(String pkg, int uid, int priority) {
1447 checkCallerIsSystem();
1448 mRankingHelper.setPriority(pkg, uid, priority);
1453 public int getPriority(String pkg, int uid) {
1454 checkCallerIsSystem();
1455 return mRankingHelper.getPriority(pkg, uid);
1459 public void setVisibilityOverride(String pkg, int uid, int visibility) {
1460 checkCallerIsSystem();
1461 mRankingHelper.setVisibilityOverride(pkg, uid, visibility);
1466 public int getVisibilityOverride(String pkg, int uid) {
1467 checkCallerIsSystem();
1468 return mRankingHelper.getVisibilityOverride(pkg, uid);
1472 public void setImportance(String pkg, int uid, int importance) {
1473 enforceSystemOrSystemUI("Caller not system or systemui");
1474 setNotificationsEnabledForPackageImpl(pkg, uid,
1475 importance != NotificationListenerService.Ranking.IMPORTANCE_NONE);
1476 mRankingHelper.setImportance(pkg, uid, importance);
1481 public int getPackageImportance(String pkg) {
1482 checkCallerIsSystemOrSameApp(pkg);
1483 return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
1487 public int getImportance(String pkg, int uid) {
1488 enforceSystemOrSystemUI("Caller not system or systemui");
1489 return mRankingHelper.getImportance(pkg, uid);
1493 * System-only API for getting a list of current (i.e. not cleared) notifications.
1495 * Requires ACCESS_NOTIFICATIONS which is signature|system.
1496 * @returns A list of all the notifications, in natural order.
1499 public StatusBarNotification[] getActiveNotifications(String callingPkg) {
1500 // enforce() will ensure the calling uid has the correct permission
1501 getContext().enforceCallingOrSelfPermission(
1502 android.Manifest.permission.ACCESS_NOTIFICATIONS,
1503 "NotificationManagerService.getActiveNotifications");
1505 StatusBarNotification[] tmp = null;
1506 int uid = Binder.getCallingUid();
1508 // noteOp will check to make sure the callingPkg matches the uid
1509 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1510 == AppOpsManager.MODE_ALLOWED) {
1511 synchronized (mNotificationList) {
1512 tmp = new StatusBarNotification[mNotificationList.size()];
1513 final int N = mNotificationList.size();
1514 for (int i=0; i<N; i++) {
1515 tmp[i] = mNotificationList.get(i).sbn;
1523 * Public API for getting a list of current notifications for the calling package/uid.
1525 * @returns A list of all the package's notifications, in natural order.
1528 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
1529 int incomingUserId) {
1530 checkCallerIsSystemOrSameApp(pkg);
1531 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1532 Binder.getCallingUid(), incomingUserId, true, false,
1533 "getAppActiveNotifications", pkg);
1535 final ArrayList<StatusBarNotification> list
1536 = new ArrayList<StatusBarNotification>(mNotificationList.size());
1538 synchronized (mNotificationList) {
1539 final int N = mNotificationList.size();
1540 for (int i = 0; i < N; i++) {
1541 final StatusBarNotification sbn = mNotificationList.get(i).sbn;
1542 if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId
1543 && (sbn.getNotification().flags
1544 & Notification.FLAG_AUTOGROUP_SUMMARY) == 0) {
1545 // We could pass back a cloneLight() but clients might get confused and
1546 // try to send this thing back to notify() again, which would not work
1548 final StatusBarNotification sbnOut = new StatusBarNotification(
1549 sbn.getPackageName(),
1551 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
1552 0, // hide score from apps
1553 sbn.getNotification().clone(),
1554 sbn.getUser(), sbn.getPostTime());
1560 return new ParceledListSlice<StatusBarNotification>(list);
1564 * System-only API for getting a list of recent (cleared, no longer shown) notifications.
1566 * Requires ACCESS_NOTIFICATIONS which is signature|system.
1569 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
1570 // enforce() will ensure the calling uid has the correct permission
1571 getContext().enforceCallingOrSelfPermission(
1572 android.Manifest.permission.ACCESS_NOTIFICATIONS,
1573 "NotificationManagerService.getHistoricalNotifications");
1575 StatusBarNotification[] tmp = null;
1576 int uid = Binder.getCallingUid();
1578 // noteOp will check to make sure the callingPkg matches the uid
1579 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1580 == AppOpsManager.MODE_ALLOWED) {
1581 synchronized (mArchive) {
1582 tmp = mArchive.getArray(count);
1589 * Register a listener binder directly with the notification manager.
1591 * Only works with system callers. Apps should extend
1592 * {@link android.service.notification.NotificationListenerService}.
1595 public void registerListener(final INotificationListener listener,
1596 final ComponentName component, final int userid) {
1597 enforceSystemOrSystemUI("INotificationManager.registerListener");
1598 mListeners.registerService(listener, component, userid);
1602 * Remove a listener binder directly
1605 public void unregisterListener(INotificationListener token, int userid) {
1606 mListeners.unregisterService(token, userid);
1610 * Allow an INotificationListener to simulate a "clear all" operation.
1612 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
1614 * @param token The binder for the listener, to check that the caller is allowed
1617 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
1618 final int callingUid = Binder.getCallingUid();
1619 final int callingPid = Binder.getCallingPid();
1620 long identity = Binder.clearCallingIdentity();
1622 synchronized (mNotificationList) {
1623 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1625 final int N = keys.length;
1626 for (int i = 0; i < N; i++) {
1627 NotificationRecord r = mNotificationsByKey.get(keys[i]);
1628 if (r == null) continue;
1629 final int userId = r.sbn.getUserId();
1630 if (userId != info.userid && userId != UserHandle.USER_ALL &&
1631 !mUserProfiles.isCurrentProfile(userId)) {
1632 throw new SecurityException("Disallowed call from listener: "
1635 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
1636 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
1640 cancelAllLocked(callingUid, callingPid, info.userid,
1641 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
1645 Binder.restoreCallingIdentity(identity);
1650 * Handle request from an approved listener to re-enable itself.
1652 * @param component The componenet to be re-enabled, caller must match package.
1655 public void requestBindListener(ComponentName component) {
1656 checkCallerIsSystemOrSameApp(component.getPackageName());
1657 long identity = Binder.clearCallingIdentity();
1659 ManagedServices manager =
1660 mRankerServices.isComponentEnabledForCurrentProfiles(component)
1663 manager.setComponentState(component, true);
1665 Binder.restoreCallingIdentity(identity);
1670 public void requestUnbindListener(INotificationListener token) {
1671 long identity = Binder.clearCallingIdentity();
1673 // allow bound services to disable themselves
1674 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1675 info.getOwner().setComponentState(info.component, false);
1677 Binder.restoreCallingIdentity(identity);
1682 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
1683 long identity = Binder.clearCallingIdentity();
1685 synchronized (mNotificationList) {
1686 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1688 final int N = keys.length;
1689 for (int i = 0; i < N; i++) {
1690 NotificationRecord r = mNotificationsByKey.get(keys[i]);
1691 if (r == null) continue;
1692 final int userId = r.sbn.getUserId();
1693 if (userId != info.userid && userId != UserHandle.USER_ALL &&
1694 !mUserProfiles.isCurrentProfile(userId)) {
1695 throw new SecurityException("Disallowed call from listener: "
1699 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
1700 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
1701 userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM
1703 UsageEvents.Event.USER_INTERACTION);
1710 Binder.restoreCallingIdentity(identity);
1714 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
1715 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
1716 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
1717 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
1719 userId, REASON_LISTENER_CANCEL, info);
1723 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
1725 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
1727 * @param token The binder for the listener, to check that the caller is allowed
1730 public void cancelNotificationFromListener(INotificationListener token, String pkg,
1731 String tag, int id) {
1732 final int callingUid = Binder.getCallingUid();
1733 final int callingPid = Binder.getCallingPid();
1734 long identity = Binder.clearCallingIdentity();
1736 synchronized (mNotificationList) {
1737 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1738 if (info.supportsProfiles()) {
1739 Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
1740 + "from " + info.component
1741 + " use cancelNotification(key) instead.");
1743 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
1744 pkg, tag, id, info.userid);
1748 Binder.restoreCallingIdentity(identity);
1753 * Allow an INotificationListener to request the list of outstanding notifications seen by
1754 * the current user. Useful when starting up, after which point the listener callbacks
1757 * @param token The binder for the listener, to check that the caller is allowed
1758 * @param keys An array of notification keys to fetch, or null to fetch everything
1759 * @returns The return value will contain the notifications specified in keys, in that
1760 * order, or if keys is null, all the notifications, in natural order.
1763 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
1764 INotificationListener token, String[] keys, int trim) {
1765 synchronized (mNotificationList) {
1766 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1767 final boolean getKeys = keys != null;
1768 final int N = getKeys ? keys.length : mNotificationList.size();
1769 final ArrayList<StatusBarNotification> list
1770 = new ArrayList<StatusBarNotification>(N);
1771 for (int i=0; i<N; i++) {
1772 final NotificationRecord r = getKeys
1773 ? mNotificationsByKey.get(keys[i])
1774 : mNotificationList.get(i);
1775 if (r == null) continue;
1776 StatusBarNotification sbn = r.sbn;
1777 if (!isVisibleToListener(sbn, info)) continue;
1778 StatusBarNotification sbnToSend =
1779 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
1780 list.add(sbnToSend);
1782 return new ParceledListSlice<StatusBarNotification>(list);
1787 public void requestHintsFromListener(INotificationListener token, int hints) {
1788 final long identity = Binder.clearCallingIdentity();
1790 synchronized (mNotificationList) {
1791 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1792 final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
1793 | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
1794 | HINT_HOST_DISABLE_CALL_EFFECTS;
1795 final boolean disableEffects = (hints & disableEffectsMask) != 0;
1796 if (disableEffects) {
1797 addDisabledHints(info, hints);
1799 removeDisabledHints(info, hints);
1801 updateListenerHintsLocked();
1802 updateEffectsSuppressorLocked();
1805 Binder.restoreCallingIdentity(identity);
1810 public int getHintsFromListener(INotificationListener token) {
1811 synchronized (mNotificationList) {
1812 return mListenerHints;
1817 public void requestInterruptionFilterFromListener(INotificationListener token,
1818 int interruptionFilter) throws RemoteException {
1819 final long identity = Binder.clearCallingIdentity();
1821 synchronized (mNotificationList) {
1822 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1823 mZenModeHelper.requestFromListener(info.component, interruptionFilter);
1824 updateInterruptionFilterLocked();
1827 Binder.restoreCallingIdentity(identity);
1832 public int getInterruptionFilterFromListener(INotificationListener token)
1833 throws RemoteException {
1834 synchronized (mNotificationLight) {
1835 return mInterruptionFilter;
1840 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
1841 throws RemoteException {
1842 synchronized (mNotificationList) {
1843 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1844 if (info == null) return;
1845 mListeners.setOnNotificationPostedTrimLocked(info, trim);
1850 public int getZenMode() {
1851 return mZenModeHelper.getZenMode();
1855 public ZenModeConfig getZenModeConfig() {
1856 enforceSystemOrSystemUIOrVolume("INotificationManager.getZenModeConfig");
1857 return mZenModeHelper.getConfig();
1861 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
1862 enforceSystemOrSystemUIOrVolume("INotificationManager.setZenMode");
1863 final long identity = Binder.clearCallingIdentity();
1865 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
1867 Binder.restoreCallingIdentity(identity);
1872 public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
1873 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
1874 return mZenModeHelper.getZenRules();
1878 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
1879 Preconditions.checkNotNull(id, "Id is null");
1880 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
1881 return mZenModeHelper.getAutomaticZenRule(id);
1885 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
1886 throws RemoteException {
1887 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
1888 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
1889 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
1890 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
1891 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
1893 return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
1894 "addAutomaticZenRule");
1898 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
1899 throws RemoteException {
1900 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
1901 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
1902 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
1903 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
1904 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
1906 return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
1907 "updateAutomaticZenRule");
1911 public boolean removeAutomaticZenRule(String id) throws RemoteException {
1912 Preconditions.checkNotNull(id, "Id is null");
1913 // Verify that they can modify zen rules.
1914 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
1916 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
1920 public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
1921 Preconditions.checkNotNull(packageName, "Package name is null");
1922 enforceSystemOrSystemUI("removeAutomaticZenRules");
1924 return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
1928 public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
1929 Preconditions.checkNotNull(owner, "Owner is null");
1930 enforceSystemOrSystemUI("getRuleInstanceCount");
1932 return mZenModeHelper.getCurrentInstanceCount(owner);
1936 public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
1937 enforcePolicyAccess(pkg, "setInterruptionFilter");
1938 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
1939 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
1940 final long identity = Binder.clearCallingIdentity();
1942 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
1944 Binder.restoreCallingIdentity(identity);
1949 public void notifyConditions(final String pkg, IConditionProvider provider,
1950 final Condition[] conditions) {
1951 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
1952 checkCallerIsSystemOrSameApp(pkg);
1953 mHandler.post(new Runnable() {
1956 mConditionProviders.notifyConditions(pkg, info, conditions);
1961 private void enforceSystemOrSystemUIOrVolume(String message) {
1962 if (mAudioManagerInternal != null) {
1963 final int vcuid = mAudioManagerInternal.getVolumeControllerUid();
1964 if (vcuid > 0 && Binder.getCallingUid() == vcuid) {
1968 enforceSystemOrSystemUI(message);
1971 private void enforceSystemOrSystemUI(String message) {
1972 if (isCallerSystem()) return;
1973 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
1977 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
1979 checkCallerIsSystemOrSameApp(pkg);
1980 } catch (SecurityException e) {
1981 getContext().enforceCallingPermission(
1982 android.Manifest.permission.STATUS_BAR_SERVICE,
1987 private void enforcePolicyAccess(int uid, String method) {
1988 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
1989 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
1992 boolean accessAllowed = false;
1993 String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
1994 final int packageCount = packages.length;
1995 for (int i = 0; i < packageCount; i++) {
1996 if (checkPolicyAccess(packages[i])) {
1997 accessAllowed = true;
2000 if (!accessAllowed) {
2001 Slog.w(TAG, "Notification policy access denied calling " + method);
2002 throw new SecurityException("Notification policy access denied");
2006 private void enforcePolicyAccess(String pkg, String method) {
2007 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2008 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2011 checkCallerIsSameApp(pkg);
2012 if (!checkPolicyAccess(pkg)) {
2013 Slog.w(TAG, "Notification policy access denied calling " + method);
2014 throw new SecurityException("Notification policy access denied");
2018 private boolean checkPackagePolicyAccess(String pkg) {
2019 return mPolicyAccess.isPackageGranted(pkg);
2022 private boolean checkPolicyAccess(String pkg) {
2024 int uid = getContext().getPackageManager().getPackageUidAsUser(
2025 pkg, UserHandle.getCallingUserId());
2026 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
2027 android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
2031 } catch (NameNotFoundException e) {
2034 return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
2038 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2039 if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2040 != PackageManager.PERMISSION_GRANTED) {
2041 pw.println("Permission Denial: can't dump NotificationManager from pid="
2042 + Binder.getCallingPid()
2043 + ", uid=" + Binder.getCallingUid());
2047 final DumpFilter filter = DumpFilter.parseFromArguments(args);
2048 if (filter != null && filter.stats) {
2049 dumpJson(pw, filter);
2051 dumpImpl(pw, filter);
2056 public ComponentName getEffectsSuppressor() {
2057 enforceSystemOrSystemUIOrVolume("INotificationManager.getEffectsSuppressor");
2058 return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
2062 public boolean matchesCallFilter(Bundle extras) {
2063 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
2064 return mZenModeHelper.matchesCallFilter(
2065 Binder.getCallingUserHandle(),
2067 mRankingHelper.findExtractor(ValidateNotificationPeople.class),
2068 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
2069 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
2073 public boolean isSystemConditionProviderEnabled(String path) {
2074 enforceSystemOrSystemUIOrVolume("INotificationManager.isSystemConditionProviderEnabled");
2075 return mConditionProviders.isSystemProviderEnabled(path);
2078 // Backup/restore interface
2080 public byte[] getBackupPayload(int user) {
2081 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
2082 //TODO: http://b/22388012
2083 if (user != UserHandle.USER_SYSTEM) {
2084 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
2087 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
2089 writePolicyXml(baos, true /*forBackup*/);
2090 return baos.toByteArray();
2091 } catch (IOException e) {
2092 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
2098 public void applyRestore(byte[] payload, int user) {
2099 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
2100 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
2101 if (payload == null) {
2102 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
2105 //TODO: http://b/22388012
2106 if (user != UserHandle.USER_SYSTEM) {
2107 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
2110 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
2112 readPolicyXml(bais, true /*forRestore*/);
2114 } catch (NumberFormatException | XmlPullParserException | IOException e) {
2115 Slog.w(TAG, "applyRestore: error reading payload", e);
2120 public boolean isNotificationPolicyAccessGranted(String pkg) {
2121 return checkPolicyAccess(pkg);
2125 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
2126 enforceSystemOrSystemUIOrSamePackage(pkg,
2127 "request policy access status for another package");
2128 return checkPolicyAccess(pkg);
2132 public String[] getPackagesRequestingNotificationPolicyAccess()
2133 throws RemoteException {
2134 enforceSystemOrSystemUI("request policy access packages");
2135 final long identity = Binder.clearCallingIdentity();
2137 return mPolicyAccess.getRequestingPackages();
2139 Binder.restoreCallingIdentity(identity);
2144 public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
2145 throws RemoteException {
2146 enforceSystemOrSystemUI("grant notification policy access");
2147 final long identity = Binder.clearCallingIdentity();
2149 synchronized (mNotificationList) {
2150 mPolicyAccess.put(pkg, granted);
2153 Binder.restoreCallingIdentity(identity);
2158 public Policy getNotificationPolicy(String pkg) {
2159 enforcePolicyAccess(pkg, "getNotificationPolicy");
2160 final long identity = Binder.clearCallingIdentity();
2162 return mZenModeHelper.getNotificationPolicy();
2164 Binder.restoreCallingIdentity(identity);
2169 public void setNotificationPolicy(String pkg, Policy policy) {
2170 enforcePolicyAccess(pkg, "setNotificationPolicy");
2171 final long identity = Binder.clearCallingIdentity();
2173 mZenModeHelper.setNotificationPolicy(policy);
2175 Binder.restoreCallingIdentity(identity);
2180 public void applyAdjustmentFromRankerService(INotificationListener token,
2181 Adjustment adjustment) throws RemoteException {
2182 final long identity = Binder.clearCallingIdentity();
2184 synchronized (mNotificationList) {
2185 mRankerServices.checkServiceTokenLocked(token);
2186 applyAdjustmentLocked(adjustment);
2188 maybeAddAutobundleSummary(adjustment);
2189 mRankingHandler.requestSort();
2191 Binder.restoreCallingIdentity(identity);
2196 public void applyAdjustmentsFromRankerService(INotificationListener token,
2197 List<Adjustment> adjustments) throws RemoteException {
2199 final long identity = Binder.clearCallingIdentity();
2201 synchronized (mNotificationList) {
2202 mRankerServices.checkServiceTokenLocked(token);
2203 for (Adjustment adjustment : adjustments) {
2204 applyAdjustmentLocked(adjustment);
2207 for (Adjustment adjustment : adjustments) {
2208 maybeAddAutobundleSummary(adjustment);
2210 mRankingHandler.requestSort();
2212 Binder.restoreCallingIdentity(identity);
2217 private void applyAdjustmentLocked(Adjustment adjustment) {
2218 maybeClearAutobundleSummaryLocked(adjustment);
2219 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2223 if (adjustment.getImportance() != IMPORTANCE_NONE) {
2224 n.setImportance(adjustment.getImportance(), adjustment.getExplanation());
2226 if (adjustment.getSignals() != null) {
2227 Bundle.setDefusable(adjustment.getSignals(), true);
2228 final String autoGroupKey = adjustment.getSignals().getString(
2229 Adjustment.GROUP_KEY_OVERRIDE_KEY, null);
2230 if (autoGroupKey == null) {
2231 EventLogTags.writeNotificationUnautogrouped(adjustment.getKey());
2233 EventLogTags.writeNotificationAutogrouped(adjustment.getKey());
2235 n.sbn.setOverrideGroupKey(autoGroupKey);
2239 // Clears the 'fake' auto-bunding summary.
2240 private void maybeClearAutobundleSummaryLocked(Adjustment adjustment) {
2241 if (adjustment.getSignals() != null) {
2242 Bundle.setDefusable(adjustment.getSignals(), true);
2243 if (adjustment.getSignals().containsKey(Adjustment.NEEDS_AUTOGROUPING_KEY)
2244 && !adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) {
2245 ArrayMap<String, String> summaries =
2246 mAutobundledSummaries.get(adjustment.getUser());
2247 if (summaries != null && summaries.containsKey(adjustment.getPackage())) {
2249 final NotificationRecord removed = mNotificationsByKey.get(
2250 summaries.remove(adjustment.getPackage()));
2251 if (removed != null) {
2252 mNotificationList.remove(removed);
2253 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED);
2260 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
2261 private void maybeAddAutobundleSummary(Adjustment adjustment) {
2262 if (adjustment.getSignals() != null) {
2263 Bundle.setDefusable(adjustment.getSignals(), true);
2264 if (adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) {
2265 final String newAutoBundleKey =
2266 adjustment.getSignals().getString(Adjustment.GROUP_KEY_OVERRIDE_KEY, null);
2268 NotificationRecord summaryRecord = null;
2269 synchronized (mNotificationList) {
2270 NotificationRecord notificationRecord =
2271 mNotificationsByKey.get(adjustment.getKey());
2272 if (notificationRecord == null) {
2273 // The notification could have been cancelled again already. A successive
2274 // adjustment will post a summary if needed.
2277 final StatusBarNotification adjustedSbn = notificationRecord.sbn;
2278 userId = adjustedSbn.getUser().getIdentifier();
2279 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
2280 if (summaries == null) {
2281 summaries = new ArrayMap<>();
2283 mAutobundledSummaries.put(userId, summaries);
2284 if (!summaries.containsKey(adjustment.getPackage())
2285 && newAutoBundleKey != null) {
2287 final ApplicationInfo appInfo =
2288 adjustedSbn.getNotification().extras.getParcelable(
2289 Notification.EXTRA_BUILDER_APPLICATION_INFO);
2290 final Bundle extras = new Bundle();
2291 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
2292 final Notification summaryNotification =
2293 new Notification.Builder(getContext()).setSmallIcon(
2294 adjustedSbn.getNotification().getSmallIcon())
2295 .setGroupSummary(true)
2296 .setGroup(newAutoBundleKey)
2297 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
2298 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
2299 .setColor(adjustedSbn.getNotification().color)
2302 summaryNotification.extras.putAll(extras);
2303 Intent appIntent = getContext().getPackageManager()
2304 .getLaunchIntentForPackage(adjustment.getPackage());
2305 if (appIntent != null) {
2306 summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
2307 getContext(), 0, appIntent, 0, null,
2308 UserHandle.of(userId));
2310 final StatusBarNotification summarySbn =
2311 new StatusBarNotification(adjustedSbn.getPackageName(),
2312 adjustedSbn.getOpPkg(),
2313 Integer.MAX_VALUE, Adjustment.GROUP_KEY_OVERRIDE_KEY,
2314 adjustedSbn.getUid(), adjustedSbn.getInitialPid(),
2315 summaryNotification, adjustedSbn.getUser(),
2317 System.currentTimeMillis());
2318 summaryRecord = new NotificationRecord(getContext(), summarySbn);
2319 summaries.put(adjustment.getPackage(), summarySbn.getKey());
2322 if (summaryRecord != null) {
2323 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
2329 private String disableNotificationEffects(NotificationRecord record) {
2330 if (mDisableNotificationEffects) {
2331 return "booleanState";
2333 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
2334 return "listenerHints";
2336 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
2342 private void dumpJson(PrintWriter pw, DumpFilter filter) {
2343 JSONObject dump = new JSONObject();
2345 dump.put("service", "Notification Manager");
2346 dump.put("bans", mRankingHelper.dumpBansJson(filter));
2347 dump.put("ranking", mRankingHelper.dumpJson(filter));
2348 dump.put("stats", mUsageStats.dumpJson(filter));
2349 } catch (JSONException e) {
2350 e.printStackTrace();
2355 void dumpImpl(PrintWriter pw, DumpFilter filter) {
2356 pw.print("Current Notification Manager state");
2357 if (filter.filtered) {
2358 pw.print(" (filtered to "); pw.print(filter); pw.print(")");
2362 final boolean zenOnly = filter.filtered && filter.zen;
2365 synchronized (mToastQueue) {
2366 N = mToastQueue.size();
2368 pw.println(" Toast Queue:");
2369 for (int i=0; i<N; i++) {
2370 mToastQueue.get(i).dump(pw, " ", filter);
2377 synchronized (mNotificationList) {
2379 N = mNotificationList.size();
2381 pw.println(" Notification List:");
2382 for (int i=0; i<N; i++) {
2383 final NotificationRecord nr = mNotificationList.get(i);
2384 if (filter.filtered && !filter.matches(nr.sbn)) continue;
2385 nr.dump(pw, " ", getContext(), filter.redact);
2390 if (!filter.filtered) {
2393 pw.println(" Lights List:");
2394 for (int i=0; i<N; i++) {
2400 pw.println(mLights.get(i));
2404 pw.println(" mUseAttentionLight=" + mUseAttentionLight);
2405 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled);
2406 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey);
2407 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey);
2408 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects);
2409 pw.println(" mCallState=" + callStateToString(mCallState));
2410 pw.println(" mSystemReady=" + mSystemReady);
2411 pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
2413 pw.println(" mArchive=" + mArchive.toString());
2414 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
2416 while (iter.hasNext()) {
2417 final StatusBarNotification sbn = iter.next();
2418 if (filter != null && !filter.matches(sbn)) continue;
2419 pw.println(" " + sbn);
2421 if (iter.hasNext()) pw.println(" ...");
2428 pw.println("\n Usage Stats:");
2429 mUsageStats.dump(pw, " ", filter);
2432 if (!filter.filtered || zenOnly) {
2433 pw.println("\n Zen Mode:");
2434 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter);
2435 mZenModeHelper.dump(pw, " ");
2437 pw.println("\n Zen Log:");
2438 ZenLog.dump(pw, " ");
2442 pw.println("\n Ranking Config:");
2443 mRankingHelper.dump(pw, " ", filter);
2445 pw.println("\n Notification listeners:");
2446 mListeners.dump(pw, filter);
2447 pw.print(" mListenerHints: "); pw.println(mListenerHints);
2448 pw.print(" mListenersDisablingEffects: (");
2449 N = mListenersDisablingEffects.size();
2450 for (int i = 0; i < N; i++) {
2451 final int hint = mListenersDisablingEffects.keyAt(i);
2452 if (i > 0) pw.print(';');
2453 pw.print("hint[" + hint + "]:");
2455 final ArraySet<ManagedServiceInfo> listeners =
2456 mListenersDisablingEffects.valueAt(i);
2457 final int listenerSize = listeners.size();
2459 for (int j = 0; j < listenerSize; j++) {
2460 if (i > 0) pw.print(',');
2461 final ManagedServiceInfo listener = listeners.valueAt(i);
2462 pw.print(listener.component);
2466 pw.println("\n mRankerServicePackageName: " + mRankerServicePackageName);
2467 pw.println("\n Notification ranker services:");
2468 mRankerServices.dump(pw, filter);
2470 pw.println("\n Policy access:");
2471 pw.print(" mPolicyAccess: "); pw.println(mPolicyAccess);
2473 pw.println("\n Condition providers:");
2474 mConditionProviders.dump(pw, filter);
2476 pw.println("\n Group summaries:");
2477 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
2478 NotificationRecord r = entry.getValue();
2479 pw.println(" " + entry.getKey() + " -> " + r.getKey());
2480 if (mNotificationsByKey.get(r.getKey()) != r) {
2481 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
2482 r.dump(pw, " ", getContext(), filter.redact);
2489 * The private API only accessible to the system process.
2491 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
2493 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
2494 String tag, int id, Notification notification, int[] idReceived, int userId) {
2495 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
2496 idReceived, userId);
2500 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
2502 checkCallerIsSystem();
2503 synchronized (mNotificationList) {
2504 int i = indexOfNotificationLocked(pkg, null, notificationId, userId);
2506 Log.d(TAG, "stripForegroundServiceFlag: Could not find notification with "
2507 + "pkg=" + pkg + " / id=" + notificationId + " / userId=" + userId);
2510 NotificationRecord r = mNotificationList.get(i);
2511 StatusBarNotification sbn = r.sbn;
2512 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
2513 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove FLAG_FOREGROUND_SERVICE,
2514 // we have to revert to the flags we received initially *and* force remove
2515 // FLAG_FOREGROUND_SERVICE.
2516 sbn.getNotification().flags =
2517 (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
2518 mRankingHelper.sort(mNotificationList);
2519 mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
2524 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
2525 final int callingPid, final String tag, final int id, final Notification notification,
2526 int[] idOut, int incomingUserId) {
2528 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
2529 + " notification=" + notification);
2531 checkCallerIsSystemOrSameApp(pkg);
2532 final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg));
2533 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
2535 final int userId = ActivityManager.handleIncomingUser(callingPid,
2536 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
2537 final UserHandle user = new UserHandle(userId);
2538 // Fix the notification as best we can.
2540 final ApplicationInfo ai = getContext().getPackageManager().getApplicationInfoAsUser(
2541 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
2542 (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
2543 Notification.addFieldsFromContext(ai, userId, notification);
2544 } catch (NameNotFoundException e) {
2545 Slog.e(TAG, "Cannot create a context for sending app", e);
2549 mUsageStats.registerEnqueuedByApp(pkg);
2551 if (pkg == null || notification == null) {
2552 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
2553 + " id=" + id + " notification=" + notification);
2556 // The system can post notifications for any package, let us resolve that.
2557 final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);
2559 final StatusBarNotification n = new StatusBarNotification(
2560 pkg, opPkg, id, tag, notificationUid, callingPid, 0, notification,
2563 // Limit the number of notifications that any given package except the android
2564 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
2565 if (!isSystemNotification && !isNotificationFromListener) {
2566 synchronized (mNotificationList) {
2567 if(mNotificationsByKey.get(n.getKey()) != null) {
2568 // this is an update, rate limit updates only
2569 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
2570 if (appEnqueueRate > mMaxPackageEnqueueRate) {
2571 mUsageStats.registerOverRateQuota(pkg);
2572 final long now = SystemClock.elapsedRealtime();
2573 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
2574 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
2575 + ". Shedding events. package=" + pkg);
2576 mLastOverRateLogTime = now;
2583 final int N = mNotificationList.size();
2584 for (int i=0; i<N; i++) {
2585 final NotificationRecord r = mNotificationList.get(i);
2586 if (r.sbn.getPackageName().equals(pkg) && r.sbn.getUserId() == userId) {
2587 if (r.sbn.getId() == id && TextUtils.equals(r.sbn.getTag(), tag)) {
2588 break; // Allow updating existing notification
2591 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
2592 mUsageStats.registerOverCountQuota(pkg);
2593 Slog.e(TAG, "Package has already posted " + count
2594 + " notifications. Not showing more. package=" + pkg);
2602 // Whitelist pending intents.
2603 if (notification.allPendingIntents != null) {
2604 final int intentCount = notification.allPendingIntents.size();
2605 if (intentCount > 0) {
2606 final ActivityManagerInternal am = LocalServices
2607 .getService(ActivityManagerInternal.class);
2608 final long duration = LocalServices.getService(
2609 DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
2610 for (int i = 0; i < intentCount; i++) {
2611 PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
2612 if (pendingIntent != null) {
2613 am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(), duration);
2620 notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN,
2621 Notification.PRIORITY_MAX);
2623 // setup local book-keeping
2624 final NotificationRecord r = new NotificationRecord(getContext(), n);
2625 mHandler.post(new EnqueueNotificationRunnable(userId, r));
2630 private int resolveNotificationUid(String opPackageName, int callingUid, int userId) {
2631 // The system can post notifications on behalf of any package it wants
2632 if (isCallerSystem() && opPackageName != null && !"android".equals(opPackageName)) {
2634 return getContext().getPackageManager()
2635 .getPackageUidAsUser(opPackageName, userId);
2636 } catch (NameNotFoundException e) {
2643 private class EnqueueNotificationRunnable implements Runnable {
2644 private final NotificationRecord r;
2645 private final int userId;
2647 EnqueueNotificationRunnable(int userId, NotificationRecord r) {
2648 this.userId = userId;
2655 synchronized (mNotificationList) {
2656 final StatusBarNotification n = r.sbn;
2657 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
2658 NotificationRecord old = mNotificationsByKey.get(n.getKey());
2660 // Retain ranking information from previous record
2661 r.copyRankingInformation(old);
2664 final int callingUid = n.getUid();
2665 final int callingPid = n.getInitialPid();
2666 final Notification notification = n.getNotification();
2667 final String pkg = n.getPackageName();
2668 final int id = n.getId();
2669 final String tag = n.getTag();
2670 final boolean isSystemNotification = isUidSystem(callingUid) ||
2671 ("android".equals(pkg));
2673 // Handle grouped notifications and bail out early if we
2674 // can to avoid extracting signals.
2675 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
2677 // This conditional is a dirty hack to limit the logging done on
2678 // behalf of the download manager without affecting other apps.
2679 if (!pkg.equals("com.android.providers.downloads")
2680 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
2681 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
2683 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
2685 EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
2686 pkg, id, tag, userId, notification.toString(),
2690 mRankingHelper.extractSignals(r);
2692 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
2695 if (r.getImportance() == NotificationListenerService.Ranking.IMPORTANCE_NONE
2696 || !noteNotificationOp(pkg, callingUid) || isPackageSuspended) {
2697 if (!isSystemNotification) {
2698 if (isPackageSuspended) {
2699 Slog.e(TAG, "Suppressing notification from package due to package "
2700 + "suspended by administrator.");
2701 mUsageStats.registerSuspendedByAdmin(r);
2703 Slog.e(TAG, "Suppressing notification from package by user request.");
2704 mUsageStats.registerBlocked(r);
2710 // tell the ranker service about the notification
2711 if (mRankerServices.isEnabled()) {
2712 mRankerServices.onNotificationEnqueued(r);
2713 // TODO delay the code below here for 100ms or until there is an answer
2717 int index = indexOfNotificationLocked(n.getKey());
2719 mNotificationList.add(r);
2720 mUsageStats.registerPostedByApp(r);
2722 old = mNotificationList.get(index);
2723 mNotificationList.set(index, r);
2724 mUsageStats.registerUpdatedByApp(r, old);
2725 // Make sure we don't lose the foreground service state.
2726 notification.flags |=
2727 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
2731 mNotificationsByKey.put(n.getKey(), r);
2733 // Ensure if this is a foreground service that the proper additional
2735 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
2736 notification.flags |= Notification.FLAG_ONGOING_EVENT
2737 | Notification.FLAG_NO_CLEAR;
2740 applyZenModeLocked(r);
2741 mRankingHelper.sort(mNotificationList);
2743 if (notification.getSmallIcon() != null) {
2744 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
2745 mListeners.notifyPostedLocked(n, oldSbn);
2747 Slog.e(TAG, "Not posting notification without small icon: " + notification);
2748 if (old != null && !old.isCanceled) {
2749 mListeners.notifyRemovedLocked(n);
2751 // ATTENTION: in a future release we will bail out here
2752 // so that we do not play sounds, show lights, etc. for invalid
2754 Slog.e(TAG, "WARNING: In a future release this will crash the app: "
2755 + n.getPackageName());
2758 buzzBeepBlinkLocked(r);
2764 * Ensures that grouped notification receive their special treatment.
2766 * <p>Cancels group children if the new notification causes a group to lose
2769 * <p>Updates mSummaryByGroupKey.</p>
2771 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
2772 int callingUid, int callingPid) {
2773 StatusBarNotification sbn = r.sbn;
2774 Notification n = sbn.getNotification();
2775 if (n.isGroupSummary() && !sbn.isAppGroup()) {
2776 // notifications without a group shouldn't be a summary, otherwise autobundling can
2778 n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
2781 String group = sbn.getGroupKey();
2782 boolean isSummary = n.isGroupSummary();
2784 Notification oldN = old != null ? old.sbn.getNotification() : null;
2785 String oldGroup = old != null ? old.sbn.getGroupKey() : null;
2786 boolean oldIsSummary = old != null && oldN.isGroupSummary();
2789 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
2790 if (removedSummary != old) {
2792 removedSummary != null ? removedSummary.getKey() : "<null>";
2793 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
2794 ", removed=" + removedKey);
2798 mSummaryByGroupKey.put(group, r);
2801 // Clear out group children of the old notification if the update
2802 // causes the group summary to go away. This happens when the old
2803 // notification was a summary and the new one isn't, or when the old
2804 // notification was a summary and its group key changed.
2805 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
2806 cancelGroupChildrenLocked(old, callingUid, callingPid, null,
2807 REASON_GROUP_SUMMARY_CANCELED, false /* sendDelete */);
2812 void buzzBeepBlinkLocked(NotificationRecord record) {
2813 boolean buzz = false;
2814 boolean beep = false;
2815 boolean blink = false;
2817 final Notification notification = record.sbn.getNotification();
2818 final String key = record.getKey();
2820 // Should this notification make noise, vibe, or use the LED?
2821 final boolean aboveThreshold = record.getImportance() >= IMPORTANCE_DEFAULT;
2822 final boolean canInterrupt = aboveThreshold && !record.isIntercepted();
2823 if (DBG || record.isIntercepted())
2825 "pkg=" + record.sbn.getPackageName() + " canInterrupt=" + canInterrupt +
2826 " intercept=" + record.isIntercepted()
2829 final int currentUser;
2830 final long token = Binder.clearCallingIdentity();
2832 currentUser = ActivityManager.getCurrentUser();
2834 Binder.restoreCallingIdentity(token);
2837 // If we're not supposed to beep, vibrate, etc. then don't.
2838 final String disableEffects = disableNotificationEffects(record);
2839 if (disableEffects != null) {
2840 ZenLog.traceDisableEffects(record, disableEffects);
2843 // Remember if this notification already owns the notification channels.
2844 boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
2845 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
2847 // These are set inside the conditional if the notification is allowed to make noise.
2848 boolean hasValidVibrate = false;
2849 boolean hasValidSound = false;
2850 if (disableEffects == null
2851 && (record.getUserId() == UserHandle.USER_ALL ||
2852 record.getUserId() == currentUser ||
2853 mUserProfiles.isCurrentProfile(record.getUserId()))
2856 && mAudioManager != null) {
2857 if (DBG) Slog.v(TAG, "Interrupting!");
2859 // should we use the default notification sound? (indicated either by
2860 // DEFAULT_SOUND or because notification.sound is pointing at
2861 // Settings.System.NOTIFICATION_SOUND)
2862 final boolean useDefaultSound =
2863 (notification.defaults & Notification.DEFAULT_SOUND) != 0 ||
2864 Settings.System.DEFAULT_NOTIFICATION_URI
2865 .equals(notification.sound);
2867 Uri soundUri = null;
2868 if (useDefaultSound) {
2869 soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
2871 // check to see if the default notification sound is silent
2872 hasValidSound = mSystemNotificationSound != null;
2873 } else if (notification.sound != null) {
2874 soundUri = notification.sound;
2875 hasValidSound = (soundUri != null);
2878 // Does the notification want to specify its own vibration?
2879 final boolean hasCustomVibrate = notification.vibrate != null;
2881 // new in 4.2: if there was supposed to be a sound and we're in vibrate
2882 // mode, and no other vibration is specified, we fall back to vibration
2883 final boolean convertSoundToVibration =
2886 && (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE);
2888 // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
2889 final boolean useDefaultVibrate =
2890 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
2892 hasValidVibrate = useDefaultVibrate || convertSoundToVibration ||
2895 // We can alert, and we're allowed to alert, but if the developer asked us to only do
2896 // it once, and we already have, then don't.
2897 if (!(record.isUpdate
2898 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0)) {
2900 sendAccessibilityEvent(notification, record.sbn.getPackageName());
2902 if (hasValidSound) {
2904 (notification.flags & Notification.FLAG_INSISTENT) != 0;
2905 AudioAttributes audioAttributes = audioAttributesForNotification(notification);
2906 mSoundNotificationKey = key;
2907 // do not play notifications if stream volume is 0 (typically because
2908 // ringer mode is silent) or if there is a user of exclusive audio focus
2909 if ((mAudioManager.getStreamVolume(
2910 AudioAttributes.toLegacyStreamType(audioAttributes)) != 0)
2911 && !mAudioManager.isAudioFocusExclusive()) {
2912 final long identity = Binder.clearCallingIdentity();
2914 final IRingtonePlayer player =
2915 mAudioManager.getRingtonePlayer();
2916 if (player != null) {
2917 if (DBG) Slog.v(TAG, "Playing sound " + soundUri
2918 + " with attributes " + audioAttributes);
2919 player.playAsync(soundUri, record.sbn.getUser(), looping,
2923 } catch (RemoteException e) {
2925 Binder.restoreCallingIdentity(identity);
2930 if (hasValidVibrate && !(mAudioManager.getRingerModeInternal()
2931 == AudioManager.RINGER_MODE_SILENT)) {
2932 mVibrateNotificationKey = key;
2934 if (useDefaultVibrate || convertSoundToVibration) {
2935 // Escalate privileges so we can use the vibrator even if the
2936 // notifying app does not have the VIBRATE permission.
2937 long identity = Binder.clearCallingIdentity();
2939 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
2940 useDefaultVibrate ? mDefaultVibrationPattern
2941 : mFallbackVibrationPattern,
2942 ((notification.flags & Notification.FLAG_INSISTENT) != 0)
2943 ? 0: -1, audioAttributesForNotification(notification));
2946 Binder.restoreCallingIdentity(identity);
2948 } else if (notification.vibrate.length > 1) {
2949 // If you want your own vibration pattern, you need the VIBRATE
2951 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
2952 notification.vibrate,
2953 ((notification.flags & Notification.FLAG_INSISTENT) != 0)
2954 ? 0: -1, audioAttributesForNotification(notification));
2961 // If a notification is updated to remove the actively playing sound or vibrate,
2962 // cancel that feedback now
2963 if (wasBeep && !hasValidSound) {
2966 if (wasBuzz && !hasValidVibrate) {
2967 clearVibrateLocked();
2971 // release the light
2972 boolean wasShowLights = mLights.remove(key);
2973 if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold
2974 && ((record.getSuppressedVisualEffects()
2975 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
2977 updateLightsLocked();
2978 if (mUseAttentionLight) {
2979 mAttentionLight.pulse();
2982 } else if (wasShowLights) {
2983 updateLightsLocked();
2985 if (buzz || beep || blink) {
2986 if (((record.getSuppressedVisualEffects()
2987 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) != 0)) {
2988 if (DBG) Slog.v(TAG, "Suppressed SystemUI from triggering screen on");
2990 EventLogTags.writeNotificationAlert(key,
2991 buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
2992 mHandler.post(mBuzzBeepBlinked);
2997 private static AudioAttributes audioAttributesForNotification(Notification n) {
2998 if (n.audioAttributes != null
2999 && !Notification.AUDIO_ATTRIBUTES_DEFAULT.equals(n.audioAttributes)) {
3000 // the audio attributes are set and different from the default, use them
3001 return n.audioAttributes;
3002 } else if (n.audioStreamType >= 0 && n.audioStreamType < AudioSystem.getNumStreamTypes()) {
3003 // the stream type is valid, use it
3004 return new AudioAttributes.Builder()
3005 .setInternalLegacyStreamType(n.audioStreamType)
3007 } else if (n.audioStreamType == AudioSystem.STREAM_DEFAULT) {
3008 return Notification.AUDIO_ATTRIBUTES_DEFAULT;
3010 Log.w(TAG, String.format("Invalid stream type: %d", n.audioStreamType));
3011 return Notification.AUDIO_ATTRIBUTES_DEFAULT;
3015 void showNextToastLocked() {
3016 ToastRecord record = mToastQueue.get(0);
3017 while (record != null) {
3018 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
3020 record.callback.show(record.token);
3021 scheduleTimeoutLocked(record);
3023 } catch (RemoteException e) {
3024 Slog.w(TAG, "Object died trying to show notification " + record.callback
3025 + " in package " + record.pkg);
3026 // remove it from the list and let the process die
3027 int index = mToastQueue.indexOf(record);
3029 mToastQueue.remove(index);
3031 keepProcessAliveIfNeededLocked(record.pid);
3032 if (mToastQueue.size() > 0) {
3033 record = mToastQueue.get(0);
3041 void cancelToastLocked(int index) {
3042 ToastRecord record = mToastQueue.get(index);
3044 record.callback.hide();
3045 } catch (RemoteException e) {
3046 Slog.w(TAG, "Object died trying to hide notification " + record.callback
3047 + " in package " + record.pkg);
3048 // don't worry about this, we're about to remove it from
3052 ToastRecord lastToast = mToastQueue.remove(index);
3053 mWindowManagerInternal.removeWindowToken(lastToast.token, true);
3055 keepProcessAliveIfNeededLocked(record.pid);
3056 if (mToastQueue.size() > 0) {
3057 // Show the next one. If the callback fails, this will remove
3058 // it from the list, so don't assume that the list hasn't changed
3059 // after this point.
3060 showNextToastLocked();
3064 private void scheduleTimeoutLocked(ToastRecord r)
3066 mHandler.removeCallbacksAndMessages(r);
3067 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
3068 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
3069 mHandler.sendMessageDelayed(m, delay);
3072 private void handleTimeout(ToastRecord record)
3074 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
3075 synchronized (mToastQueue) {
3076 int index = indexOfToastLocked(record.pkg, record.callback);
3078 cancelToastLocked(index);
3083 // lock on mToastQueue
3084 int indexOfToastLocked(String pkg, ITransientNotification callback)
3086 IBinder cbak = callback.asBinder();
3087 ArrayList<ToastRecord> list = mToastQueue;
3088 int len = list.size();
3089 for (int i=0; i<len; i++) {
3090 ToastRecord r = list.get(i);
3091 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
3098 // lock on mToastQueue
3099 void keepProcessAliveIfNeededLocked(int pid)
3101 int toastCount = 0; // toasts from this pid
3102 ArrayList<ToastRecord> list = mToastQueue;
3103 int N = list.size();
3104 for (int i=0; i<N; i++) {
3105 ToastRecord r = list.get(i);
3111 mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
3112 } catch (RemoteException e) {
3113 // Shouldn't happen.
3117 private void handleRankingReconsideration(Message message) {
3118 if (!(message.obj instanceof RankingReconsideration)) return;
3119 RankingReconsideration recon = (RankingReconsideration) message.obj;
3122 synchronized (mNotificationList) {
3123 final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
3124 if (record == null) {
3127 int indexBefore = findNotificationRecordIndexLocked(record);
3128 boolean interceptBefore = record.isIntercepted();
3129 int visibilityBefore = record.getPackageVisibilityOverride();
3130 recon.applyChangesLocked(record);
3131 applyZenModeLocked(record);
3132 mRankingHelper.sort(mNotificationList);
3133 int indexAfter = findNotificationRecordIndexLocked(record);
3134 boolean interceptAfter = record.isIntercepted();
3135 int visibilityAfter = record.getPackageVisibilityOverride();
3136 changed = indexBefore != indexAfter || interceptBefore != interceptAfter
3137 || visibilityBefore != visibilityAfter;
3138 if (interceptBefore && !interceptAfter) {
3139 buzzBeepBlinkLocked(record);
3143 scheduleSendRankingUpdate();
3147 private void handleRankingSort() {
3148 synchronized (mNotificationList) {
3149 final int N = mNotificationList.size();
3150 ArrayList<String> orderBefore = new ArrayList<String>(N);
3151 ArrayList<String> groupOverrideBefore = new ArrayList<>(N);
3152 int[] visibilities = new int[N];
3153 int[] importances = new int[N];
3154 for (int i = 0; i < N; i++) {
3155 final NotificationRecord r = mNotificationList.get(i);
3156 orderBefore.add(r.getKey());
3157 groupOverrideBefore.add(r.sbn.getGroupKey());
3158 visibilities[i] = r.getPackageVisibilityOverride();
3159 importances[i] = r.getImportance();
3160 mRankingHelper.extractSignals(r);
3162 mRankingHelper.sort(mNotificationList);
3163 for (int i = 0; i < N; i++) {
3164 final NotificationRecord r = mNotificationList.get(i);
3165 if (!orderBefore.get(i).equals(r.getKey())
3166 || visibilities[i] != r.getPackageVisibilityOverride()
3167 || importances[i] != r.getImportance()
3168 || !groupOverrideBefore.get(i).equals(r.sbn.getGroupKey())) {
3169 scheduleSendRankingUpdate();
3176 private void recordCallerLocked(NotificationRecord record) {
3177 if (mZenModeHelper.isCall(record)) {
3178 mZenModeHelper.recordCaller(record);
3182 // let zen mode evaluate this record
3183 private void applyZenModeLocked(NotificationRecord record) {
3184 record.setIntercepted(mZenModeHelper.shouldIntercept(record));
3185 if (record.isIntercepted()) {
3186 int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
3187 ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
3188 | (mZenModeHelper.shouldSuppressWhenScreenOn()
3189 ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
3190 record.setSuppressedVisualEffects(suppressed);
3194 // lock on mNotificationList
3195 private int findNotificationRecordIndexLocked(NotificationRecord target) {
3196 return mRankingHelper.indexOf(mNotificationList, target);
3199 private void scheduleSendRankingUpdate() {
3200 if (!mHandler.hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
3201 Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE);
3202 mHandler.sendMessage(m);
3206 private void handleSendRankingUpdate() {
3207 synchronized (mNotificationList) {
3208 mListeners.notifyRankingUpdateLocked();
3212 private void scheduleListenerHintsChanged(int state) {
3213 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
3214 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
3217 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
3218 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
3219 mHandler.obtainMessage(
3220 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
3221 listenerInterruptionFilter,
3225 private void handleListenerHintsChanged(int hints) {
3226 synchronized (mNotificationList) {
3227 mListeners.notifyListenerHintsChangedLocked(hints);
3231 private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
3232 synchronized (mNotificationList) {
3233 mListeners.notifyInterruptionFilterChanged(interruptionFilter);
3237 private final class WorkerHandler extends Handler
3240 public void handleMessage(Message msg)
3244 case MESSAGE_TIMEOUT:
3245 handleTimeout((ToastRecord)msg.obj);
3247 case MESSAGE_SAVE_POLICY_FILE:
3248 handleSavePolicyFile();
3250 case MESSAGE_SEND_RANKING_UPDATE:
3251 handleSendRankingUpdate();
3253 case MESSAGE_LISTENER_HINTS_CHANGED:
3254 handleListenerHintsChanged(msg.arg1);
3256 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
3257 handleListenerInterruptionFilterChanged(msg.arg1);
3264 private final class RankingHandlerWorker extends Handler implements RankingHandler
3266 public RankingHandlerWorker(Looper looper) {
3271 public void handleMessage(Message msg) {
3273 case MESSAGE_RECONSIDER_RANKING:
3274 handleRankingReconsideration(msg);
3276 case MESSAGE_RANKING_SORT:
3277 handleRankingSort();
3282 public void requestSort() {
3283 removeMessages(MESSAGE_RANKING_SORT);
3284 sendEmptyMessage(MESSAGE_RANKING_SORT);
3287 public void requestReconsideration(RankingReconsideration recon) {
3288 Message m = Message.obtain(this,
3289 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
3290 long delay = recon.getDelay(TimeUnit.MILLISECONDS);
3291 sendMessageDelayed(m, delay);
3296 // ============================================================================
3297 static int clamp(int x, int low, int high) {
3298 return (x < low) ? low : ((x > high) ? high : x);
3301 void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
3302 AccessibilityManager manager = AccessibilityManager.getInstance(getContext());
3303 if (!manager.isEnabled()) {
3307 AccessibilityEvent event =
3308 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
3309 event.setPackageName(packageName);
3310 event.setClassName(Notification.class.getName());
3311 event.setParcelableData(notification);
3312 CharSequence tickerText = notification.tickerText;
3313 if (!TextUtils.isEmpty(tickerText)) {
3314 event.getText().add(tickerText);
3317 manager.sendAccessibilityEvent(event);
3320 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) {
3323 recordCallerLocked(r);
3327 if (r.getNotification().deleteIntent != null) {
3329 r.getNotification().deleteIntent.send();
3330 } catch (PendingIntent.CanceledException ex) {
3331 // do nothing - there's no relevant way to recover, and
3332 // no reason to let this propagate
3333 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
3339 if (r.getNotification().getSmallIcon() != null) {
3340 r.isCanceled = true;
3341 mListeners.notifyRemovedLocked(r.sbn);
3344 final String canceledKey = r.getKey();
3347 if (canceledKey.equals(mSoundNotificationKey)) {
3348 mSoundNotificationKey = null;
3349 final long identity = Binder.clearCallingIdentity();
3351 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
3352 if (player != null) {
3355 } catch (RemoteException e) {
3357 Binder.restoreCallingIdentity(identity);
3362 if (canceledKey.equals(mVibrateNotificationKey)) {
3363 mVibrateNotificationKey = null;
3364 long identity = Binder.clearCallingIdentity();
3369 Binder.restoreCallingIdentity(identity);
3374 mLights.remove(canceledKey);
3376 // Record usage stats
3377 // TODO: add unbundling stats?
3379 case REASON_DELEGATE_CANCEL:
3380 case REASON_DELEGATE_CANCEL_ALL:
3381 case REASON_LISTENER_CANCEL:
3382 case REASON_LISTENER_CANCEL_ALL:
3383 mUsageStats.registerDismissedByUser(r);
3385 case REASON_APP_CANCEL:
3386 case REASON_APP_CANCEL_ALL:
3387 mUsageStats.registerRemovedByApp(r);
3391 mNotificationsByKey.remove(r.sbn.getKey());
3392 String groupKey = r.getGroupKey();
3393 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
3394 if (groupSummary != null && groupSummary.getKey().equals(r.getKey())) {
3395 mSummaryByGroupKey.remove(groupKey);
3397 final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
3398 if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
3399 summaries.remove(r.sbn.getPackageName());
3402 // Save it for users of getHistoricalNotifications()
3403 mArchive.record(r.sbn);
3405 final long now = System.currentTimeMillis();
3406 EventLogTags.writeNotificationCanceled(canceledKey, reason,
3407 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
3411 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
3412 * and none of the {@code mustNotHaveFlags}.
3414 void cancelNotification(final int callingUid, final int callingPid,
3415 final String pkg, final String tag, final int id,
3416 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
3417 final int userId, final int reason, final ManagedServiceInfo listener) {
3418 // In enqueueNotificationInternal notifications are added by scheduling the
3419 // work on the worker handler. Hence, we also schedule the cancel on this
3420 // handler to avoid a scenario where an add notification call followed by a
3421 // remove notification call ends up in not removing the notification.
3422 mHandler.post(new Runnable() {
3425 String listenerName = listener == null ? null : listener.component.toShortString();
3426 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
3427 userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
3429 synchronized (mNotificationList) {
3430 int index = indexOfNotificationLocked(pkg, tag, id, userId);
3432 NotificationRecord r = mNotificationList.get(index);
3434 // Ideally we'd do this in the caller of this method. However, that would
3435 // require the caller to also find the notification.
3436 if (reason == REASON_DELEGATE_CLICK) {
3437 mUsageStats.registerClickedByUser(r);
3440 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
3443 if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
3447 mNotificationList.remove(index);
3449 cancelNotificationLocked(r, sendDelete, reason);
3450 cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
3451 REASON_GROUP_SUMMARY_CANCELED, sendDelete);
3452 updateLightsLocked();
3460 * Determine whether the userId applies to the notification in question, either because
3461 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
3463 private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
3465 // looking for USER_ALL notifications? match everything
3466 userId == UserHandle.USER_ALL
3467 // a notification sent to USER_ALL matches any query
3468 || r.getUserId() == UserHandle.USER_ALL
3469 // an exact user match
3470 || r.getUserId() == userId;
3474 * Determine whether the userId applies to the notification in question, either because
3475 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
3476 * because it matches one of the users profiles.
3478 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
3479 return notificationMatchesUserId(r, userId)
3480 || mUserProfiles.isCurrentProfile(r.getUserId());
3484 * Cancels all notifications from a given package that have all of the
3485 * {@code mustHaveFlags}.
3487 boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags,
3488 int mustNotHaveFlags, boolean doit, int userId, int reason,
3489 ManagedServiceInfo listener) {
3490 String listenerName = listener == null ? null : listener.component.toShortString();
3491 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
3492 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
3495 synchronized (mNotificationList) {
3496 final int N = mNotificationList.size();
3497 ArrayList<NotificationRecord> canceledNotifications = null;
3498 for (int i = N-1; i >= 0; --i) {
3499 NotificationRecord r = mNotificationList.get(i);
3500 if (!notificationMatchesUserId(r, userId)) {
3503 // Don't remove notifications to all, if there's no package name specified
3504 if (r.getUserId() == UserHandle.USER_ALL && pkg == null) {
3507 if ((r.getFlags() & mustHaveFlags) != mustHaveFlags) {
3510 if ((r.getFlags() & mustNotHaveFlags) != 0) {
3513 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
3516 if (canceledNotifications == null) {
3517 canceledNotifications = new ArrayList<>();
3519 canceledNotifications.add(r);
3523 mNotificationList.remove(i);
3524 cancelNotificationLocked(r, false, reason);
3526 if (doit && canceledNotifications != null) {
3527 final int M = canceledNotifications.size();
3528 for (int i = 0; i < M; i++) {
3529 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
3530 listenerName, REASON_GROUP_SUMMARY_CANCELED, false /* sendDelete */);
3533 if (canceledNotifications != null) {
3534 updateLightsLocked();
3536 return canceledNotifications != null;
3540 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
3541 ManagedServiceInfo listener, boolean includeCurrentProfiles) {
3542 String listenerName = listener == null ? null : listener.component.toShortString();
3543 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
3544 null, userId, 0, 0, reason, listenerName);
3546 ArrayList<NotificationRecord> canceledNotifications = null;
3547 final int N = mNotificationList.size();
3548 for (int i=N-1; i>=0; i--) {
3549 NotificationRecord r = mNotificationList.get(i);
3550 if (includeCurrentProfiles) {
3551 if (!notificationMatchesCurrentProfiles(r, userId)) {
3555 if (!notificationMatchesUserId(r, userId)) {
3560 if ((r.getFlags() & (Notification.FLAG_ONGOING_EVENT
3561 | Notification.FLAG_NO_CLEAR)) == 0) {
3562 mNotificationList.remove(i);
3563 cancelNotificationLocked(r, true, reason);
3564 // Make a note so we can cancel children later.
3565 if (canceledNotifications == null) {
3566 canceledNotifications = new ArrayList<>();
3568 canceledNotifications.add(r);
3571 int M = canceledNotifications != null ? canceledNotifications.size() : 0;
3572 for (int i = 0; i < M; i++) {
3573 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
3574 listenerName, REASON_GROUP_SUMMARY_CANCELED, false /* sendDelete */);
3576 updateLightsLocked();
3579 // Warning: The caller is responsible for invoking updateLightsLocked().
3580 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
3581 String listenerName, int reason, boolean sendDelete) {
3582 Notification n = r.getNotification();
3583 if (!n.isGroupSummary()) {
3587 String pkg = r.sbn.getPackageName();
3588 int userId = r.getUserId();
3591 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
3595 final int N = mNotificationList.size();
3596 for (int i = N - 1; i >= 0; i--) {
3597 NotificationRecord childR = mNotificationList.get(i);
3598 StatusBarNotification childSbn = childR.sbn;
3599 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
3600 childR.getGroupKey().equals(r.getGroupKey())
3601 && (childR.getFlags() & Notification.FLAG_FOREGROUND_SERVICE) == 0) {
3602 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
3603 childSbn.getTag(), userId, 0, 0, reason, listenerName);
3604 mNotificationList.remove(i);
3605 cancelNotificationLocked(childR, sendDelete, reason);
3610 // lock on mNotificationList
3611 void updateLightsLocked()
3613 // handle notification lights
3614 NotificationRecord ledNotification = null;
3615 while (ledNotification == null && !mLights.isEmpty()) {
3616 final String owner = mLights.get(mLights.size() - 1);
3617 ledNotification = mNotificationsByKey.get(owner);
3618 if (ledNotification == null) {
3619 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
3620 mLights.remove(owner);
3624 // Don't flash while we are in a call or screen is on
3625 if (ledNotification == null || mInCall || mScreenOn) {
3626 mNotificationLight.turnOff();
3627 if (mStatusBar != null) {
3628 mStatusBar.notificationLightOff();
3631 final Notification ledno = ledNotification.sbn.getNotification();
3632 int ledARGB = ledno.ledARGB;
3633 int ledOnMS = ledno.ledOnMS;
3634 int ledOffMS = ledno.ledOffMS;
3635 if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0) {
3636 ledARGB = mDefaultNotificationColor;
3637 ledOnMS = mDefaultNotificationLedOn;
3638 ledOffMS = mDefaultNotificationLedOff;
3640 if (mNotificationPulseEnabled) {
3642 mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED,
3645 if (mStatusBar != null) {
3646 // let SystemUI make an independent decision
3647 mStatusBar.notificationLightPulse(ledARGB, ledOnMS, ledOffMS);
3652 // lock on mNotificationList
3653 int indexOfNotificationLocked(String pkg, String tag, int id, int userId)
3655 ArrayList<NotificationRecord> list = mNotificationList;
3656 final int len = list.size();
3657 for (int i=0; i<len; i++) {
3658 NotificationRecord r = list.get(i);
3659 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
3660 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
3667 // lock on mNotificationList
3668 int indexOfNotificationLocked(String key) {
3669 final int N = mNotificationList.size();
3670 for (int i = 0; i < N; i++) {
3671 if (key.equals(mNotificationList.get(i).getKey())) {
3678 private void updateNotificationPulse() {
3679 synchronized (mNotificationList) {
3680 updateLightsLocked();
3684 private static boolean isUidSystem(int uid) {
3685 final int appid = UserHandle.getAppId(uid);
3686 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
3689 private static boolean isCallerSystem() {
3690 return isUidSystem(Binder.getCallingUid());
3693 private static void checkCallerIsSystem() {
3694 if (isCallerSystem()) {
3697 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
3700 private static void checkCallerIsSystemOrSameApp(String pkg) {
3701 if (isCallerSystem()) {
3704 checkCallerIsSameApp(pkg);
3707 private static void checkCallerIsSameApp(String pkg) {
3708 final int uid = Binder.getCallingUid();
3710 ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
3711 pkg, 0, UserHandle.getCallingUserId());
3713 throw new SecurityException("Unknown package " + pkg);
3715 if (!UserHandle.isSameApp(ai.uid, uid)) {
3716 throw new SecurityException("Calling uid " + uid + " gave package"
3717 + pkg + " which is owned by uid " + ai.uid);
3719 } catch (RemoteException re) {
3720 throw new SecurityException("Unknown package " + pkg + "\n" + re);
3724 private static String callStateToString(int state) {
3726 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
3727 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
3728 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
3729 default: return "CALL_STATE_UNKNOWN_" + state;
3733 private void listenForCallState() {
3734 TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
3736 public void onCallStateChanged(int state, String incomingNumber) {
3737 if (mCallState == state) return;
3738 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
3741 }, PhoneStateListener.LISTEN_CALL_STATE);
3745 * Generates a NotificationRankingUpdate from 'sbns', considering only
3746 * notifications visible to the given listener.
3748 * <p>Caller must hold a lock on mNotificationList.</p>
3750 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
3751 final int N = mNotificationList.size();
3752 ArrayList<String> keys = new ArrayList<String>(N);
3753 ArrayList<String> interceptedKeys = new ArrayList<String>(N);
3754 ArrayList<Integer> importance = new ArrayList<>(N);
3755 Bundle overrideGroupKeys = new Bundle();
3756 Bundle visibilityOverrides = new Bundle();
3757 Bundle suppressedVisualEffects = new Bundle();
3758 Bundle explanation = new Bundle();
3759 for (int i = 0; i < N; i++) {
3760 NotificationRecord record = mNotificationList.get(i);
3761 if (!isVisibleToListener(record.sbn, info)) {
3764 final String key = record.sbn.getKey();
3766 importance.add(record.getImportance());
3767 if (record.getImportanceExplanation() != null) {
3768 explanation.putCharSequence(key, record.getImportanceExplanation());
3770 if (record.isIntercepted()) {
3771 interceptedKeys.add(key);
3774 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
3775 if (record.getPackageVisibilityOverride()
3776 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
3777 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
3779 overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
3781 final int M = keys.size();
3782 String[] keysAr = keys.toArray(new String[M]);
3783 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
3784 int[] importanceAr = new int[M];
3785 for (int i = 0; i < M; i++) {
3786 importanceAr[i] = importance.get(i);
3788 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
3789 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys);
3792 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
3793 if (!listener.enabledAndUserMatches(sbn.getUserId())) {
3796 // TODO: remove this for older listeners.
3800 private boolean isPackageSuspendedForUser(String pkg, int uid) {
3801 int userId = UserHandle.getUserId(uid);
3803 return AppGlobals.getPackageManager().isPackageSuspendedForUser(pkg, userId);
3804 } catch (RemoteException re) {
3805 throw new SecurityException("Could not talk to package manager service");
3806 } catch (IllegalArgumentException ex) {
3807 // Package not found.
3812 private class TrimCache {
3813 StatusBarNotification heavy;
3814 StatusBarNotification sbnClone;
3815 StatusBarNotification sbnCloneLight;
3817 TrimCache(StatusBarNotification sbn) {
3821 StatusBarNotification ForListener(ManagedServiceInfo info) {
3822 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
3823 if (sbnCloneLight == null) {
3824 sbnCloneLight = heavy.cloneLight();
3826 return sbnCloneLight;
3828 if (sbnClone == null) {
3829 sbnClone = heavy.clone();
3836 public class NotificationRankers extends ManagedServices {
3838 public NotificationRankers() {
3839 super(getContext(), mHandler, mNotificationList, mUserProfiles);
3843 protected Config getConfig() {
3844 Config c = new Config();
3845 c.caption = "notification ranker service";
3846 c.serviceInterface = NotificationRankerService.SERVICE_INTERFACE;
3847 c.secureSettingName = null;
3848 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_RANKER_SERVICE;
3849 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
3850 c.clientLabel = R.string.notification_ranker_binding_label;
3855 protected IInterface asInterface(IBinder binder) {
3856 return INotificationListener.Stub.asInterface(binder);
3860 protected boolean checkType(IInterface service) {
3861 return service instanceof INotificationListener;
3865 protected void onServiceAdded(ManagedServiceInfo info) {
3866 mListeners.registerGuestService(info);
3870 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
3871 mListeners.unregisterService(removed.service, removed.userid);
3874 public void onNotificationEnqueued(final NotificationRecord r) {
3875 final StatusBarNotification sbn = r.sbn;
3876 TrimCache trimCache = new TrimCache(sbn);
3878 // mServices is the list inside ManagedServices of all the rankers,
3879 // There should be only one, but it's a list, so while we enforce
3880 // singularity elsewhere, we keep it general here, to avoid surprises.
3881 for (final ManagedServiceInfo info : NotificationRankers.this.mServices) {
3882 boolean sbnVisible = isVisibleToListener(sbn, info);
3887 final int importance = r.getImportance();
3888 final boolean fromUser = r.isImportanceFromUser();
3889 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
3890 mHandler.post(new Runnable() {
3893 notifyEnqueued(info, sbnToPost, importance, fromUser);
3899 private void notifyEnqueued(final ManagedServiceInfo info,
3900 final StatusBarNotification sbn, int importance, boolean fromUser) {
3901 final INotificationListener ranker = (INotificationListener) info.service;
3902 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
3904 ranker.onNotificationEnqueued(sbnHolder, importance, fromUser);
3905 } catch (RemoteException ex) {
3906 Log.e(TAG, "unable to notify ranker (enqueued): " + ranker, ex);
3910 public boolean isEnabled() {
3911 return !mServices.isEmpty();
3915 public void onUserSwitched(int user) {
3916 synchronized (mNotificationList) {
3917 int i = mServices.size()-1;
3919 final ManagedServiceInfo info = mServices.get(i);
3920 unregisterService(info.service, info.userid);
3927 public void onPackagesChanged(boolean removingPackage, String[] pkgList) {
3928 if (DEBUG) Slog.d(TAG, "onPackagesChanged removingPackage=" + removingPackage
3929 + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList)));
3930 if (mRankerServicePackageName == null) {
3934 if (pkgList != null && (pkgList.length > 0) && !removingPackage) {
3935 for (String pkgName : pkgList) {
3936 if (mRankerServicePackageName.equals(pkgName)) {
3943 protected void registerRanker() {
3944 // Find the updatable ranker and register it.
3945 if (mRankerServicePackageName == null) {
3946 Slog.w(TAG, "could not start ranker service: no package specified!");
3949 Set<ComponentName> rankerComponents = queryPackageForServices(
3950 mRankerServicePackageName, UserHandle.USER_SYSTEM);
3951 Iterator<ComponentName> iterator = rankerComponents.iterator();
3952 if (iterator.hasNext()) {
3953 ComponentName rankerComponent = iterator.next();
3954 if (iterator.hasNext()) {
3955 Slog.e(TAG, "found multiple ranker services:" + rankerComponents);
3957 registerSystemService(rankerComponent, UserHandle.USER_SYSTEM);
3960 Slog.w(TAG, "could not start ranker service: none found");
3965 public class NotificationListeners extends ManagedServices {
3967 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
3969 public NotificationListeners() {
3970 super(getContext(), mHandler, mNotificationList, mUserProfiles);
3974 protected Config getConfig() {
3975 Config c = new Config();
3976 c.caption = "notification listener";
3977 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
3978 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
3979 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
3980 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
3981 c.clientLabel = R.string.notification_listener_binding_label;
3986 protected IInterface asInterface(IBinder binder) {
3987 return INotificationListener.Stub.asInterface(binder);
3991 protected boolean checkType(IInterface service) {
3992 return service instanceof INotificationListener;
3996 public void onServiceAdded(ManagedServiceInfo info) {
3997 final INotificationListener listener = (INotificationListener) info.service;
3998 final NotificationRankingUpdate update;
3999 synchronized (mNotificationList) {
4000 update = makeRankingUpdateLocked(info);
4003 listener.onListenerConnected(update);
4004 } catch (RemoteException e) {
4010 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
4011 if (removeDisabledHints(removed)) {
4012 updateListenerHintsLocked();
4013 updateEffectsSuppressorLocked();
4015 mLightTrimListeners.remove(removed);
4018 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
4019 if (trim == TRIM_LIGHT) {
4020 mLightTrimListeners.add(info);
4022 mLightTrimListeners.remove(info);
4026 public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
4027 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
4031 * asynchronously notify all listeners about a new notification
4034 * Also takes care of removing a notification that has been visible to a listener before,
4035 * but isn't anymore.
4037 public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
4038 // Lazily initialized snapshots of the notification.
4039 TrimCache trimCache = new TrimCache(sbn);
4041 for (final ManagedServiceInfo info : mServices) {
4042 boolean sbnVisible = isVisibleToListener(sbn, info);
4043 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
4044 // This notification hasn't been and still isn't visible -> ignore.
4045 if (!oldSbnVisible && !sbnVisible) {
4048 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
4050 // This notification became invisible -> remove the old one.
4051 if (oldSbnVisible && !sbnVisible) {
4052 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
4053 mHandler.post(new Runnable() {
4056 notifyRemoved(info, oldSbnLightClone, update);
4062 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
4063 mHandler.post(new Runnable() {
4066 notifyPosted(info, sbnToPost, update);
4073 * asynchronously notify all listeners about a removed notification
4075 public void notifyRemovedLocked(StatusBarNotification sbn) {
4076 // make a copy in case changes are made to the underlying Notification object
4077 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
4079 final StatusBarNotification sbnLight = sbn.cloneLight();
4080 for (final ManagedServiceInfo info : mServices) {
4081 if (!isVisibleToListener(sbn, info)) {
4084 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
4085 mHandler.post(new Runnable() {
4088 notifyRemoved(info, sbnLight, update);
4095 * asynchronously notify all listeners about a reordering of notifications
4097 public void notifyRankingUpdateLocked() {
4098 for (final ManagedServiceInfo serviceInfo : mServices) {
4099 if (!serviceInfo.isEnabledForCurrentProfiles()) {
4102 final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
4103 mHandler.post(new Runnable() {
4106 notifyRankingUpdate(serviceInfo, update);
4112 public void notifyListenerHintsChangedLocked(final int hints) {
4113 for (final ManagedServiceInfo serviceInfo : mServices) {
4114 if (!serviceInfo.isEnabledForCurrentProfiles()) {
4117 mHandler.post(new Runnable() {
4120 notifyListenerHintsChanged(serviceInfo, hints);
4126 public void notifyInterruptionFilterChanged(final int interruptionFilter) {
4127 for (final ManagedServiceInfo serviceInfo : mServices) {
4128 if (!serviceInfo.isEnabledForCurrentProfiles()) {
4131 mHandler.post(new Runnable() {
4134 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
4140 private void notifyPosted(final ManagedServiceInfo info,
4141 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
4142 final INotificationListener listener = (INotificationListener)info.service;
4143 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
4145 listener.onNotificationPosted(sbnHolder, rankingUpdate);
4146 } catch (RemoteException ex) {
4147 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
4151 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
4152 NotificationRankingUpdate rankingUpdate) {
4153 if (!info.enabledAndUserMatches(sbn.getUserId())) {
4156 final INotificationListener listener = (INotificationListener) info.service;
4157 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
4159 listener.onNotificationRemoved(sbnHolder, rankingUpdate);
4160 } catch (RemoteException ex) {
4161 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
4165 private void notifyRankingUpdate(ManagedServiceInfo info,
4166 NotificationRankingUpdate rankingUpdate) {
4167 final INotificationListener listener = (INotificationListener) info.service;
4169 listener.onNotificationRankingUpdate(rankingUpdate);
4170 } catch (RemoteException ex) {
4171 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
4175 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
4176 final INotificationListener listener = (INotificationListener) info.service;
4178 listener.onListenerHintsChanged(hints);
4179 } catch (RemoteException ex) {
4180 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
4184 private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
4185 int interruptionFilter) {
4186 final INotificationListener listener = (INotificationListener) info.service;
4188 listener.onInterruptionFilterChanged(interruptionFilter);
4189 } catch (RemoteException ex) {
4190 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
4194 private boolean isListenerPackage(String packageName) {
4195 if (packageName == null) {
4198 // TODO: clean up locking object later
4199 synchronized (mNotificationList) {
4200 for (final ManagedServiceInfo serviceInfo : mServices) {
4201 if (packageName.equals(serviceInfo.component.getPackageName())) {
4210 public static final class DumpFilter {
4211 public boolean filtered = false;
4212 public String pkgFilter;
4215 public boolean stats;
4216 public boolean redact = true;
4218 public static DumpFilter parseFromArguments(String[] args) {
4219 final DumpFilter filter = new DumpFilter();
4220 for (int ai = 0; ai < args.length; ai++) {
4221 final String a = args[ai];
4222 if ("--noredact".equals(a) || "--reveal".equals(a)) {
4223 filter.redact = false;
4224 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
4225 if (ai < args.length-1) {
4227 filter.pkgFilter = args[ai].trim().toLowerCase();
4228 if (filter.pkgFilter.isEmpty()) {
4229 filter.pkgFilter = null;
4231 filter.filtered = true;
4234 } else if ("--zen".equals(a) || "zen".equals(a)) {
4235 filter.filtered = true;
4237 } else if ("--stats".equals(a)) {
4238 filter.stats = true;
4239 if (ai < args.length-1) {
4241 filter.since = Long.valueOf(args[ai]);
4250 public boolean matches(StatusBarNotification sbn) {
4251 if (!filtered) return true;
4252 return zen ? true : sbn != null
4253 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
4256 public boolean matches(ComponentName component) {
4257 if (!filtered) return true;
4258 return zen ? true : component != null && matches(component.getPackageName());
4261 public boolean matches(String pkg) {
4262 if (!filtered) return true;
4263 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
4267 public String toString() {
4268 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
4273 * Wrapper for a StatusBarNotification object that allows transfer across a oneway
4274 * binder without sending large amounts of data over a oneway transaction.
4276 private static final class StatusBarNotificationHolder
4277 extends IStatusBarNotificationHolder.Stub {
4278 private StatusBarNotification mValue;
4280 public StatusBarNotificationHolder(StatusBarNotification value) {
4284 /** Get the held value and clear it. This function should only be called once per holder */
4286 public StatusBarNotification get() {
4287 StatusBarNotification value = mValue;
4293 private final class PolicyAccess {
4294 private static final String SEPARATOR = ":";
4295 private final String[] PERM = {
4296 android.Manifest.permission.ACCESS_NOTIFICATION_POLICY
4299 public boolean isPackageGranted(String pkg) {
4300 return pkg != null && getGrantedPackages().contains(pkg);
4303 public void put(String pkg, boolean granted) {
4304 if (pkg == null) return;
4305 final ArraySet<String> pkgs = getGrantedPackages();
4308 changed = pkgs.add(pkg);
4310 changed = pkgs.remove(pkg);
4312 if (!changed) return;
4313 final String setting = TextUtils.join(SEPARATOR, pkgs);
4314 final int currentUser = ActivityManager.getCurrentUser();
4315 Settings.Secure.putStringForUser(getContext().getContentResolver(),
4316 Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
4319 getContext().sendBroadcastAsUser(new Intent(NotificationManager
4320 .ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
4322 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), new UserHandle(currentUser), null);
4325 public ArraySet<String> getGrantedPackages() {
4326 final ArraySet<String> pkgs = new ArraySet<>();
4328 long identity = Binder.clearCallingIdentity();
4330 final String setting = Settings.Secure.getStringForUser(
4331 getContext().getContentResolver(),
4332 Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
4333 ActivityManager.getCurrentUser());
4334 if (setting != null) {
4335 final String[] tokens = setting.split(SEPARATOR);
4336 for (int i = 0; i < tokens.length; i++) {
4337 String token = tokens[i];
4338 if (token != null) {
4339 token = token.trim();
4341 if (TextUtils.isEmpty(token)) {
4348 Binder.restoreCallingIdentity(identity);
4353 public String[] getRequestingPackages() throws RemoteException {
4354 final ParceledListSlice list = AppGlobals.getPackageManager()
4355 .getPackagesHoldingPermissions(PERM, 0 /*flags*/,
4356 ActivityManager.getCurrentUser());
4357 final List<PackageInfo> pkgs = list.getList();
4358 if (pkgs == null || pkgs.isEmpty()) return new String[0];
4359 final int N = pkgs.size();
4360 final String[] rt = new String[N];
4361 for (int i = 0; i < N; i++) {
4362 rt[i] = pkgs.get(i).packageName;