2 * Copyright (C) 2007 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.server.notification;
19 import static android.service.notification.NotificationRankerService.REASON_APP_CANCEL;
20 import static android.service.notification.NotificationRankerService.REASON_APP_CANCEL_ALL;
21 import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CANCEL;
22 import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CANCEL_ALL;
23 import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CLICK;
24 import static android.service.notification.NotificationRankerService.REASON_DELEGATE_ERROR;
25 import static android.service.notification.NotificationRankerService.REASON_GROUP_SUMMARY_CANCELED;
26 import static android.service.notification.NotificationRankerService.REASON_LISTENER_CANCEL;
27 import static android.service.notification.NotificationRankerService.REASON_LISTENER_CANCEL_ALL;
28 import static android.service.notification.NotificationRankerService.REASON_PACKAGE_BANNED;
29 import static android.service.notification.NotificationRankerService.REASON_PACKAGE_CHANGED;
30 import static android.service.notification.NotificationRankerService.REASON_PACKAGE_SUSPENDED;
31 import static android.service.notification.NotificationRankerService.REASON_PROFILE_TURNED_OFF;
32 import static android.service.notification.NotificationRankerService.REASON_UNAUTOBUNDLED;
33 import static android.service.notification.NotificationRankerService.REASON_USER_STOPPED;
34 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
35 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
36 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
37 import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
38 import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
39 import static android.service.notification.NotificationListenerService.TRIM_FULL;
40 import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
41 import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_DEFAULT;
42 import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_NONE;
44 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
46 import android.Manifest;
47 import android.annotation.Nullable;
48 import android.app.ActivityManager;
49 import android.app.ActivityManagerInternal;
50 import android.app.ActivityManagerNative;
51 import android.app.AppGlobals;
52 import android.app.AppOpsManager;
53 import android.app.AutomaticZenRule;
54 import android.app.IActivityManager;
55 import android.app.INotificationManager;
56 import android.app.ITransientNotification;
57 import android.app.Notification;
58 import android.app.NotificationManager;
59 import android.app.NotificationManager.Policy;
60 import android.app.PendingIntent;
61 import android.app.RemoteInput;
62 import android.app.StatusBarManager;
63 import android.app.backup.BackupManager;
64 import android.app.usage.UsageEvents;
65 import android.app.usage.UsageStatsManagerInternal;
66 import android.content.BroadcastReceiver;
67 import android.content.ComponentName;
68 import android.content.ContentResolver;
69 import android.content.Context;
70 import android.content.Intent;
71 import android.content.IntentFilter;
72 import android.content.pm.ApplicationInfo;
73 import android.content.pm.IPackageManager;
74 import android.content.pm.PackageInfo;
75 import android.content.pm.PackageManager;
76 import android.content.pm.PackageManager.NameNotFoundException;
77 import android.content.pm.ParceledListSlice;
78 import android.content.pm.UserInfo;
79 import android.content.res.Resources;
80 import android.database.ContentObserver;
81 import android.media.AudioAttributes;
82 import android.media.AudioManager;
83 import android.media.AudioManagerInternal;
84 import android.media.AudioSystem;
85 import android.media.IRingtonePlayer;
86 import android.net.Uri;
87 import android.os.Binder;
88 import android.os.Bundle;
89 import android.os.Environment;
90 import android.os.Handler;
91 import android.os.HandlerThread;
92 import android.os.IBinder;
93 import android.os.IInterface;
94 import android.os.Looper;
95 import android.os.Message;
96 import android.os.Parcelable;
97 import android.os.Process;
98 import android.os.RemoteException;
99 import android.os.SystemClock;
100 import android.os.SystemProperties;
101 import android.os.UserHandle;
102 import android.os.UserManager;
103 import android.os.Vibrator;
104 import android.provider.Settings;
105 import android.service.notification.Adjustment;
106 import android.service.notification.Condition;
107 import android.service.notification.IConditionProvider;
108 import android.service.notification.INotificationListener;
109 import android.service.notification.IStatusBarNotificationHolder;
110 import android.service.notification.NotificationRankerService;
111 import android.service.notification.NotificationListenerService;
112 import android.service.notification.NotificationRankingUpdate;
113 import android.service.notification.StatusBarNotification;
114 import android.service.notification.ZenModeConfig;
115 import android.telephony.PhoneStateListener;
116 import android.telephony.TelephonyManager;
117 import android.text.TextUtils;
118 import android.util.ArrayMap;
119 import android.util.ArraySet;
120 import android.util.AtomicFile;
121 import android.util.Log;
122 import android.util.Slog;
123 import android.util.SparseArray;
124 import android.util.Xml;
125 import android.view.accessibility.AccessibilityEvent;
126 import android.view.accessibility.AccessibilityManager;
127 import android.widget.Toast;
129 import com.android.internal.R;
130 import com.android.internal.annotations.VisibleForTesting;
131 import com.android.internal.statusbar.NotificationVisibility;
132 import com.android.internal.util.FastXmlSerializer;
133 import com.android.internal.util.Preconditions;
134 import com.android.server.DeviceIdleController;
135 import com.android.server.EventLogTags;
136 import com.android.server.LocalServices;
137 import com.android.server.SystemService;
138 import com.android.server.lights.Light;
139 import com.android.server.lights.LightsManager;
140 import com.android.server.notification.ManagedServices.ManagedServiceInfo;
141 import com.android.server.statusbar.StatusBarManagerInternal;
142 import com.android.server.vr.VrManagerInternal;
143 import com.android.server.notification.ManagedServices.UserProfiles;
145 import libcore.io.IoUtils;
147 import org.json.JSONException;
148 import org.json.JSONObject;
149 import org.xmlpull.v1.XmlPullParser;
150 import org.xmlpull.v1.XmlPullParserException;
151 import org.xmlpull.v1.XmlSerializer;
153 import java.io.ByteArrayInputStream;
154 import java.io.ByteArrayOutputStream;
156 import java.io.FileDescriptor;
157 import java.io.FileInputStream;
158 import java.io.FileNotFoundException;
159 import java.io.FileOutputStream;
160 import java.io.IOException;
161 import java.io.InputStream;
162 import java.io.OutputStream;
163 import java.io.PrintWriter;
164 import java.nio.charset.StandardCharsets;
165 import java.util.ArrayDeque;
166 import java.util.ArrayList;
167 import java.util.Arrays;
168 import java.util.Iterator;
169 import java.util.List;
170 import java.util.Map;
171 import java.util.Map.Entry;
172 import java.util.Set;
173 import java.util.concurrent.TimeUnit;
176 public class NotificationManagerService extends SystemService {
177 static final String TAG = "NotificationService";
178 static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
179 public static final boolean ENABLE_CHILD_NOTIFICATIONS
180 = SystemProperties.getBoolean("debug.child_notifs", true);
182 static final int MAX_PACKAGE_NOTIFICATIONS = 50;
183 static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 50f;
186 static final int MESSAGE_TIMEOUT = 2;
187 static final int MESSAGE_SAVE_POLICY_FILE = 3;
188 static final int MESSAGE_SEND_RANKING_UPDATE = 4;
189 static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
190 static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
192 // ranking thread messages
193 private static final int MESSAGE_RECONSIDER_RANKING = 1000;
194 private static final int MESSAGE_RANKING_SORT = 1001;
196 static final int LONG_DELAY = 3500; // 3.5 seconds
197 static final int SHORT_DELAY = 2000; // 2 seconds
199 static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
201 static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
203 static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
205 static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true;
206 static final boolean ENABLE_BLOCKED_TOASTS = true;
208 // When #matchesCallFilter is called from the ringer, wait at most
209 // 3s to resolve the contacts. This timeout is required since
210 // ContactsProvider might take a long time to start up.
212 // Return STARRED_CONTACT when the timeout is hit in order to avoid
213 // missed calls in ZEN mode "Important".
214 static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
215 static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
216 ValidateNotificationPeople.STARRED_CONTACT;
218 /** notification_enqueue status value for a newly enqueued notification. */
219 private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
221 /** notification_enqueue status value for an existing notification. */
222 private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
224 /** notification_enqueue status value for an ignored notification. */
225 private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
226 private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
227 private String mRankerServicePackageName;
229 private IActivityManager mAm;
230 AudioManager mAudioManager;
231 AudioManagerInternal mAudioManagerInternal;
232 @Nullable StatusBarManagerInternal mStatusBar;
234 private VrManagerInternal mVrManagerInternal;
236 final IBinder mForegroundToken = new Binder();
237 private Handler mHandler;
238 private final HandlerThread mRankingThread = new HandlerThread("ranker",
239 Process.THREAD_PRIORITY_BACKGROUND);
241 private Light mNotificationLight;
242 Light mAttentionLight;
243 private int mDefaultNotificationColor;
244 private int mDefaultNotificationLedOn;
246 private int mDefaultNotificationLedOff;
247 private long[] mDefaultVibrationPattern;
249 private long[] mFallbackVibrationPattern;
250 private boolean mUseAttentionLight;
251 boolean mSystemReady;
253 private boolean mDisableNotificationEffects;
254 private int mCallState;
255 private String mSoundNotificationKey;
256 private String mVibrateNotificationKey;
258 private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
259 new SparseArray<ArraySet<ManagedServiceInfo>>();
260 private List<ComponentName> mEffectsSuppressors = new ArrayList<ComponentName>();
261 private int mListenerHints; // right now, all hints are global
262 private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
264 // for enabling and disabling notification pulse behavior
265 private boolean mScreenOn = true;
266 private boolean mInCall = false;
267 private boolean mNotificationPulseEnabled;
269 // used as a mutex for access to all active notifications & listeners
270 final ArrayList<NotificationRecord> mNotificationList =
271 new ArrayList<NotificationRecord>();
272 final ArrayMap<String, NotificationRecord> mNotificationsByKey =
273 new ArrayMap<String, NotificationRecord>();
274 final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
275 final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();
276 final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
277 final PolicyAccess mPolicyAccess = new PolicyAccess();
279 // The last key in this list owns the hardware.
280 ArrayList<String> mLights = new ArrayList<>();
282 private AppOpsManager mAppOps;
283 private UsageStatsManagerInternal mAppUsageStats;
285 private Archive mArchive;
287 // Persistent storage for notification policy
288 private AtomicFile mPolicyFile;
290 private static final int DB_VERSION = 1;
292 private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
293 private static final String ATTR_VERSION = "version";
295 private RankingHelper mRankingHelper;
297 private final UserProfiles mUserProfiles = new UserProfiles();
298 private NotificationListeners mListeners;
299 private NotificationRankers mRankerServices;
300 private ConditionProviders mConditionProviders;
301 private NotificationUsageStats mUsageStats;
303 private static final int MY_UID = Process.myUid();
304 private static final int MY_PID = Process.myPid();
305 private RankingHandler mRankingHandler;
306 private long mLastOverRateLogTime;
307 private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
309 private static class Archive {
310 final int mBufferSize;
311 final ArrayDeque<StatusBarNotification> mBuffer;
313 public Archive(int size) {
315 mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
318 public String toString() {
319 final StringBuilder sb = new StringBuilder();
320 final int N = mBuffer.size();
321 sb.append("Archive (");
323 sb.append(" notification");
324 sb.append((N==1)?")":"s)");
325 return sb.toString();
328 public void record(StatusBarNotification nr) {
329 if (mBuffer.size() == mBufferSize) {
330 mBuffer.removeFirst();
333 // We don't want to store the heavy bits of the notification in the archive,
334 // but other clients in the system process might be using the object, so we
335 // store a (lightened) copy.
336 mBuffer.addLast(nr.cloneLight());
339 public Iterator<StatusBarNotification> descendingIterator() {
340 return mBuffer.descendingIterator();
343 public StatusBarNotification[] getArray(int count) {
344 if (count == 0) count = mBufferSize;
345 final StatusBarNotification[] a
346 = new StatusBarNotification[Math.min(count, mBuffer.size())];
347 Iterator<StatusBarNotification> iter = descendingIterator();
349 while (iter.hasNext() && i < count) {
350 a[i++] = iter.next();
357 private void readPolicyXml(InputStream stream, boolean forRestore)
358 throws XmlPullParserException, NumberFormatException, IOException {
359 final XmlPullParser parser = Xml.newPullParser();
360 parser.setInput(stream, StandardCharsets.UTF_8.name());
362 while (parser.next() != END_DOCUMENT) {
363 mZenModeHelper.readXml(parser, forRestore);
364 mRankingHelper.readXml(parser, forRestore);
368 private void loadPolicyFile() {
369 if (DBG) Slog.d(TAG, "loadPolicyFile");
370 synchronized(mPolicyFile) {
372 FileInputStream infile = null;
374 infile = mPolicyFile.openRead();
375 readPolicyXml(infile, false /*forRestore*/);
376 } catch (FileNotFoundException e) {
378 } catch (IOException e) {
379 Log.wtf(TAG, "Unable to read notification policy", e);
380 } catch (NumberFormatException e) {
381 Log.wtf(TAG, "Unable to parse notification policy", e);
382 } catch (XmlPullParserException e) {
383 Log.wtf(TAG, "Unable to parse notification policy", e);
385 IoUtils.closeQuietly(infile);
390 public void savePolicyFile() {
391 mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
392 mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
395 private void handleSavePolicyFile() {
396 if (DBG) Slog.d(TAG, "handleSavePolicyFile");
397 synchronized (mPolicyFile) {
398 final FileOutputStream stream;
400 stream = mPolicyFile.startWrite();
401 } catch (IOException e) {
402 Slog.w(TAG, "Failed to save policy file", e);
407 writePolicyXml(stream, false /*forBackup*/);
408 mPolicyFile.finishWrite(stream);
409 } catch (IOException e) {
410 Slog.w(TAG, "Failed to save policy file, restoring backup", e);
411 mPolicyFile.failWrite(stream);
414 BackupManager.dataChanged(getContext().getPackageName());
417 private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
418 final XmlSerializer out = new FastXmlSerializer();
419 out.setOutput(stream, StandardCharsets.UTF_8.name());
420 out.startDocument(null, true);
421 out.startTag(null, TAG_NOTIFICATION_POLICY);
422 out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
423 mZenModeHelper.writeXml(out, forBackup);
424 mRankingHelper.writeXml(out, forBackup);
425 out.endTag(null, TAG_NOTIFICATION_POLICY);
429 /** Use this when you actually want to post a notification or toast.
431 * Unchecked. Not exposed via Binder, but can be called in the course of enqueue*().
433 private boolean noteNotificationOp(String pkg, int uid) {
434 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
435 != AppOpsManager.MODE_ALLOWED) {
436 Slog.v(TAG, "notifications are disabled by AppOps for " + pkg);
442 /** Use this to check if a package can post a notification or toast. */
443 private boolean checkNotificationOp(String pkg, int uid) {
444 return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
445 == AppOpsManager.MODE_ALLOWED && !isPackageSuspendedForUser(pkg, uid);
448 private static final class ToastRecord
452 final ITransientNotification callback;
455 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration)
459 this.callback = callback;
460 this.duration = duration;
463 void update(int duration) {
464 this.duration = duration;
467 void dump(PrintWriter pw, String prefix, DumpFilter filter) {
468 if (filter != null && !filter.matches(pkg)) return;
469 pw.println(prefix + this);
473 public final String toString()
475 return "ToastRecord{"
476 + Integer.toHexString(System.identityHashCode(this))
478 + " callback=" + callback
479 + " duration=" + duration;
483 private final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
486 public void onSetDisabled(int status) {
487 synchronized (mNotificationList) {
488 mDisableNotificationEffects =
489 (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
490 if (disableNotificationEffects(null) != null) {
491 // cancel whatever's going on
492 long identity = Binder.clearCallingIdentity();
494 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
495 if (player != null) {
498 } catch (RemoteException e) {
500 Binder.restoreCallingIdentity(identity);
503 identity = Binder.clearCallingIdentity();
507 Binder.restoreCallingIdentity(identity);
514 public void onClearAll(int callingUid, int callingPid, int userId) {
515 synchronized (mNotificationList) {
516 cancelAllLocked(callingUid, callingPid, userId, REASON_DELEGATE_CANCEL_ALL, null,
517 /*includeCurrentProfiles*/ true);
522 public void onNotificationClick(int callingUid, int callingPid, String key) {
523 synchronized (mNotificationList) {
524 NotificationRecord r = mNotificationsByKey.get(key);
526 Log.w(TAG, "No notification with key: " + key);
529 final long now = System.currentTimeMillis();
530 EventLogTags.writeNotificationClicked(key,
531 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
533 StatusBarNotification sbn = r.sbn;
534 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
535 sbn.getId(), Notification.FLAG_AUTO_CANCEL,
536 Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
537 REASON_DELEGATE_CLICK, null);
542 public void onNotificationActionClick(int callingUid, int callingPid, String key,
544 synchronized (mNotificationList) {
545 NotificationRecord r = mNotificationsByKey.get(key);
547 Log.w(TAG, "No notification with key: " + key);
550 final long now = System.currentTimeMillis();
551 EventLogTags.writeNotificationActionClicked(key, actionIndex,
552 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
553 // TODO: Log action click via UsageStats.
558 public void onNotificationClear(int callingUid, int callingPid,
559 String pkg, String tag, int id, int userId) {
560 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
561 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
562 true, userId, REASON_DELEGATE_CANCEL, null);
566 public void onPanelRevealed(boolean clearEffects, int items) {
567 EventLogTags.writeNotificationPanelRevealed(items);
574 public void onPanelHidden() {
575 EventLogTags.writeNotificationPanelHidden();
579 public void clearEffects() {
580 synchronized (mNotificationList) {
581 if (DBG) Slog.d(TAG, "clearEffects");
583 clearVibrateLocked();
589 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
590 int uid, int initialPid, String message, int userId) {
591 Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
592 + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
593 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
594 REASON_DELEGATE_ERROR, null);
595 long ident = Binder.clearCallingIdentity();
597 ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg,
598 "Bad notification posted from package " + pkg
600 } catch (RemoteException e) {
602 Binder.restoreCallingIdentity(ident);
606 public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
607 NotificationVisibility[] noLongerVisibleKeys) {
608 synchronized (mNotificationList) {
609 for (NotificationVisibility nv : newlyVisibleKeys) {
610 NotificationRecord r = mNotificationsByKey.get(nv.key);
611 if (r == null) continue;
612 r.setVisibility(true, nv.rank);
615 // Note that we might receive this event after notifications
616 // have already left the system, e.g. after dismissing from the
617 // shade. Hence not finding notifications in
618 // mNotificationsByKey is not an exceptional condition.
619 for (NotificationVisibility nv : noLongerVisibleKeys) {
620 NotificationRecord r = mNotificationsByKey.get(nv.key);
621 if (r == null) continue;
622 r.setVisibility(false, nv.rank);
629 public void onNotificationExpansionChanged(String key,
630 boolean userAction, boolean expanded) {
631 synchronized (mNotificationList) {
632 NotificationRecord r = mNotificationsByKey.get(key);
634 r.stats.onExpansionChanged(userAction, expanded);
635 final long now = System.currentTimeMillis();
636 EventLogTags.writeNotificationExpansion(key,
637 userAction ? 1 : 0, expanded ? 1 : 0,
638 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
644 private void clearSoundLocked() {
645 mSoundNotificationKey = null;
646 long identity = Binder.clearCallingIdentity();
648 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
649 if (player != null) {
652 } catch (RemoteException e) {
654 Binder.restoreCallingIdentity(identity);
658 private void clearVibrateLocked() {
659 mVibrateNotificationKey = null;
660 long identity = Binder.clearCallingIdentity();
664 Binder.restoreCallingIdentity(identity);
668 private void clearLightsLocked() {
671 updateLightsLocked();
674 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
676 public void onReceive(Context context, Intent intent) {
677 String action = intent.getAction();
678 if (action == null) {
682 boolean queryRestart = false;
683 boolean queryRemove = false;
684 boolean packageChanged = false;
685 boolean cancelNotifications = true;
686 int reason = REASON_PACKAGE_CHANGED;
688 if (action.equals(Intent.ACTION_PACKAGE_ADDED)
689 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
690 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
691 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
692 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
693 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
694 || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
695 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
696 UserHandle.USER_ALL);
697 String pkgList[] = null;
698 boolean queryReplace = queryRemove &&
699 intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
700 if (DBG) Slog.i(TAG, "action=" + action + " queryReplace=" + queryReplace);
701 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
702 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
703 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
704 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
705 reason = REASON_PACKAGE_SUSPENDED;
706 } else if (queryRestart) {
707 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
709 Uri uri = intent.getData();
713 String pkgName = uri.getSchemeSpecificPart();
714 if (pkgName == null) {
717 if (packageChanged) {
718 // We cancel notifications for packages which have just been disabled
720 final IPackageManager pm = AppGlobals.getPackageManager();
721 final int enabled = pm.getApplicationEnabledSetting(pkgName,
722 changeUserId != UserHandle.USER_ALL ? changeUserId :
723 UserHandle.USER_SYSTEM);
724 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
725 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
726 cancelNotifications = false;
728 } catch (IllegalArgumentException e) {
729 // Package doesn't exist; probably racing with uninstall.
730 // cancelNotifications is already true, so nothing to do here.
732 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
734 } catch (RemoteException e) {
735 // Failed to talk to PackageManagerService Should never happen!
738 pkgList = new String[]{pkgName};
741 if (pkgList != null && (pkgList.length > 0)) {
742 for (String pkgName : pkgList) {
743 if (cancelNotifications) {
744 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart,
745 changeUserId, reason, null);
749 mListeners.onPackagesChanged(queryReplace, pkgList);
750 mRankerServices.onPackagesChanged(queryReplace, pkgList);
751 mConditionProviders.onPackagesChanged(queryReplace, pkgList);
752 mRankingHelper.onPackagesChanged(queryReplace, pkgList);
757 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
759 public void onReceive(Context context, Intent intent) {
760 String action = intent.getAction();
762 if (action.equals(Intent.ACTION_SCREEN_ON)) {
763 // Keep track of screen on/off state, but do not turn off the notification light
764 // until user passes through the lock screen or views the notification.
766 updateNotificationPulse();
767 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
769 updateNotificationPulse();
770 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
771 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
772 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
773 updateNotificationPulse();
774 } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
775 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
776 if (userHandle >= 0) {
777 cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
778 REASON_USER_STOPPED, null);
780 } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
781 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
782 if (userHandle >= 0) {
783 cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
784 REASON_PROFILE_TURNED_OFF, null);
786 } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
787 // turn off LED when user passes through lock screen
788 mNotificationLight.turnOff();
789 if (mStatusBar != null) {
790 mStatusBar.notificationLightOff();
792 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
793 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
794 // reload per-user settings
795 mSettingsObserver.update(null);
796 mUserProfiles.updateCache(context);
797 // Refresh managed services
798 mConditionProviders.onUserSwitched(user);
799 mListeners.onUserSwitched(user);
800 mRankerServices.onUserSwitched(user);
801 mZenModeHelper.onUserSwitched(user);
802 } else if (action.equals(Intent.ACTION_USER_ADDED)) {
803 mUserProfiles.updateCache(context);
804 } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
805 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
806 mZenModeHelper.onUserRemoved(user);
807 } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
808 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
809 mConditionProviders.onUserUnlocked(user);
810 mListeners.onUserUnlocked(user);
811 mRankerServices.onUserUnlocked(user);
812 mZenModeHelper.onUserUnlocked(user);
817 private final class SettingsObserver extends ContentObserver {
818 private final Uri NOTIFICATION_LIGHT_PULSE_URI
819 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
820 private final Uri NOTIFICATION_RATE_LIMIT_URI
821 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
823 SettingsObserver(Handler handler) {
828 ContentResolver resolver = getContext().getContentResolver();
829 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
830 false, this, UserHandle.USER_ALL);
831 resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
832 false, this, UserHandle.USER_ALL);
836 @Override public void onChange(boolean selfChange, Uri uri) {
840 public void update(Uri uri) {
841 ContentResolver resolver = getContext().getContentResolver();
842 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
843 boolean pulseEnabled = Settings.System.getInt(resolver,
844 Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
845 if (mNotificationPulseEnabled != pulseEnabled) {
846 mNotificationPulseEnabled = pulseEnabled;
847 updateNotificationPulse();
850 if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
851 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
852 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
857 private SettingsObserver mSettingsObserver;
858 private ZenModeHelper mZenModeHelper;
860 private final Runnable mBuzzBeepBlinked = new Runnable() {
863 if (mStatusBar != null) {
864 mStatusBar.buzzBeepBlinked();
869 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
870 int[] ar = r.getIntArray(resid);
874 final int len = ar.length > maxlen ? maxlen : ar.length;
875 long[] out = new long[len];
876 for (int i=0; i<len; i++) {
882 public NotificationManagerService(Context context) {
887 void setAudioManager(AudioManager audioMananger) {
888 mAudioManager = audioMananger;
892 void setVibrator(Vibrator vibrator) {
893 mVibrator = vibrator;
897 void setSystemReady(boolean systemReady) {
898 mSystemReady = systemReady;
902 void setHandler(Handler handler) {
907 public void onStart() {
908 Resources resources = getContext().getResources();
910 mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
911 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
912 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
914 mAm = ActivityManagerNative.getDefault();
915 mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
916 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
917 mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
919 // This is the package that contains the AOSP framework update.
920 mRankerServicePackageName = getContext().getPackageManager()
921 .getServicesSystemSharedLibraryPackageName();
923 mHandler = new WorkerHandler();
924 mRankingThread.start();
925 String[] extractorNames;
927 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
928 } catch (Resources.NotFoundException e) {
929 extractorNames = new String[0];
931 mUsageStats = new NotificationUsageStats(getContext());
932 mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
933 mRankingHelper = new RankingHelper(getContext(),
937 mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles);
938 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
939 mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
941 public void onConfigChanged() {
946 void onZenModeChanged() {
947 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
948 getContext().sendBroadcastAsUser(
949 new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
950 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
951 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
952 synchronized(mNotificationList) {
953 updateInterruptionFilterLocked();
958 void onPolicyChanged() {
959 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
962 final File systemDir = new File(Environment.getDataDirectory(), "system");
963 mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
967 // This is a MangedServices object that keeps track of the listeners.
968 mListeners = new NotificationListeners();
970 // This is a MangedServices object that keeps track of the ranker.
971 mRankerServices = new NotificationRankers();
972 // Find the updatable ranker and register it.
973 mRankerServices.registerRanker();
975 mStatusBar = getLocalService(StatusBarManagerInternal.class);
976 if (mStatusBar != null) {
977 mStatusBar.setNotificationDelegate(mNotificationDelegate);
980 final LightsManager lights = getLocalService(LightsManager.class);
981 mNotificationLight = lights.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
982 mAttentionLight = lights.getLight(LightsManager.LIGHT_ID_ATTENTION);
984 mDefaultNotificationColor = resources.getColor(
985 R.color.config_defaultNotificationColor);
986 mDefaultNotificationLedOn = resources.getInteger(
987 R.integer.config_defaultNotificationLedOn);
988 mDefaultNotificationLedOff = resources.getInteger(
989 R.integer.config_defaultNotificationLedOff);
991 mDefaultVibrationPattern = getLongArray(resources,
992 R.array.config_defaultNotificationVibePattern,
993 VIBRATE_PATTERN_MAXLEN,
994 DEFAULT_VIBRATE_PATTERN);
996 mFallbackVibrationPattern = getLongArray(resources,
997 R.array.config_notificationFallbackVibePattern,
998 VIBRATE_PATTERN_MAXLEN,
999 DEFAULT_VIBRATE_PATTERN);
1001 mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
1003 // Don't start allowing notifications until the setup wizard has run once.
1004 // After that, including subsequent boots, init with notifications turned on.
1005 // This works on the first boot because the setup wizard will toggle this
1006 // flag at least once and we'll go back to 0 after that.
1007 if (0 == Settings.Global.getInt(getContext().getContentResolver(),
1008 Settings.Global.DEVICE_PROVISIONED, 0)) {
1009 mDisableNotificationEffects = true;
1011 mZenModeHelper.initZenMode();
1012 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1014 mUserProfiles.updateCache(getContext());
1015 listenForCallState();
1017 // register for various Intents
1018 IntentFilter filter = new IntentFilter();
1019 filter.addAction(Intent.ACTION_SCREEN_ON);
1020 filter.addAction(Intent.ACTION_SCREEN_OFF);
1021 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
1022 filter.addAction(Intent.ACTION_USER_PRESENT);
1023 filter.addAction(Intent.ACTION_USER_STOPPED);
1024 filter.addAction(Intent.ACTION_USER_SWITCHED);
1025 filter.addAction(Intent.ACTION_USER_ADDED);
1026 filter.addAction(Intent.ACTION_USER_REMOVED);
1027 filter.addAction(Intent.ACTION_USER_UNLOCKED);
1028 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
1029 getContext().registerReceiver(mIntentReceiver, filter);
1031 IntentFilter pkgFilter = new IntentFilter();
1032 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
1033 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1034 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
1035 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1036 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1037 pkgFilter.addDataScheme("package");
1038 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1041 IntentFilter suspendedPkgFilter = new IntentFilter();
1042 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
1043 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1044 suspendedPkgFilter, null, null);
1046 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
1047 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1050 mSettingsObserver = new SettingsObserver(mHandler);
1052 mArchive = new Archive(resources.getInteger(
1053 R.integer.config_notificationServiceArchiveSize));
1055 publishBinderService(Context.NOTIFICATION_SERVICE, mService);
1056 publishLocalService(NotificationManagerInternal.class, mInternalService);
1059 private void sendRegisteredOnlyBroadcast(String action) {
1060 getContext().sendBroadcastAsUser(new Intent(action)
1061 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
1065 * Make sure the XML config and the the AppOps system agree about blocks.
1067 private void syncBlockDb() {
1070 // sync bans from ranker into app opps
1071 Map<Integer, String> packageBans = mRankingHelper.getPackageBans();
1072 for(Entry<Integer, String> ban : packageBans.entrySet()) {
1073 final int uid = ban.getKey();
1074 final String packageName = ban.getValue();
1075 setNotificationsEnabledForPackageImpl(packageName, uid, false);
1078 // sync bans from app opps into ranker
1079 packageBans.clear();
1080 for (UserInfo user : UserManager.get(getContext()).getUsers()) {
1081 final int userId = user.getUserHandle().getIdentifier();
1082 final PackageManager packageManager = getContext().getPackageManager();
1083 List<PackageInfo> packages = packageManager.getInstalledPackagesAsUser(0, userId);
1084 final int packageCount = packages.size();
1085 for (int p = 0; p < packageCount; p++) {
1086 final String packageName = packages.get(p).packageName;
1088 final int uid = packageManager.getPackageUidAsUser(packageName, userId);
1089 if (!checkNotificationOp(packageName, uid)) {
1090 packageBans.put(uid, packageName);
1092 } catch (NameNotFoundException e) {
1097 for (Entry<Integer, String> ban : packageBans.entrySet()) {
1098 mRankingHelper.setImportance(ban.getValue(), ban.getKey(), IMPORTANCE_NONE);
1105 public void onBootPhase(int phase) {
1106 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1107 // no beeping until we're basically done booting
1108 mSystemReady = true;
1110 // Grab our optional AudioService
1111 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
1112 mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
1113 mVrManagerInternal = getLocalService(VrManagerInternal.class);
1114 mZenModeHelper.onSystemReady();
1115 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1116 // This observer will force an update when observe is called, causing us to
1117 // bind to listener services.
1118 mSettingsObserver.observe();
1119 mListeners.onBootPhaseAppsCanStart();
1120 mRankerServices.onBootPhaseAppsCanStart();
1121 mConditionProviders.onBootPhaseAppsCanStart();
1125 void setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled) {
1126 Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
1128 mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
1129 enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
1131 // Now, cancel any outstanding notifications that are part of a just-disabled app
1132 if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
1133 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true, UserHandle.getUserId(uid),
1134 REASON_PACKAGE_BANNED, null);
1138 private void updateListenerHintsLocked() {
1139 final int hints = calculateHints();
1140 if (hints == mListenerHints) return;
1141 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
1142 mListenerHints = hints;
1143 scheduleListenerHintsChanged(hints);
1146 private void updateEffectsSuppressorLocked() {
1147 final long updatedSuppressedEffects = calculateSuppressedEffects();
1148 if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1149 final List<ComponentName> suppressors = getSuppressors();
1150 ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1151 mEffectsSuppressors = suppressors;
1152 mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
1153 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
1156 private ArrayList<ComponentName> getSuppressors() {
1157 ArrayList<ComponentName> names = new ArrayList<ComponentName>();
1158 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1159 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1161 for (ManagedServiceInfo info : serviceInfoList) {
1162 names.add(info.component);
1169 private boolean removeDisabledHints(ManagedServiceInfo info) {
1170 return removeDisabledHints(info, 0);
1173 private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
1174 boolean removed = false;
1176 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1177 final int hint = mListenersDisablingEffects.keyAt(i);
1178 final ArraySet<ManagedServiceInfo> listeners =
1179 mListenersDisablingEffects.valueAt(i);
1181 if (hints == 0 || (hint & hints) == hint) {
1182 removed = removed || listeners.remove(info);
1189 private void addDisabledHints(ManagedServiceInfo info, int hints) {
1190 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1191 addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
1194 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1195 addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1198 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1199 addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
1203 private void addDisabledHint(ManagedServiceInfo info, int hint) {
1204 if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
1205 mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
1208 ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
1209 hintListeners.add(info);
1212 private int calculateHints() {
1214 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1215 int hint = mListenersDisablingEffects.keyAt(i);
1216 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1218 if (!serviceInfoList.isEmpty()) {
1226 private long calculateSuppressedEffects() {
1227 int hints = calculateHints();
1228 long suppressedEffects = 0;
1230 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1231 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
1234 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1235 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
1238 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1239 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
1242 return suppressedEffects;
1245 private void updateInterruptionFilterLocked() {
1246 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1247 if (interruptionFilter == mInterruptionFilter) return;
1248 mInterruptionFilter = interruptionFilter;
1249 scheduleInterruptionFilterChanged(interruptionFilter);
1252 private final IBinder mService = new INotificationManager.Stub() {
1254 // ============================================================================
1257 public void enqueueToast(String pkg, ITransientNotification callback, int duration)
1260 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1261 + " duration=" + duration);
1264 if (pkg == null || callback == null) {
1265 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1269 final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg));
1270 final boolean isPackageSuspended =
1271 isPackageSuspendedForUser(pkg, Binder.getCallingUid());
1273 if (ENABLE_BLOCKED_TOASTS && (!noteNotificationOp(pkg, Binder.getCallingUid())
1274 || isPackageSuspended)) {
1275 if (!isSystemToast) {
1276 Slog.e(TAG, "Suppressing toast from package " + pkg
1277 + (isPackageSuspended
1278 ? " due to package suspended by administrator."
1279 : " by user request."));
1284 synchronized (mToastQueue) {
1285 int callingPid = Binder.getCallingPid();
1286 long callingId = Binder.clearCallingIdentity();
1289 int index = indexOfToastLocked(pkg, callback);
1290 // If it's already in the queue, we update it in place, we don't
1291 // move it to the end of the queue.
1293 record = mToastQueue.get(index);
1294 record.update(duration);
1296 // Limit the number of toasts that any given package except the android
1297 // package can enqueue. Prevents DOS attacks and deals with leaks.
1298 if (!isSystemToast) {
1300 final int N = mToastQueue.size();
1301 for (int i=0; i<N; i++) {
1302 final ToastRecord r = mToastQueue.get(i);
1303 if (r.pkg.equals(pkg)) {
1305 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
1306 Slog.e(TAG, "Package has already posted " + count
1307 + " toasts. Not showing more. Package=" + pkg);
1314 record = new ToastRecord(callingPid, pkg, callback, duration);
1315 mToastQueue.add(record);
1316 index = mToastQueue.size() - 1;
1317 keepProcessAliveLocked(callingPid);
1319 // If it's at index 0, it's the current toast. It doesn't matter if it's
1320 // new or just been updated. Call back and tell it to show itself.
1321 // If the callback fails, this will remove it from the list, so don't
1322 // assume that it's valid after this.
1324 showNextToastLocked();
1327 Binder.restoreCallingIdentity(callingId);
1333 public void cancelToast(String pkg, ITransientNotification callback) {
1334 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
1336 if (pkg == null || callback == null) {
1337 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
1341 synchronized (mToastQueue) {
1342 long callingId = Binder.clearCallingIdentity();
1344 int index = indexOfToastLocked(pkg, callback);
1346 cancelToastLocked(index);
1348 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
1349 + " callback=" + callback);
1352 Binder.restoreCallingIdentity(callingId);
1358 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
1359 Notification notification, int[] idOut, int userId) throws RemoteException {
1360 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
1361 Binder.getCallingPid(), tag, id, notification, idOut, userId);
1365 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
1366 checkCallerIsSystemOrSameApp(pkg);
1367 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1368 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
1369 // Don't allow client applications to cancel foreground service notis or autobundled
1371 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
1372 (Binder.getCallingUid() == Process.SYSTEM_UID
1373 ? 0 : Notification.FLAG_FOREGROUND_SERVICE)
1374 | (Binder.getCallingUid() == Process.SYSTEM_UID
1375 ? 0 : Notification.FLAG_AUTOGROUP_SUMMARY), false, userId,
1376 REASON_APP_CANCEL, null);
1380 public void cancelAllNotifications(String pkg, int userId) {
1381 checkCallerIsSystemOrSameApp(pkg);
1383 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1384 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
1386 // Calling from user space, don't allow the canceling of actively
1387 // running foreground services.
1388 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
1389 pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
1390 REASON_APP_CANCEL_ALL, null);
1394 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
1395 checkCallerIsSystem();
1397 setNotificationsEnabledForPackageImpl(pkg, uid, enabled);
1398 mRankingHelper.setEnabled(pkg, uid, enabled);
1403 * Use this when you just want to know if notifications are OK for this package.
1406 public boolean areNotificationsEnabled(String pkg) {
1407 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
1411 * Use this when you just want to know if notifications are OK for this package.
1414 public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
1415 checkCallerIsSystemOrSameApp(pkg);
1416 return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
1417 == AppOpsManager.MODE_ALLOWED) && !isPackageSuspendedForUser(pkg, uid);
1421 public void setPriority(String pkg, int uid, int priority) {
1422 checkCallerIsSystem();
1423 mRankingHelper.setPriority(pkg, uid, priority);
1428 public int getPriority(String pkg, int uid) {
1429 checkCallerIsSystem();
1430 return mRankingHelper.getPriority(pkg, uid);
1434 public void setVisibilityOverride(String pkg, int uid, int visibility) {
1435 checkCallerIsSystem();
1436 mRankingHelper.setVisibilityOverride(pkg, uid, visibility);
1441 public int getVisibilityOverride(String pkg, int uid) {
1442 checkCallerIsSystem();
1443 return mRankingHelper.getVisibilityOverride(pkg, uid);
1447 public void setImportance(String pkg, int uid, int importance) {
1448 enforceSystemOrSystemUI("Caller not system or systemui");
1449 setNotificationsEnabledForPackageImpl(pkg, uid,
1450 importance != NotificationListenerService.Ranking.IMPORTANCE_NONE);
1451 mRankingHelper.setImportance(pkg, uid, importance);
1456 public int getPackageImportance(String pkg) {
1457 checkCallerIsSystemOrSameApp(pkg);
1458 return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
1462 public int getImportance(String pkg, int uid) {
1463 enforceSystemOrSystemUI("Caller not system or systemui");
1464 return mRankingHelper.getImportance(pkg, uid);
1468 * System-only API for getting a list of current (i.e. not cleared) notifications.
1470 * Requires ACCESS_NOTIFICATIONS which is signature|system.
1471 * @returns A list of all the notifications, in natural order.
1474 public StatusBarNotification[] getActiveNotifications(String callingPkg) {
1475 // enforce() will ensure the calling uid has the correct permission
1476 getContext().enforceCallingOrSelfPermission(
1477 android.Manifest.permission.ACCESS_NOTIFICATIONS,
1478 "NotificationManagerService.getActiveNotifications");
1480 StatusBarNotification[] tmp = null;
1481 int uid = Binder.getCallingUid();
1483 // noteOp will check to make sure the callingPkg matches the uid
1484 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1485 == AppOpsManager.MODE_ALLOWED) {
1486 synchronized (mNotificationList) {
1487 tmp = new StatusBarNotification[mNotificationList.size()];
1488 final int N = mNotificationList.size();
1489 for (int i=0; i<N; i++) {
1490 tmp[i] = mNotificationList.get(i).sbn;
1498 * Public API for getting a list of current notifications for the calling package/uid.
1500 * @returns A list of all the package's notifications, in natural order.
1503 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
1504 int incomingUserId) {
1505 checkCallerIsSystemOrSameApp(pkg);
1506 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1507 Binder.getCallingUid(), incomingUserId, true, false,
1508 "getAppActiveNotifications", pkg);
1510 final ArrayList<StatusBarNotification> list
1511 = new ArrayList<StatusBarNotification>(mNotificationList.size());
1513 synchronized (mNotificationList) {
1514 final int N = mNotificationList.size();
1515 for (int i = 0; i < N; i++) {
1516 final StatusBarNotification sbn = mNotificationList.get(i).sbn;
1517 if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId
1518 && (sbn.getNotification().flags
1519 & Notification.FLAG_AUTOGROUP_SUMMARY) == 0) {
1520 // We could pass back a cloneLight() but clients might get confused and
1521 // try to send this thing back to notify() again, which would not work
1523 final StatusBarNotification sbnOut = new StatusBarNotification(
1524 sbn.getPackageName(),
1526 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
1527 0, // hide score from apps
1528 sbn.getNotification().clone(),
1529 sbn.getUser(), sbn.getPostTime());
1535 return new ParceledListSlice<StatusBarNotification>(list);
1539 * System-only API for getting a list of recent (cleared, no longer shown) notifications.
1541 * Requires ACCESS_NOTIFICATIONS which is signature|system.
1544 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
1545 // enforce() will ensure the calling uid has the correct permission
1546 getContext().enforceCallingOrSelfPermission(
1547 android.Manifest.permission.ACCESS_NOTIFICATIONS,
1548 "NotificationManagerService.getHistoricalNotifications");
1550 StatusBarNotification[] tmp = null;
1551 int uid = Binder.getCallingUid();
1553 // noteOp will check to make sure the callingPkg matches the uid
1554 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1555 == AppOpsManager.MODE_ALLOWED) {
1556 synchronized (mArchive) {
1557 tmp = mArchive.getArray(count);
1564 * Register a listener binder directly with the notification manager.
1566 * Only works with system callers. Apps should extend
1567 * {@link android.service.notification.NotificationListenerService}.
1570 public void registerListener(final INotificationListener listener,
1571 final ComponentName component, final int userid) {
1572 enforceSystemOrSystemUI("INotificationManager.registerListener");
1573 mListeners.registerService(listener, component, userid);
1577 * Remove a listener binder directly
1580 public void unregisterListener(INotificationListener token, int userid) {
1581 mListeners.unregisterService(token, userid);
1585 * Allow an INotificationListener to simulate a "clear all" operation.
1587 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
1589 * @param token The binder for the listener, to check that the caller is allowed
1592 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
1593 final int callingUid = Binder.getCallingUid();
1594 final int callingPid = Binder.getCallingPid();
1595 long identity = Binder.clearCallingIdentity();
1597 synchronized (mNotificationList) {
1598 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1600 final int N = keys.length;
1601 for (int i = 0; i < N; i++) {
1602 NotificationRecord r = mNotificationsByKey.get(keys[i]);
1603 if (r == null) continue;
1604 final int userId = r.sbn.getUserId();
1605 if (userId != info.userid && userId != UserHandle.USER_ALL &&
1606 !mUserProfiles.isCurrentProfile(userId)) {
1607 throw new SecurityException("Disallowed call from listener: "
1610 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
1611 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
1615 cancelAllLocked(callingUid, callingPid, info.userid,
1616 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
1620 Binder.restoreCallingIdentity(identity);
1625 * Handle request from an approved listener to re-enable itself.
1627 * @param component The componenet to be re-enabled, caller must match package.
1630 public void requestBindListener(ComponentName component) {
1631 checkCallerIsSystemOrSameApp(component.getPackageName());
1632 long identity = Binder.clearCallingIdentity();
1634 ManagedServices manager =
1635 mRankerServices.isComponentEnabledForCurrentProfiles(component)
1638 manager.setComponentState(component, true);
1640 Binder.restoreCallingIdentity(identity);
1645 public void requestUnbindListener(INotificationListener token) {
1646 long identity = Binder.clearCallingIdentity();
1648 // allow bound services to disable themselves
1649 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1650 info.getOwner().setComponentState(info.component, false);
1652 Binder.restoreCallingIdentity(identity);
1657 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
1658 long identity = Binder.clearCallingIdentity();
1660 synchronized (mNotificationList) {
1661 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1663 final int N = keys.length;
1664 for (int i = 0; i < N; i++) {
1665 NotificationRecord r = mNotificationsByKey.get(keys[i]);
1666 if (r == null) continue;
1667 final int userId = r.sbn.getUserId();
1668 if (userId != info.userid && userId != UserHandle.USER_ALL &&
1669 !mUserProfiles.isCurrentProfile(userId)) {
1670 throw new SecurityException("Disallowed call from listener: "
1674 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
1675 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
1676 userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM
1678 UsageEvents.Event.USER_INTERACTION);
1685 Binder.restoreCallingIdentity(identity);
1689 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
1690 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
1691 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
1692 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
1694 userId, REASON_LISTENER_CANCEL, info);
1698 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
1700 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
1702 * @param token The binder for the listener, to check that the caller is allowed
1705 public void cancelNotificationFromListener(INotificationListener token, String pkg,
1706 String tag, int id) {
1707 final int callingUid = Binder.getCallingUid();
1708 final int callingPid = Binder.getCallingPid();
1709 long identity = Binder.clearCallingIdentity();
1711 synchronized (mNotificationList) {
1712 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1713 if (info.supportsProfiles()) {
1714 Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
1715 + "from " + info.component
1716 + " use cancelNotification(key) instead.");
1718 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
1719 pkg, tag, id, info.userid);
1723 Binder.restoreCallingIdentity(identity);
1728 * Allow an INotificationListener to request the list of outstanding notifications seen by
1729 * the current user. Useful when starting up, after which point the listener callbacks
1732 * @param token The binder for the listener, to check that the caller is allowed
1733 * @param keys An array of notification keys to fetch, or null to fetch everything
1734 * @returns The return value will contain the notifications specified in keys, in that
1735 * order, or if keys is null, all the notifications, in natural order.
1738 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
1739 INotificationListener token, String[] keys, int trim) {
1740 synchronized (mNotificationList) {
1741 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1742 final boolean getKeys = keys != null;
1743 final int N = getKeys ? keys.length : mNotificationList.size();
1744 final ArrayList<StatusBarNotification> list
1745 = new ArrayList<StatusBarNotification>(N);
1746 for (int i=0; i<N; i++) {
1747 final NotificationRecord r = getKeys
1748 ? mNotificationsByKey.get(keys[i])
1749 : mNotificationList.get(i);
1750 if (r == null) continue;
1751 StatusBarNotification sbn = r.sbn;
1752 if (!isVisibleToListener(sbn, info)) continue;
1753 StatusBarNotification sbnToSend =
1754 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
1755 list.add(sbnToSend);
1757 return new ParceledListSlice<StatusBarNotification>(list);
1762 public void requestHintsFromListener(INotificationListener token, int hints) {
1763 final long identity = Binder.clearCallingIdentity();
1765 synchronized (mNotificationList) {
1766 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1767 final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
1768 | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
1769 | HINT_HOST_DISABLE_CALL_EFFECTS;
1770 final boolean disableEffects = (hints & disableEffectsMask) != 0;
1771 if (disableEffects) {
1772 addDisabledHints(info, hints);
1774 removeDisabledHints(info, hints);
1776 updateListenerHintsLocked();
1777 updateEffectsSuppressorLocked();
1780 Binder.restoreCallingIdentity(identity);
1785 public int getHintsFromListener(INotificationListener token) {
1786 synchronized (mNotificationList) {
1787 return mListenerHints;
1792 public void requestInterruptionFilterFromListener(INotificationListener token,
1793 int interruptionFilter) throws RemoteException {
1794 final long identity = Binder.clearCallingIdentity();
1796 synchronized (mNotificationList) {
1797 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1798 mZenModeHelper.requestFromListener(info.component, interruptionFilter);
1799 updateInterruptionFilterLocked();
1802 Binder.restoreCallingIdentity(identity);
1807 public int getInterruptionFilterFromListener(INotificationListener token)
1808 throws RemoteException {
1809 synchronized (mNotificationLight) {
1810 return mInterruptionFilter;
1815 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
1816 throws RemoteException {
1817 synchronized (mNotificationList) {
1818 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1819 if (info == null) return;
1820 mListeners.setOnNotificationPostedTrimLocked(info, trim);
1825 public int getZenMode() {
1826 return mZenModeHelper.getZenMode();
1830 public ZenModeConfig getZenModeConfig() {
1831 enforceSystemOrSystemUIOrVolume("INotificationManager.getZenModeConfig");
1832 return mZenModeHelper.getConfig();
1836 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
1837 enforceSystemOrSystemUIOrVolume("INotificationManager.setZenMode");
1838 final long identity = Binder.clearCallingIdentity();
1840 mZenModeHelper.setManualZenMode(mode, conditionId, reason);
1842 Binder.restoreCallingIdentity(identity);
1847 public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
1848 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
1849 return mZenModeHelper.getZenRules();
1853 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
1854 Preconditions.checkNotNull(id, "Id is null");
1855 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
1856 return mZenModeHelper.getAutomaticZenRule(id);
1860 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
1861 throws RemoteException {
1862 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
1863 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
1864 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
1865 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
1866 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
1868 return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
1869 "addAutomaticZenRule");
1873 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
1874 throws RemoteException {
1875 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
1876 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
1877 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
1878 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
1879 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
1881 return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
1882 "updateAutomaticZenRule");
1886 public boolean removeAutomaticZenRule(String id) throws RemoteException {
1887 Preconditions.checkNotNull(id, "Id is null");
1888 // Verify that they can modify zen rules.
1889 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
1891 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
1895 public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
1896 Preconditions.checkNotNull(packageName, "Package name is null");
1897 enforceSystemOrSystemUI("removeAutomaticZenRules");
1899 return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
1903 public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
1904 Preconditions.checkNotNull(owner, "Owner is null");
1905 enforceSystemOrSystemUI("getRuleInstanceCount");
1907 return mZenModeHelper.getCurrentInstanceCount(owner);
1911 public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
1912 enforcePolicyAccess(pkg, "setInterruptionFilter");
1913 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
1914 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
1915 final long identity = Binder.clearCallingIdentity();
1917 mZenModeHelper.setManualZenMode(zen, null, "setInterruptionFilter");
1919 Binder.restoreCallingIdentity(identity);
1924 public void notifyConditions(final String pkg, IConditionProvider provider,
1925 final Condition[] conditions) {
1926 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
1927 checkCallerIsSystemOrSameApp(pkg);
1928 mHandler.post(new Runnable() {
1931 mConditionProviders.notifyConditions(pkg, info, conditions);
1936 private void enforceSystemOrSystemUIOrVolume(String message) {
1937 if (mAudioManagerInternal != null) {
1938 final int vcuid = mAudioManagerInternal.getVolumeControllerUid();
1939 if (vcuid > 0 && Binder.getCallingUid() == vcuid) {
1943 enforceSystemOrSystemUI(message);
1946 private void enforceSystemOrSystemUI(String message) {
1947 if (isCallerSystem()) return;
1948 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
1952 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
1954 checkCallerIsSystemOrSameApp(pkg);
1955 } catch (SecurityException e) {
1956 getContext().enforceCallingPermission(
1957 android.Manifest.permission.STATUS_BAR_SERVICE,
1962 private void enforcePolicyAccess(int uid, String method) {
1963 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
1964 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
1967 boolean accessAllowed = false;
1968 String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
1969 final int packageCount = packages.length;
1970 for (int i = 0; i < packageCount; i++) {
1971 if (checkPolicyAccess(packages[i])) {
1972 accessAllowed = true;
1975 if (!accessAllowed) {
1976 Slog.w(TAG, "Notification policy access denied calling " + method);
1977 throw new SecurityException("Notification policy access denied");
1981 private void enforcePolicyAccess(String pkg, String method) {
1982 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
1983 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
1986 checkCallerIsSameApp(pkg);
1987 if (!checkPolicyAccess(pkg)) {
1988 Slog.w(TAG, "Notification policy access denied calling " + method);
1989 throw new SecurityException("Notification policy access denied");
1993 private boolean checkPackagePolicyAccess(String pkg) {
1994 return mPolicyAccess.isPackageGranted(pkg);
1997 private boolean checkPolicyAccess(String pkg) {
1999 int uid = getContext().getPackageManager().getPackageUidAsUser(
2000 pkg, UserHandle.getCallingUserId());
2001 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
2002 android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
2006 } catch (NameNotFoundException e) {
2009 return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
2013 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2014 if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2015 != PackageManager.PERMISSION_GRANTED) {
2016 pw.println("Permission Denial: can't dump NotificationManager from pid="
2017 + Binder.getCallingPid()
2018 + ", uid=" + Binder.getCallingUid());
2022 final DumpFilter filter = DumpFilter.parseFromArguments(args);
2023 if (filter != null && filter.stats) {
2024 dumpJson(pw, filter);
2026 dumpImpl(pw, filter);
2031 public ComponentName getEffectsSuppressor() {
2032 enforceSystemOrSystemUIOrVolume("INotificationManager.getEffectsSuppressor");
2033 return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
2037 public boolean matchesCallFilter(Bundle extras) {
2038 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
2039 return mZenModeHelper.matchesCallFilter(
2040 Binder.getCallingUserHandle(),
2042 mRankingHelper.findExtractor(ValidateNotificationPeople.class),
2043 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
2044 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
2048 public boolean isSystemConditionProviderEnabled(String path) {
2049 enforceSystemOrSystemUIOrVolume("INotificationManager.isSystemConditionProviderEnabled");
2050 return mConditionProviders.isSystemProviderEnabled(path);
2053 // Backup/restore interface
2055 public byte[] getBackupPayload(int user) {
2056 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
2057 //TODO: http://b/22388012
2058 if (user != UserHandle.USER_SYSTEM) {
2059 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
2062 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
2064 writePolicyXml(baos, true /*forBackup*/);
2065 return baos.toByteArray();
2066 } catch (IOException e) {
2067 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
2073 public void applyRestore(byte[] payload, int user) {
2074 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
2075 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
2076 if (payload == null) {
2077 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
2080 //TODO: http://b/22388012
2081 if (user != UserHandle.USER_SYSTEM) {
2082 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
2085 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
2087 readPolicyXml(bais, true /*forRestore*/);
2089 } catch (NumberFormatException | XmlPullParserException | IOException e) {
2090 Slog.w(TAG, "applyRestore: error reading payload", e);
2095 public boolean isNotificationPolicyAccessGranted(String pkg) {
2096 return checkPolicyAccess(pkg);
2100 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
2101 enforceSystemOrSystemUIOrSamePackage(pkg,
2102 "request policy access status for another package");
2103 return checkPolicyAccess(pkg);
2107 public String[] getPackagesRequestingNotificationPolicyAccess()
2108 throws RemoteException {
2109 enforceSystemOrSystemUI("request policy access packages");
2110 final long identity = Binder.clearCallingIdentity();
2112 return mPolicyAccess.getRequestingPackages();
2114 Binder.restoreCallingIdentity(identity);
2119 public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
2120 throws RemoteException {
2121 enforceSystemOrSystemUI("grant notification policy access");
2122 final long identity = Binder.clearCallingIdentity();
2124 synchronized (mNotificationList) {
2125 mPolicyAccess.put(pkg, granted);
2128 Binder.restoreCallingIdentity(identity);
2133 public Policy getNotificationPolicy(String pkg) {
2134 enforcePolicyAccess(pkg, "getNotificationPolicy");
2135 final long identity = Binder.clearCallingIdentity();
2137 return mZenModeHelper.getNotificationPolicy();
2139 Binder.restoreCallingIdentity(identity);
2144 public void setNotificationPolicy(String pkg, Policy policy) {
2145 enforcePolicyAccess(pkg, "setNotificationPolicy");
2146 final long identity = Binder.clearCallingIdentity();
2148 mZenModeHelper.setNotificationPolicy(policy);
2150 Binder.restoreCallingIdentity(identity);
2155 public void applyAdjustmentFromRankerService(INotificationListener token,
2156 Adjustment adjustment) throws RemoteException {
2157 final long identity = Binder.clearCallingIdentity();
2159 synchronized (mNotificationList) {
2160 mRankerServices.checkServiceTokenLocked(token);
2161 applyAdjustmentLocked(adjustment);
2163 maybeAddAutobundleSummary(adjustment);
2164 mRankingHandler.requestSort();
2166 Binder.restoreCallingIdentity(identity);
2171 public void applyAdjustmentsFromRankerService(INotificationListener token,
2172 List<Adjustment> adjustments) throws RemoteException {
2174 final long identity = Binder.clearCallingIdentity();
2176 synchronized (mNotificationList) {
2177 mRankerServices.checkServiceTokenLocked(token);
2178 for (Adjustment adjustment : adjustments) {
2179 applyAdjustmentLocked(adjustment);
2182 for (Adjustment adjustment : adjustments) {
2183 maybeAddAutobundleSummary(adjustment);
2185 mRankingHandler.requestSort();
2187 Binder.restoreCallingIdentity(identity);
2192 private void applyAdjustmentLocked(Adjustment adjustment) {
2193 maybeClearAutobundleSummaryLocked(adjustment);
2194 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2198 if (adjustment.getImportance() != IMPORTANCE_NONE) {
2199 n.setImportance(adjustment.getImportance(), adjustment.getExplanation());
2201 if (adjustment.getSignals() != null) {
2202 Bundle.setDefusable(adjustment.getSignals(), true);
2203 final String autoGroupKey = adjustment.getSignals().getString(
2204 Adjustment.GROUP_KEY_OVERRIDE_KEY, null);
2205 if (autoGroupKey == null) {
2206 EventLogTags.writeNotificationUnautogrouped(adjustment.getKey());
2208 EventLogTags.writeNotificationAutogrouped(adjustment.getKey());
2210 n.sbn.setOverrideGroupKey(autoGroupKey);
2214 // Clears the 'fake' auto-bunding summary.
2215 private void maybeClearAutobundleSummaryLocked(Adjustment adjustment) {
2216 if (adjustment.getSignals() != null) {
2217 Bundle.setDefusable(adjustment.getSignals(), true);
2218 if (adjustment.getSignals().containsKey(Adjustment.NEEDS_AUTOGROUPING_KEY)
2219 && !adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) {
2220 ArrayMap<String, String> summaries =
2221 mAutobundledSummaries.get(adjustment.getUser());
2222 if (summaries != null && summaries.containsKey(adjustment.getPackage())) {
2224 final NotificationRecord removed = mNotificationsByKey.get(
2225 summaries.remove(adjustment.getPackage()));
2226 if (removed != null) {
2227 mNotificationList.remove(removed);
2228 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED);
2235 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
2236 private void maybeAddAutobundleSummary(Adjustment adjustment) {
2237 if (adjustment.getSignals() != null) {
2238 Bundle.setDefusable(adjustment.getSignals(), true);
2239 if (adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) {
2240 final String newAutoBundleKey =
2241 adjustment.getSignals().getString(Adjustment.GROUP_KEY_OVERRIDE_KEY, null);
2243 NotificationRecord summaryRecord = null;
2244 synchronized (mNotificationList) {
2245 NotificationRecord notificationRecord =
2246 mNotificationsByKey.get(adjustment.getKey());
2247 if (notificationRecord == null) {
2248 // The notification could have been cancelled again already. A successive
2249 // adjustment will post a summary if needed.
2252 final StatusBarNotification adjustedSbn = notificationRecord.sbn;
2253 userId = adjustedSbn.getUser().getIdentifier();
2254 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
2255 if (summaries == null) {
2256 summaries = new ArrayMap<>();
2258 mAutobundledSummaries.put(userId, summaries);
2259 if (!summaries.containsKey(adjustment.getPackage())
2260 && newAutoBundleKey != null) {
2262 final ApplicationInfo appInfo =
2263 adjustedSbn.getNotification().extras.getParcelable(
2264 Notification.EXTRA_BUILDER_APPLICATION_INFO);
2265 final Bundle extras = new Bundle();
2266 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
2267 final Notification summaryNotification =
2268 new Notification.Builder(getContext()).setSmallIcon(
2269 adjustedSbn.getNotification().getSmallIcon())
2270 .setGroupSummary(true)
2271 .setGroup(newAutoBundleKey)
2272 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
2273 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
2274 .setColor(adjustedSbn.getNotification().color)
2276 summaryNotification.extras.putAll(extras);
2277 Intent appIntent = getContext().getPackageManager()
2278 .getLaunchIntentForPackage(adjustment.getPackage());
2279 if (appIntent != null) {
2280 summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
2281 getContext(), 0, appIntent, 0, null,
2282 UserHandle.of(userId));
2284 final StatusBarNotification summarySbn =
2285 new StatusBarNotification(adjustedSbn.getPackageName(),
2286 adjustedSbn.getOpPkg(),
2287 Integer.MAX_VALUE, Adjustment.GROUP_KEY_OVERRIDE_KEY,
2288 adjustedSbn.getUid(), adjustedSbn.getInitialPid(),
2289 summaryNotification, adjustedSbn.getUser(),
2291 System.currentTimeMillis());
2292 summaryRecord = new NotificationRecord(getContext(), summarySbn);
2293 summaries.put(adjustment.getPackage(), summarySbn.getKey());
2296 if (summaryRecord != null) {
2297 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
2303 private String disableNotificationEffects(NotificationRecord record) {
2304 if (mDisableNotificationEffects) {
2305 return "booleanState";
2307 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
2308 return "listenerHints";
2310 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
2316 private void dumpJson(PrintWriter pw, DumpFilter filter) {
2317 JSONObject dump = new JSONObject();
2319 dump.put("service", "Notification Manager");
2320 dump.put("bans", mRankingHelper.dumpBansJson(filter));
2321 dump.put("ranking", mRankingHelper.dumpJson(filter));
2322 dump.put("stats", mUsageStats.dumpJson(filter));
2323 } catch (JSONException e) {
2324 e.printStackTrace();
2329 void dumpImpl(PrintWriter pw, DumpFilter filter) {
2330 pw.print("Current Notification Manager state");
2331 if (filter.filtered) {
2332 pw.print(" (filtered to "); pw.print(filter); pw.print(")");
2336 final boolean zenOnly = filter.filtered && filter.zen;
2339 synchronized (mToastQueue) {
2340 N = mToastQueue.size();
2342 pw.println(" Toast Queue:");
2343 for (int i=0; i<N; i++) {
2344 mToastQueue.get(i).dump(pw, " ", filter);
2351 synchronized (mNotificationList) {
2353 N = mNotificationList.size();
2355 pw.println(" Notification List:");
2356 for (int i=0; i<N; i++) {
2357 final NotificationRecord nr = mNotificationList.get(i);
2358 if (filter.filtered && !filter.matches(nr.sbn)) continue;
2359 nr.dump(pw, " ", getContext(), filter.redact);
2364 if (!filter.filtered) {
2367 pw.println(" Lights List:");
2368 for (int i=0; i<N; i++) {
2374 pw.println(mLights.get(i));
2378 pw.println(" mUseAttentionLight=" + mUseAttentionLight);
2379 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled);
2380 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey);
2381 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey);
2382 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects);
2383 pw.println(" mCallState=" + callStateToString(mCallState));
2384 pw.println(" mSystemReady=" + mSystemReady);
2385 pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
2387 pw.println(" mArchive=" + mArchive.toString());
2388 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
2390 while (iter.hasNext()) {
2391 final StatusBarNotification sbn = iter.next();
2392 if (filter != null && !filter.matches(sbn)) continue;
2393 pw.println(" " + sbn);
2395 if (iter.hasNext()) pw.println(" ...");
2402 pw.println("\n Usage Stats:");
2403 mUsageStats.dump(pw, " ", filter);
2406 if (!filter.filtered || zenOnly) {
2407 pw.println("\n Zen Mode:");
2408 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter);
2409 mZenModeHelper.dump(pw, " ");
2411 pw.println("\n Zen Log:");
2412 ZenLog.dump(pw, " ");
2416 pw.println("\n Ranking Config:");
2417 mRankingHelper.dump(pw, " ", filter);
2419 pw.println("\n Notification listeners:");
2420 mListeners.dump(pw, filter);
2421 pw.print(" mListenerHints: "); pw.println(mListenerHints);
2422 pw.print(" mListenersDisablingEffects: (");
2423 N = mListenersDisablingEffects.size();
2424 for (int i = 0; i < N; i++) {
2425 final int hint = mListenersDisablingEffects.keyAt(i);
2426 if (i > 0) pw.print(';');
2427 pw.print("hint[" + hint + "]:");
2429 final ArraySet<ManagedServiceInfo> listeners =
2430 mListenersDisablingEffects.valueAt(i);
2431 final int listenerSize = listeners.size();
2433 for (int j = 0; j < listenerSize; j++) {
2434 if (i > 0) pw.print(',');
2435 final ManagedServiceInfo listener = listeners.valueAt(i);
2436 pw.print(listener.component);
2440 pw.println("\n mRankerServicePackageName: " + mRankerServicePackageName);
2441 pw.println("\n Notification ranker services:");
2442 mRankerServices.dump(pw, filter);
2444 pw.println("\n Policy access:");
2445 pw.print(" mPolicyAccess: "); pw.println(mPolicyAccess);
2447 pw.println("\n Condition providers:");
2448 mConditionProviders.dump(pw, filter);
2450 pw.println("\n Group summaries:");
2451 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
2452 NotificationRecord r = entry.getValue();
2453 pw.println(" " + entry.getKey() + " -> " + r.getKey());
2454 if (mNotificationsByKey.get(r.getKey()) != r) {
2455 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
2456 r.dump(pw, " ", getContext(), filter.redact);
2463 * The private API only accessible to the system process.
2465 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
2467 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
2468 String tag, int id, Notification notification, int[] idReceived, int userId) {
2469 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
2470 idReceived, userId);
2474 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
2476 checkCallerIsSystem();
2477 synchronized (mNotificationList) {
2478 int i = indexOfNotificationLocked(pkg, null, notificationId, userId);
2480 Log.d(TAG, "stripForegroundServiceFlag: Could not find notification with "
2481 + "pkg=" + pkg + " / id=" + notificationId + " / userId=" + userId);
2484 NotificationRecord r = mNotificationList.get(i);
2485 StatusBarNotification sbn = r.sbn;
2486 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
2487 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove FLAG_FOREGROUND_SERVICE,
2488 // we have to revert to the flags we received initially *and* force remove
2489 // FLAG_FOREGROUND_SERVICE.
2490 sbn.getNotification().flags =
2491 (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
2492 mRankingHelper.sort(mNotificationList);
2493 mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
2498 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
2499 final int callingPid, final String tag, final int id, final Notification notification,
2500 int[] idOut, int incomingUserId) {
2502 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
2503 + " notification=" + notification);
2505 checkCallerIsSystemOrSameApp(pkg);
2506 final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg));
2507 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
2509 final int userId = ActivityManager.handleIncomingUser(callingPid,
2510 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
2511 final UserHandle user = new UserHandle(userId);
2513 // Fix the notification as best we can.
2515 final ApplicationInfo ai = getContext().getPackageManager().getApplicationInfoAsUser(
2516 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
2517 (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
2518 Notification.addFieldsFromContext(ai, userId, notification);
2519 } catch (NameNotFoundException e) {
2520 Slog.e(TAG, "Cannot create a context for sending app", e);
2524 mUsageStats.registerEnqueuedByApp(pkg);
2526 // Limit the number of notifications that any given package except the android
2527 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
2528 if (!isSystemNotification && !isNotificationFromListener) {
2529 synchronized (mNotificationList) {
2530 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
2531 if (appEnqueueRate > mMaxPackageEnqueueRate) {
2532 mUsageStats.registerOverRateQuota(pkg);
2533 final long now = SystemClock.elapsedRealtime();
2534 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
2535 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
2536 + ". Shedding events. package=" + pkg);
2537 mLastOverRateLogTime = now;
2543 final int N = mNotificationList.size();
2544 for (int i=0; i<N; i++) {
2545 final NotificationRecord r = mNotificationList.get(i);
2546 if (r.sbn.getPackageName().equals(pkg) && r.sbn.getUserId() == userId) {
2547 if (r.sbn.getId() == id && TextUtils.equals(r.sbn.getTag(), tag)) {
2548 break; // Allow updating existing notification
2551 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
2552 mUsageStats.registerOverCountQuota(pkg);
2553 Slog.e(TAG, "Package has already posted " + count
2554 + " notifications. Not showing more. package=" + pkg);
2562 if (pkg == null || notification == null) {
2563 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
2564 + " id=" + id + " notification=" + notification);
2567 // Whitelist pending intents.
2568 if (notification.allPendingIntents != null) {
2569 final int intentCount = notification.allPendingIntents.size();
2570 if (intentCount > 0) {
2571 final ActivityManagerInternal am = LocalServices
2572 .getService(ActivityManagerInternal.class);
2573 final long duration = LocalServices.getService(
2574 DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
2575 for (int i = 0; i < intentCount; i++) {
2576 PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
2577 if (pendingIntent != null) {
2578 am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(), duration);
2585 notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN,
2586 Notification.PRIORITY_MAX);
2588 // setup local book-keeping
2589 final StatusBarNotification n = new StatusBarNotification(
2590 pkg, opPkg, id, tag, callingUid, callingPid, 0, notification,
2592 final NotificationRecord r = new NotificationRecord(getContext(), n);
2593 mHandler.post(new EnqueueNotificationRunnable(userId, r));
2598 private class EnqueueNotificationRunnable implements Runnable {
2599 private final NotificationRecord r;
2600 private final int userId;
2602 EnqueueNotificationRunnable(int userId, NotificationRecord r) {
2603 this.userId = userId;
2610 synchronized (mNotificationList) {
2611 final StatusBarNotification n = r.sbn;
2612 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
2613 NotificationRecord old = mNotificationsByKey.get(n.getKey());
2615 // Retain ranking information from previous record
2616 r.copyRankingInformation(old);
2619 final int callingUid = n.getUid();
2620 final int callingPid = n.getInitialPid();
2621 final Notification notification = n.getNotification();
2622 final String pkg = n.getPackageName();
2623 final int id = n.getId();
2624 final String tag = n.getTag();
2625 final boolean isSystemNotification = isUidSystem(callingUid) ||
2626 ("android".equals(pkg));
2628 // Handle grouped notifications and bail out early if we
2629 // can to avoid extracting signals.
2630 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
2632 // This conditional is a dirty hack to limit the logging done on
2633 // behalf of the download manager without affecting other apps.
2634 if (!pkg.equals("com.android.providers.downloads")
2635 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
2636 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
2638 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
2640 EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
2641 pkg, id, tag, userId, notification.toString(),
2645 mRankingHelper.extractSignals(r);
2647 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
2650 if (r.getImportance() == NotificationListenerService.Ranking.IMPORTANCE_NONE
2651 || !noteNotificationOp(pkg, callingUid) || isPackageSuspended) {
2652 if (!isSystemNotification) {
2653 if (isPackageSuspended) {
2654 Slog.e(TAG, "Suppressing notification from package due to package "
2655 + "suspended by administrator.");
2656 mUsageStats.registerSuspendedByAdmin(r);
2658 Slog.e(TAG, "Suppressing notification from package by user request.");
2659 mUsageStats.registerBlocked(r);
2665 // tell the ranker service about the notification
2666 if (mRankerServices.isEnabled()) {
2667 mRankerServices.onNotificationEnqueued(r);
2668 // TODO delay the code below here for 100ms or until there is an answer
2672 int index = indexOfNotificationLocked(n.getKey());
2674 mNotificationList.add(r);
2675 mUsageStats.registerPostedByApp(r);
2677 old = mNotificationList.get(index);
2678 mNotificationList.set(index, r);
2679 mUsageStats.registerUpdatedByApp(r, old);
2680 // Make sure we don't lose the foreground service state.
2681 notification.flags |=
2682 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
2686 mNotificationsByKey.put(n.getKey(), r);
2688 // Ensure if this is a foreground service that the proper additional
2690 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
2691 notification.flags |= Notification.FLAG_ONGOING_EVENT
2692 | Notification.FLAG_NO_CLEAR;
2695 applyZenModeLocked(r);
2696 mRankingHelper.sort(mNotificationList);
2698 if (notification.getSmallIcon() != null) {
2699 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
2700 mListeners.notifyPostedLocked(n, oldSbn);
2702 Slog.e(TAG, "Not posting notification without small icon: " + notification);
2703 if (old != null && !old.isCanceled) {
2704 mListeners.notifyRemovedLocked(n);
2706 // ATTENTION: in a future release we will bail out here
2707 // so that we do not play sounds, show lights, etc. for invalid
2709 Slog.e(TAG, "WARNING: In a future release this will crash the app: "
2710 + n.getPackageName());
2713 buzzBeepBlinkLocked(r);
2719 * Ensures that grouped notification receive their special treatment.
2721 * <p>Cancels group children if the new notification causes a group to lose
2724 * <p>Updates mSummaryByGroupKey.</p>
2726 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
2727 int callingUid, int callingPid) {
2728 StatusBarNotification sbn = r.sbn;
2729 Notification n = sbn.getNotification();
2730 if (n.isGroupSummary() && !sbn.isAppGroup()) {
2731 // notifications without a group shouldn't be a summary, otherwise autobundling can
2733 n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
2736 String group = sbn.getGroupKey();
2737 boolean isSummary = n.isGroupSummary();
2739 Notification oldN = old != null ? old.sbn.getNotification() : null;
2740 String oldGroup = old != null ? old.sbn.getGroupKey() : null;
2741 boolean oldIsSummary = old != null && oldN.isGroupSummary();
2744 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
2745 if (removedSummary != old) {
2747 removedSummary != null ? removedSummary.getKey() : "<null>";
2748 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
2749 ", removed=" + removedKey);
2753 mSummaryByGroupKey.put(group, r);
2756 // Clear out group children of the old notification if the update
2757 // causes the group summary to go away. This happens when the old
2758 // notification was a summary and the new one isn't, or when the old
2759 // notification was a summary and its group key changed.
2760 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
2761 cancelGroupChildrenLocked(old, callingUid, callingPid, null,
2762 REASON_GROUP_SUMMARY_CANCELED, false /* sendDelete */);
2767 void buzzBeepBlinkLocked(NotificationRecord record) {
2768 boolean buzz = false;
2769 boolean beep = false;
2770 boolean blink = false;
2772 final Notification notification = record.sbn.getNotification();
2773 final String key = record.getKey();
2775 // Should this notification make noise, vibe, or use the LED?
2776 final boolean aboveThreshold = record.getImportance() >= IMPORTANCE_DEFAULT;
2777 final boolean canInterrupt = aboveThreshold && !record.isIntercepted();
2778 if (DBG || record.isIntercepted())
2780 "pkg=" + record.sbn.getPackageName() + " canInterrupt=" + canInterrupt +
2781 " intercept=" + record.isIntercepted()
2784 final int currentUser;
2785 final long token = Binder.clearCallingIdentity();
2787 currentUser = ActivityManager.getCurrentUser();
2789 Binder.restoreCallingIdentity(token);
2792 // If we're not supposed to beep, vibrate, etc. then don't.
2793 final String disableEffects = disableNotificationEffects(record);
2794 if (disableEffects != null) {
2795 ZenLog.traceDisableEffects(record, disableEffects);
2798 // Remember if this notification already owns the notification channels.
2799 boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
2800 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
2802 // These are set inside the conditional if the notification is allowed to make noise.
2803 boolean hasValidVibrate = false;
2804 boolean hasValidSound = false;
2805 if (disableEffects == null
2806 && (record.getUserId() == UserHandle.USER_ALL ||
2807 record.getUserId() == currentUser ||
2808 mUserProfiles.isCurrentProfile(record.getUserId()))
2811 && mAudioManager != null) {
2812 if (DBG) Slog.v(TAG, "Interrupting!");
2814 // should we use the default notification sound? (indicated either by
2815 // DEFAULT_SOUND or because notification.sound is pointing at
2816 // Settings.System.NOTIFICATION_SOUND)
2817 final boolean useDefaultSound =
2818 (notification.defaults & Notification.DEFAULT_SOUND) != 0 ||
2819 Settings.System.DEFAULT_NOTIFICATION_URI
2820 .equals(notification.sound);
2822 Uri soundUri = null;
2823 if (useDefaultSound) {
2824 soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
2826 // check to see if the default notification sound is silent
2827 ContentResolver resolver = getContext().getContentResolver();
2828 hasValidSound = Settings.System.getString(resolver,
2829 Settings.System.NOTIFICATION_SOUND) != null;
2830 } else if (notification.sound != null) {
2831 soundUri = notification.sound;
2832 hasValidSound = (soundUri != null);
2835 // Does the notification want to specify its own vibration?
2836 final boolean hasCustomVibrate = notification.vibrate != null;
2838 // new in 4.2: if there was supposed to be a sound and we're in vibrate
2839 // mode, and no other vibration is specified, we fall back to vibration
2840 final boolean convertSoundToVibration =
2843 && (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE);
2845 // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
2846 final boolean useDefaultVibrate =
2847 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
2849 hasValidVibrate = useDefaultVibrate || convertSoundToVibration ||
2852 // We can alert, and we're allowed to alert, but if the developer asked us to only do
2853 // it once, and we already have, then don't.
2854 if (!(record.isUpdate
2855 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0)) {
2857 sendAccessibilityEvent(notification, record.sbn.getPackageName());
2859 if (hasValidSound) {
2861 (notification.flags & Notification.FLAG_INSISTENT) != 0;
2862 AudioAttributes audioAttributes = audioAttributesForNotification(notification);
2863 mSoundNotificationKey = key;
2864 // do not play notifications if stream volume is 0 (typically because
2865 // ringer mode is silent) or if there is a user of exclusive audio focus
2866 if ((mAudioManager.getStreamVolume(
2867 AudioAttributes.toLegacyStreamType(audioAttributes)) != 0)
2868 && !mAudioManager.isAudioFocusExclusive()) {
2869 final long identity = Binder.clearCallingIdentity();
2871 final IRingtonePlayer player =
2872 mAudioManager.getRingtonePlayer();
2873 if (player != null) {
2874 if (DBG) Slog.v(TAG, "Playing sound " + soundUri
2875 + " with attributes " + audioAttributes);
2876 player.playAsync(soundUri, record.sbn.getUser(), looping,
2880 } catch (RemoteException e) {
2882 Binder.restoreCallingIdentity(identity);
2887 if (hasValidVibrate && !(mAudioManager.getRingerModeInternal()
2888 == AudioManager.RINGER_MODE_SILENT)) {
2889 mVibrateNotificationKey = key;
2891 if (useDefaultVibrate || convertSoundToVibration) {
2892 // Escalate privileges so we can use the vibrator even if the
2893 // notifying app does not have the VIBRATE permission.
2894 long identity = Binder.clearCallingIdentity();
2896 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
2897 useDefaultVibrate ? mDefaultVibrationPattern
2898 : mFallbackVibrationPattern,
2899 ((notification.flags & Notification.FLAG_INSISTENT) != 0)
2900 ? 0: -1, audioAttributesForNotification(notification));
2903 Binder.restoreCallingIdentity(identity);
2905 } else if (notification.vibrate.length > 1) {
2906 // If you want your own vibration pattern, you need the VIBRATE
2908 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
2909 notification.vibrate,
2910 ((notification.flags & Notification.FLAG_INSISTENT) != 0)
2911 ? 0: -1, audioAttributesForNotification(notification));
2918 // If a notification is updated to remove the actively playing sound or vibrate,
2919 // cancel that feedback now
2920 if (wasBeep && !hasValidSound) {
2923 if (wasBuzz && !hasValidVibrate) {
2924 clearVibrateLocked();
2928 // release the light
2929 boolean wasShowLights = mLights.remove(key);
2930 if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold
2931 && ((record.getSuppressedVisualEffects()
2932 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
2934 updateLightsLocked();
2935 if (mUseAttentionLight) {
2936 mAttentionLight.pulse();
2939 } else if (wasShowLights) {
2940 updateLightsLocked();
2942 if (buzz || beep || blink) {
2943 if (((record.getSuppressedVisualEffects()
2944 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) != 0)) {
2945 if (DBG) Slog.v(TAG, "Suppressed SystemUI from triggering screen on");
2947 EventLogTags.writeNotificationAlert(key,
2948 buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
2949 mHandler.post(mBuzzBeepBlinked);
2954 private static AudioAttributes audioAttributesForNotification(Notification n) {
2955 if (n.audioAttributes != null
2956 && !Notification.AUDIO_ATTRIBUTES_DEFAULT.equals(n.audioAttributes)) {
2957 // the audio attributes are set and different from the default, use them
2958 return n.audioAttributes;
2959 } else if (n.audioStreamType >= 0 && n.audioStreamType < AudioSystem.getNumStreamTypes()) {
2960 // the stream type is valid, use it
2961 return new AudioAttributes.Builder()
2962 .setInternalLegacyStreamType(n.audioStreamType)
2964 } else if (n.audioStreamType == AudioSystem.STREAM_DEFAULT) {
2965 return Notification.AUDIO_ATTRIBUTES_DEFAULT;
2967 Log.w(TAG, String.format("Invalid stream type: %d", n.audioStreamType));
2968 return Notification.AUDIO_ATTRIBUTES_DEFAULT;
2972 void showNextToastLocked() {
2973 ToastRecord record = mToastQueue.get(0);
2974 while (record != null) {
2975 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
2977 record.callback.show();
2978 scheduleTimeoutLocked(record);
2980 } catch (RemoteException e) {
2981 Slog.w(TAG, "Object died trying to show notification " + record.callback
2982 + " in package " + record.pkg);
2983 // remove it from the list and let the process die
2984 int index = mToastQueue.indexOf(record);
2986 mToastQueue.remove(index);
2988 keepProcessAliveLocked(record.pid);
2989 if (mToastQueue.size() > 0) {
2990 record = mToastQueue.get(0);
2998 void cancelToastLocked(int index) {
2999 ToastRecord record = mToastQueue.get(index);
3001 record.callback.hide();
3002 } catch (RemoteException e) {
3003 Slog.w(TAG, "Object died trying to hide notification " + record.callback
3004 + " in package " + record.pkg);
3005 // don't worry about this, we're about to remove it from
3008 mToastQueue.remove(index);
3009 keepProcessAliveLocked(record.pid);
3010 if (mToastQueue.size() > 0) {
3011 // Show the next one. If the callback fails, this will remove
3012 // it from the list, so don't assume that the list hasn't changed
3013 // after this point.
3014 showNextToastLocked();
3018 private void scheduleTimeoutLocked(ToastRecord r)
3020 mHandler.removeCallbacksAndMessages(r);
3021 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
3022 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
3023 mHandler.sendMessageDelayed(m, delay);
3026 private void handleTimeout(ToastRecord record)
3028 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
3029 synchronized (mToastQueue) {
3030 int index = indexOfToastLocked(record.pkg, record.callback);
3032 cancelToastLocked(index);
3037 // lock on mToastQueue
3038 int indexOfToastLocked(String pkg, ITransientNotification callback)
3040 IBinder cbak = callback.asBinder();
3041 ArrayList<ToastRecord> list = mToastQueue;
3042 int len = list.size();
3043 for (int i=0; i<len; i++) {
3044 ToastRecord r = list.get(i);
3045 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
3052 // lock on mToastQueue
3053 void keepProcessAliveLocked(int pid)
3055 int toastCount = 0; // toasts from this pid
3056 ArrayList<ToastRecord> list = mToastQueue;
3057 int N = list.size();
3058 for (int i=0; i<N; i++) {
3059 ToastRecord r = list.get(i);
3065 mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
3066 } catch (RemoteException e) {
3067 // Shouldn't happen.
3071 private void handleRankingReconsideration(Message message) {
3072 if (!(message.obj instanceof RankingReconsideration)) return;
3073 RankingReconsideration recon = (RankingReconsideration) message.obj;
3076 synchronized (mNotificationList) {
3077 final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
3078 if (record == null) {
3081 int indexBefore = findNotificationRecordIndexLocked(record);
3082 boolean interceptBefore = record.isIntercepted();
3083 int visibilityBefore = record.getPackageVisibilityOverride();
3084 recon.applyChangesLocked(record);
3085 applyZenModeLocked(record);
3086 mRankingHelper.sort(mNotificationList);
3087 int indexAfter = findNotificationRecordIndexLocked(record);
3088 boolean interceptAfter = record.isIntercepted();
3089 int visibilityAfter = record.getPackageVisibilityOverride();
3090 changed = indexBefore != indexAfter || interceptBefore != interceptAfter
3091 || visibilityBefore != visibilityAfter;
3092 if (interceptBefore && !interceptAfter) {
3093 buzzBeepBlinkLocked(record);
3097 scheduleSendRankingUpdate();
3101 private void handleRankingSort() {
3102 synchronized (mNotificationList) {
3103 final int N = mNotificationList.size();
3104 ArrayList<String> orderBefore = new ArrayList<String>(N);
3105 ArrayList<String> groupOverrideBefore = new ArrayList<>(N);
3106 int[] visibilities = new int[N];
3107 int[] importances = new int[N];
3108 for (int i = 0; i < N; i++) {
3109 final NotificationRecord r = mNotificationList.get(i);
3110 orderBefore.add(r.getKey());
3111 groupOverrideBefore.add(r.sbn.getGroupKey());
3112 visibilities[i] = r.getPackageVisibilityOverride();
3113 importances[i] = r.getImportance();
3114 mRankingHelper.extractSignals(r);
3116 mRankingHelper.sort(mNotificationList);
3117 for (int i = 0; i < N; i++) {
3118 final NotificationRecord r = mNotificationList.get(i);
3119 if (!orderBefore.get(i).equals(r.getKey())
3120 || visibilities[i] != r.getPackageVisibilityOverride()
3121 || importances[i] != r.getImportance()
3122 || !groupOverrideBefore.get(i).equals(r.sbn.getGroupKey())) {
3123 scheduleSendRankingUpdate();
3130 // let zen mode evaluate this record
3131 private void applyZenModeLocked(NotificationRecord record) {
3132 record.setIntercepted(mZenModeHelper.shouldIntercept(record));
3133 if (record.isIntercepted()) {
3134 int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
3135 ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
3136 | (mZenModeHelper.shouldSuppressWhenScreenOn()
3137 ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
3138 record.setSuppressedVisualEffects(suppressed);
3142 // lock on mNotificationList
3143 private int findNotificationRecordIndexLocked(NotificationRecord target) {
3144 return mRankingHelper.indexOf(mNotificationList, target);
3147 private void scheduleSendRankingUpdate() {
3148 if (!mHandler.hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
3149 Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE);
3150 mHandler.sendMessage(m);
3154 private void handleSendRankingUpdate() {
3155 synchronized (mNotificationList) {
3156 mListeners.notifyRankingUpdateLocked();
3160 private void scheduleListenerHintsChanged(int state) {
3161 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
3162 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
3165 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
3166 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
3167 mHandler.obtainMessage(
3168 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
3169 listenerInterruptionFilter,
3173 private void handleListenerHintsChanged(int hints) {
3174 synchronized (mNotificationList) {
3175 mListeners.notifyListenerHintsChangedLocked(hints);
3179 private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
3180 synchronized (mNotificationList) {
3181 mListeners.notifyInterruptionFilterChanged(interruptionFilter);
3185 private final class WorkerHandler extends Handler
3188 public void handleMessage(Message msg)
3192 case MESSAGE_TIMEOUT:
3193 handleTimeout((ToastRecord)msg.obj);
3195 case MESSAGE_SAVE_POLICY_FILE:
3196 handleSavePolicyFile();
3198 case MESSAGE_SEND_RANKING_UPDATE:
3199 handleSendRankingUpdate();
3201 case MESSAGE_LISTENER_HINTS_CHANGED:
3202 handleListenerHintsChanged(msg.arg1);
3204 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
3205 handleListenerInterruptionFilterChanged(msg.arg1);
3212 private final class RankingHandlerWorker extends Handler implements RankingHandler
3214 public RankingHandlerWorker(Looper looper) {
3219 public void handleMessage(Message msg) {
3221 case MESSAGE_RECONSIDER_RANKING:
3222 handleRankingReconsideration(msg);
3224 case MESSAGE_RANKING_SORT:
3225 handleRankingSort();
3230 public void requestSort() {
3231 removeMessages(MESSAGE_RANKING_SORT);
3232 sendEmptyMessage(MESSAGE_RANKING_SORT);
3235 public void requestReconsideration(RankingReconsideration recon) {
3236 Message m = Message.obtain(this,
3237 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
3238 long delay = recon.getDelay(TimeUnit.MILLISECONDS);
3239 sendMessageDelayed(m, delay);
3244 // ============================================================================
3245 static int clamp(int x, int low, int high) {
3246 return (x < low) ? low : ((x > high) ? high : x);
3249 void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
3250 AccessibilityManager manager = AccessibilityManager.getInstance(getContext());
3251 if (!manager.isEnabled()) {
3255 AccessibilityEvent event =
3256 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
3257 event.setPackageName(packageName);
3258 event.setClassName(Notification.class.getName());
3259 event.setParcelableData(notification);
3260 CharSequence tickerText = notification.tickerText;
3261 if (!TextUtils.isEmpty(tickerText)) {
3262 event.getText().add(tickerText);
3265 manager.sendAccessibilityEvent(event);
3268 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) {
3271 if (r.getNotification().deleteIntent != null) {
3273 r.getNotification().deleteIntent.send();
3274 } catch (PendingIntent.CanceledException ex) {
3275 // do nothing - there's no relevant way to recover, and
3276 // no reason to let this propagate
3277 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
3283 if (r.getNotification().getSmallIcon() != null) {
3284 r.isCanceled = true;
3285 mListeners.notifyRemovedLocked(r.sbn);
3288 final String canceledKey = r.getKey();
3291 if (canceledKey.equals(mSoundNotificationKey)) {
3292 mSoundNotificationKey = null;
3293 final long identity = Binder.clearCallingIdentity();
3295 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
3296 if (player != null) {
3299 } catch (RemoteException e) {
3301 Binder.restoreCallingIdentity(identity);
3306 if (canceledKey.equals(mVibrateNotificationKey)) {
3307 mVibrateNotificationKey = null;
3308 long identity = Binder.clearCallingIdentity();
3313 Binder.restoreCallingIdentity(identity);
3318 mLights.remove(canceledKey);
3320 // Record usage stats
3321 // TODO: add unbundling stats?
3323 case REASON_DELEGATE_CANCEL:
3324 case REASON_DELEGATE_CANCEL_ALL:
3325 case REASON_LISTENER_CANCEL:
3326 case REASON_LISTENER_CANCEL_ALL:
3327 mUsageStats.registerDismissedByUser(r);
3329 case REASON_APP_CANCEL:
3330 case REASON_APP_CANCEL_ALL:
3331 mUsageStats.registerRemovedByApp(r);
3335 mNotificationsByKey.remove(r.sbn.getKey());
3336 String groupKey = r.getGroupKey();
3337 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
3338 if (groupSummary != null && groupSummary.getKey().equals(r.getKey())) {
3339 mSummaryByGroupKey.remove(groupKey);
3341 final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
3342 if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
3343 summaries.remove(r.sbn.getPackageName());
3346 // Save it for users of getHistoricalNotifications()
3347 mArchive.record(r.sbn);
3349 final long now = System.currentTimeMillis();
3350 EventLogTags.writeNotificationCanceled(canceledKey, reason,
3351 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
3355 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
3356 * and none of the {@code mustNotHaveFlags}.
3358 void cancelNotification(final int callingUid, final int callingPid,
3359 final String pkg, final String tag, final int id,
3360 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
3361 final int userId, final int reason, final ManagedServiceInfo listener) {
3362 // In enqueueNotificationInternal notifications are added by scheduling the
3363 // work on the worker handler. Hence, we also schedule the cancel on this
3364 // handler to avoid a scenario where an add notification call followed by a
3365 // remove notification call ends up in not removing the notification.
3366 mHandler.post(new Runnable() {
3369 String listenerName = listener == null ? null : listener.component.toShortString();
3370 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
3371 userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
3373 synchronized (mNotificationList) {
3374 int index = indexOfNotificationLocked(pkg, tag, id, userId);
3376 NotificationRecord r = mNotificationList.get(index);
3378 // Ideally we'd do this in the caller of this method. However, that would
3379 // require the caller to also find the notification.
3380 if (reason == REASON_DELEGATE_CLICK) {
3381 mUsageStats.registerClickedByUser(r);
3384 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
3387 if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
3391 mNotificationList.remove(index);
3393 cancelNotificationLocked(r, sendDelete, reason);
3394 cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
3395 REASON_GROUP_SUMMARY_CANCELED, sendDelete);
3396 updateLightsLocked();
3404 * Determine whether the userId applies to the notification in question, either because
3405 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
3407 private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
3409 // looking for USER_ALL notifications? match everything
3410 userId == UserHandle.USER_ALL
3411 // a notification sent to USER_ALL matches any query
3412 || r.getUserId() == UserHandle.USER_ALL
3413 // an exact user match
3414 || r.getUserId() == userId;
3418 * Determine whether the userId applies to the notification in question, either because
3419 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
3420 * because it matches one of the users profiles.
3422 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
3423 return notificationMatchesUserId(r, userId)
3424 || mUserProfiles.isCurrentProfile(r.getUserId());
3428 * Cancels all notifications from a given package that have all of the
3429 * {@code mustHaveFlags}.
3431 boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags,
3432 int mustNotHaveFlags, boolean doit, int userId, int reason,
3433 ManagedServiceInfo listener) {
3434 String listenerName = listener == null ? null : listener.component.toShortString();
3435 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
3436 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
3439 synchronized (mNotificationList) {
3440 final int N = mNotificationList.size();
3441 ArrayList<NotificationRecord> canceledNotifications = null;
3442 for (int i = N-1; i >= 0; --i) {
3443 NotificationRecord r = mNotificationList.get(i);
3444 if (!notificationMatchesUserId(r, userId)) {
3447 // Don't remove notifications to all, if there's no package name specified
3448 if (r.getUserId() == UserHandle.USER_ALL && pkg == null) {
3451 if ((r.getFlags() & mustHaveFlags) != mustHaveFlags) {
3454 if ((r.getFlags() & mustNotHaveFlags) != 0) {
3457 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
3460 if (canceledNotifications == null) {
3461 canceledNotifications = new ArrayList<>();
3463 canceledNotifications.add(r);
3467 mNotificationList.remove(i);
3468 cancelNotificationLocked(r, false, reason);
3470 if (doit && canceledNotifications != null) {
3471 final int M = canceledNotifications.size();
3472 for (int i = 0; i < M; i++) {
3473 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
3474 listenerName, REASON_GROUP_SUMMARY_CANCELED, false /* sendDelete */);
3477 if (canceledNotifications != null) {
3478 updateLightsLocked();
3480 return canceledNotifications != null;
3484 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
3485 ManagedServiceInfo listener, boolean includeCurrentProfiles) {
3486 String listenerName = listener == null ? null : listener.component.toShortString();
3487 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
3488 null, userId, 0, 0, reason, listenerName);
3490 ArrayList<NotificationRecord> canceledNotifications = null;
3491 final int N = mNotificationList.size();
3492 for (int i=N-1; i>=0; i--) {
3493 NotificationRecord r = mNotificationList.get(i);
3494 if (includeCurrentProfiles) {
3495 if (!notificationMatchesCurrentProfiles(r, userId)) {
3499 if (!notificationMatchesUserId(r, userId)) {
3504 if ((r.getFlags() & (Notification.FLAG_ONGOING_EVENT
3505 | Notification.FLAG_NO_CLEAR)) == 0) {
3506 mNotificationList.remove(i);
3507 cancelNotificationLocked(r, true, reason);
3508 // Make a note so we can cancel children later.
3509 if (canceledNotifications == null) {
3510 canceledNotifications = new ArrayList<>();
3512 canceledNotifications.add(r);
3515 int M = canceledNotifications != null ? canceledNotifications.size() : 0;
3516 for (int i = 0; i < M; i++) {
3517 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
3518 listenerName, REASON_GROUP_SUMMARY_CANCELED, false /* sendDelete */);
3520 updateLightsLocked();
3523 // Warning: The caller is responsible for invoking updateLightsLocked().
3524 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
3525 String listenerName, int reason, boolean sendDelete) {
3526 Notification n = r.getNotification();
3527 if (!n.isGroupSummary()) {
3531 String pkg = r.sbn.getPackageName();
3532 int userId = r.getUserId();
3535 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
3539 final int N = mNotificationList.size();
3540 for (int i = N - 1; i >= 0; i--) {
3541 NotificationRecord childR = mNotificationList.get(i);
3542 StatusBarNotification childSbn = childR.sbn;
3543 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
3544 childR.getGroupKey().equals(r.getGroupKey())) {
3545 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
3546 childSbn.getTag(), userId, 0, 0, reason, listenerName);
3547 mNotificationList.remove(i);
3548 cancelNotificationLocked(childR, sendDelete, reason);
3553 // lock on mNotificationList
3554 void updateLightsLocked()
3556 // handle notification lights
3557 NotificationRecord ledNotification = null;
3558 while (ledNotification == null && !mLights.isEmpty()) {
3559 final String owner = mLights.get(mLights.size() - 1);
3560 ledNotification = mNotificationsByKey.get(owner);
3561 if (ledNotification == null) {
3562 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
3563 mLights.remove(owner);
3567 // Don't flash while we are in a call or screen is on
3568 if (ledNotification == null || mInCall || mScreenOn) {
3569 mNotificationLight.turnOff();
3570 if (mStatusBar != null) {
3571 mStatusBar.notificationLightOff();
3574 final Notification ledno = ledNotification.sbn.getNotification();
3575 int ledARGB = ledno.ledARGB;
3576 int ledOnMS = ledno.ledOnMS;
3577 int ledOffMS = ledno.ledOffMS;
3578 if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0) {
3579 ledARGB = mDefaultNotificationColor;
3580 ledOnMS = mDefaultNotificationLedOn;
3581 ledOffMS = mDefaultNotificationLedOff;
3583 if (mNotificationPulseEnabled) {
3585 mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED,
3588 if (mStatusBar != null) {
3589 // let SystemUI make an independent decision
3590 mStatusBar.notificationLightPulse(ledARGB, ledOnMS, ledOffMS);
3595 // lock on mNotificationList
3596 int indexOfNotificationLocked(String pkg, String tag, int id, int userId)
3598 ArrayList<NotificationRecord> list = mNotificationList;
3599 final int len = list.size();
3600 for (int i=0; i<len; i++) {
3601 NotificationRecord r = list.get(i);
3602 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
3603 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
3610 // lock on mNotificationList
3611 int indexOfNotificationLocked(String key) {
3612 final int N = mNotificationList.size();
3613 for (int i = 0; i < N; i++) {
3614 if (key.equals(mNotificationList.get(i).getKey())) {
3621 private void updateNotificationPulse() {
3622 synchronized (mNotificationList) {
3623 updateLightsLocked();
3627 private static boolean isUidSystem(int uid) {
3628 final int appid = UserHandle.getAppId(uid);
3629 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
3632 private static boolean isCallerSystem() {
3633 return isUidSystem(Binder.getCallingUid());
3636 private static void checkCallerIsSystem() {
3637 if (isCallerSystem()) {
3640 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
3643 private static void checkCallerIsSystemOrSameApp(String pkg) {
3644 if (isCallerSystem()) {
3647 checkCallerIsSameApp(pkg);
3650 private static void checkCallerIsSameApp(String pkg) {
3651 final int uid = Binder.getCallingUid();
3653 ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
3654 pkg, 0, UserHandle.getCallingUserId());
3656 throw new SecurityException("Unknown package " + pkg);
3658 if (!UserHandle.isSameApp(ai.uid, uid)) {
3659 throw new SecurityException("Calling uid " + uid + " gave package"
3660 + pkg + " which is owned by uid " + ai.uid);
3662 } catch (RemoteException re) {
3663 throw new SecurityException("Unknown package " + pkg + "\n" + re);
3667 private static String callStateToString(int state) {
3669 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
3670 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
3671 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
3672 default: return "CALL_STATE_UNKNOWN_" + state;
3676 private void listenForCallState() {
3677 TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
3679 public void onCallStateChanged(int state, String incomingNumber) {
3680 if (mCallState == state) return;
3681 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
3684 }, PhoneStateListener.LISTEN_CALL_STATE);
3688 * Generates a NotificationRankingUpdate from 'sbns', considering only
3689 * notifications visible to the given listener.
3691 * <p>Caller must hold a lock on mNotificationList.</p>
3693 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
3694 final int N = mNotificationList.size();
3695 ArrayList<String> keys = new ArrayList<String>(N);
3696 ArrayList<String> interceptedKeys = new ArrayList<String>(N);
3697 ArrayList<Integer> importance = new ArrayList<>(N);
3698 Bundle overrideGroupKeys = new Bundle();
3699 Bundle visibilityOverrides = new Bundle();
3700 Bundle suppressedVisualEffects = new Bundle();
3701 Bundle explanation = new Bundle();
3702 for (int i = 0; i < N; i++) {
3703 NotificationRecord record = mNotificationList.get(i);
3704 if (!isVisibleToListener(record.sbn, info)) {
3707 final String key = record.sbn.getKey();
3709 importance.add(record.getImportance());
3710 if (record.getImportanceExplanation() != null) {
3711 explanation.putCharSequence(key, record.getImportanceExplanation());
3713 if (record.isIntercepted()) {
3714 interceptedKeys.add(key);
3717 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
3718 if (record.getPackageVisibilityOverride()
3719 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
3720 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
3722 overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
3724 final int M = keys.size();
3725 String[] keysAr = keys.toArray(new String[M]);
3726 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
3727 int[] importanceAr = new int[M];
3728 for (int i = 0; i < M; i++) {
3729 importanceAr[i] = importance.get(i);
3731 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
3732 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys);
3735 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
3736 if (!listener.enabledAndUserMatches(sbn.getUserId())) {
3739 // TODO: remove this for older listeners.
3743 private boolean isPackageSuspendedForUser(String pkg, int uid) {
3744 int userId = UserHandle.getUserId(uid);
3746 return AppGlobals.getPackageManager().isPackageSuspendedForUser(pkg, userId);
3747 } catch (RemoteException re) {
3748 throw new SecurityException("Could not talk to package manager service");
3749 } catch (IllegalArgumentException ex) {
3750 // Package not found.
3755 private class TrimCache {
3756 StatusBarNotification heavy;
3757 StatusBarNotification sbnClone;
3758 StatusBarNotification sbnCloneLight;
3760 TrimCache(StatusBarNotification sbn) {
3764 StatusBarNotification ForListener(ManagedServiceInfo info) {
3765 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
3766 if (sbnCloneLight == null) {
3767 sbnCloneLight = heavy.cloneLight();
3769 return sbnCloneLight;
3771 if (sbnClone == null) {
3772 sbnClone = heavy.clone();
3779 public class NotificationRankers extends ManagedServices {
3781 public NotificationRankers() {
3782 super(getContext(), mHandler, mNotificationList, mUserProfiles);
3786 protected Config getConfig() {
3787 Config c = new Config();
3788 c.caption = "notification ranker service";
3789 c.serviceInterface = NotificationRankerService.SERVICE_INTERFACE;
3790 c.secureSettingName = null;
3791 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_RANKER_SERVICE;
3792 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
3793 c.clientLabel = R.string.notification_ranker_binding_label;
3798 protected IInterface asInterface(IBinder binder) {
3799 return INotificationListener.Stub.asInterface(binder);
3803 protected boolean checkType(IInterface service) {
3804 return service instanceof INotificationListener;
3808 protected void onServiceAdded(ManagedServiceInfo info) {
3809 mListeners.registerGuestService(info);
3813 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
3814 mListeners.unregisterService(removed.service, removed.userid);
3817 public void onNotificationEnqueued(final NotificationRecord r) {
3818 final StatusBarNotification sbn = r.sbn;
3819 TrimCache trimCache = new TrimCache(sbn);
3821 // mServices is the list inside ManagedServices of all the rankers,
3822 // There should be only one, but it's a list, so while we enforce
3823 // singularity elsewhere, we keep it general here, to avoid surprises.
3824 for (final ManagedServiceInfo info : NotificationRankers.this.mServices) {
3825 boolean sbnVisible = isVisibleToListener(sbn, info);
3830 final int importance = r.getImportance();
3831 final boolean fromUser = r.isImportanceFromUser();
3832 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
3833 mHandler.post(new Runnable() {
3836 notifyEnqueued(info, sbnToPost, importance, fromUser);
3842 private void notifyEnqueued(final ManagedServiceInfo info,
3843 final StatusBarNotification sbn, int importance, boolean fromUser) {
3844 final INotificationListener ranker = (INotificationListener) info.service;
3845 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
3847 ranker.onNotificationEnqueued(sbnHolder, importance, fromUser);
3848 } catch (RemoteException ex) {
3849 Log.e(TAG, "unable to notify ranker (enqueued): " + ranker, ex);
3853 public boolean isEnabled() {
3854 return !mServices.isEmpty();
3858 public void onUserSwitched(int user) {
3859 synchronized (mNotificationList) {
3860 int i = mServices.size()-1;
3862 final ManagedServiceInfo info = mServices.get(i);
3863 unregisterService(info.service, info.userid);
3870 public void onPackagesChanged(boolean queryReplace, String[] pkgList) {
3871 if (DEBUG) Slog.d(TAG, "onPackagesChanged queryReplace=" + queryReplace
3872 + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList)));
3873 if (mRankerServicePackageName == null) {
3877 if (pkgList != null && (pkgList.length > 0)) {
3878 for (String pkgName : pkgList) {
3879 if (mRankerServicePackageName.equals(pkgName)) {
3886 protected void registerRanker() {
3887 // Find the updatable ranker and register it.
3888 if (mRankerServicePackageName == null) {
3889 Slog.w(TAG, "could not start ranker service: no package specified!");
3892 Set<ComponentName> rankerComponents = queryPackageForServices(
3893 mRankerServicePackageName, UserHandle.USER_SYSTEM);
3894 Iterator<ComponentName> iterator = rankerComponents.iterator();
3895 if (iterator.hasNext()) {
3896 ComponentName rankerComponent = iterator.next();
3897 if (iterator.hasNext()) {
3898 Slog.e(TAG, "found multiple ranker services:" + rankerComponents);
3900 registerSystemService(rankerComponent, UserHandle.USER_SYSTEM);
3903 Slog.w(TAG, "could not start ranker service: none found");
3908 public class NotificationListeners extends ManagedServices {
3910 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
3912 public NotificationListeners() {
3913 super(getContext(), mHandler, mNotificationList, mUserProfiles);
3917 protected Config getConfig() {
3918 Config c = new Config();
3919 c.caption = "notification listener";
3920 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
3921 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
3922 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
3923 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
3924 c.clientLabel = R.string.notification_listener_binding_label;
3929 protected IInterface asInterface(IBinder binder) {
3930 return INotificationListener.Stub.asInterface(binder);
3934 protected boolean checkType(IInterface service) {
3935 return service instanceof INotificationListener;
3939 public void onServiceAdded(ManagedServiceInfo info) {
3940 final INotificationListener listener = (INotificationListener) info.service;
3941 final NotificationRankingUpdate update;
3942 synchronized (mNotificationList) {
3943 update = makeRankingUpdateLocked(info);
3946 listener.onListenerConnected(update);
3947 } catch (RemoteException e) {
3953 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
3954 if (removeDisabledHints(removed)) {
3955 updateListenerHintsLocked();
3956 updateEffectsSuppressorLocked();
3958 mLightTrimListeners.remove(removed);
3961 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
3962 if (trim == TRIM_LIGHT) {
3963 mLightTrimListeners.add(info);
3965 mLightTrimListeners.remove(info);
3969 public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
3970 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
3974 * asynchronously notify all listeners about a new notification
3977 * Also takes care of removing a notification that has been visible to a listener before,
3978 * but isn't anymore.
3980 public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
3981 // Lazily initialized snapshots of the notification.
3982 TrimCache trimCache = new TrimCache(sbn);
3984 for (final ManagedServiceInfo info : mServices) {
3985 boolean sbnVisible = isVisibleToListener(sbn, info);
3986 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
3987 // This notification hasn't been and still isn't visible -> ignore.
3988 if (!oldSbnVisible && !sbnVisible) {
3991 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
3993 // This notification became invisible -> remove the old one.
3994 if (oldSbnVisible && !sbnVisible) {
3995 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
3996 mHandler.post(new Runnable() {
3999 notifyRemoved(info, oldSbnLightClone, update);
4005 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
4006 mHandler.post(new Runnable() {
4009 notifyPosted(info, sbnToPost, update);
4016 * asynchronously notify all listeners about a removed notification
4018 public void notifyRemovedLocked(StatusBarNotification sbn) {
4019 // make a copy in case changes are made to the underlying Notification object
4020 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
4022 final StatusBarNotification sbnLight = sbn.cloneLight();
4023 for (final ManagedServiceInfo info : mServices) {
4024 if (!isVisibleToListener(sbn, info)) {
4027 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
4028 mHandler.post(new Runnable() {
4031 notifyRemoved(info, sbnLight, update);
4038 * asynchronously notify all listeners about a reordering of notifications
4040 public void notifyRankingUpdateLocked() {
4041 for (final ManagedServiceInfo serviceInfo : mServices) {
4042 if (!serviceInfo.isEnabledForCurrentProfiles()) {
4045 final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
4046 mHandler.post(new Runnable() {
4049 notifyRankingUpdate(serviceInfo, update);
4055 public void notifyListenerHintsChangedLocked(final int hints) {
4056 for (final ManagedServiceInfo serviceInfo : mServices) {
4057 if (!serviceInfo.isEnabledForCurrentProfiles()) {
4060 mHandler.post(new Runnable() {
4063 notifyListenerHintsChanged(serviceInfo, hints);
4069 public void notifyInterruptionFilterChanged(final int interruptionFilter) {
4070 for (final ManagedServiceInfo serviceInfo : mServices) {
4071 if (!serviceInfo.isEnabledForCurrentProfiles()) {
4074 mHandler.post(new Runnable() {
4077 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
4083 private void notifyPosted(final ManagedServiceInfo info,
4084 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
4085 final INotificationListener listener = (INotificationListener)info.service;
4086 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
4088 listener.onNotificationPosted(sbnHolder, rankingUpdate);
4089 } catch (RemoteException ex) {
4090 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
4094 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
4095 NotificationRankingUpdate rankingUpdate) {
4096 if (!info.enabledAndUserMatches(sbn.getUserId())) {
4099 final INotificationListener listener = (INotificationListener) info.service;
4100 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
4102 listener.onNotificationRemoved(sbnHolder, rankingUpdate);
4103 } catch (RemoteException ex) {
4104 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
4108 private void notifyRankingUpdate(ManagedServiceInfo info,
4109 NotificationRankingUpdate rankingUpdate) {
4110 final INotificationListener listener = (INotificationListener) info.service;
4112 listener.onNotificationRankingUpdate(rankingUpdate);
4113 } catch (RemoteException ex) {
4114 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
4118 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
4119 final INotificationListener listener = (INotificationListener) info.service;
4121 listener.onListenerHintsChanged(hints);
4122 } catch (RemoteException ex) {
4123 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
4127 private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
4128 int interruptionFilter) {
4129 final INotificationListener listener = (INotificationListener) info.service;
4131 listener.onInterruptionFilterChanged(interruptionFilter);
4132 } catch (RemoteException ex) {
4133 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
4137 private boolean isListenerPackage(String packageName) {
4138 if (packageName == null) {
4141 // TODO: clean up locking object later
4142 synchronized (mNotificationList) {
4143 for (final ManagedServiceInfo serviceInfo : mServices) {
4144 if (packageName.equals(serviceInfo.component.getPackageName())) {
4153 public static final class DumpFilter {
4154 public boolean filtered = false;
4155 public String pkgFilter;
4158 public boolean stats;
4159 public boolean redact = true;
4161 public static DumpFilter parseFromArguments(String[] args) {
4162 final DumpFilter filter = new DumpFilter();
4163 for (int ai = 0; ai < args.length; ai++) {
4164 final String a = args[ai];
4165 if ("--noredact".equals(a) || "--reveal".equals(a)) {
4166 filter.redact = false;
4167 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
4168 if (ai < args.length-1) {
4170 filter.pkgFilter = args[ai].trim().toLowerCase();
4171 if (filter.pkgFilter.isEmpty()) {
4172 filter.pkgFilter = null;
4174 filter.filtered = true;
4177 } else if ("--zen".equals(a) || "zen".equals(a)) {
4178 filter.filtered = true;
4180 } else if ("--stats".equals(a)) {
4181 filter.stats = true;
4182 if (ai < args.length-1) {
4184 filter.since = Long.valueOf(args[ai]);
4193 public boolean matches(StatusBarNotification sbn) {
4194 if (!filtered) return true;
4195 return zen ? true : sbn != null
4196 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
4199 public boolean matches(ComponentName component) {
4200 if (!filtered) return true;
4201 return zen ? true : component != null && matches(component.getPackageName());
4204 public boolean matches(String pkg) {
4205 if (!filtered) return true;
4206 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
4210 public String toString() {
4211 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
4216 * Wrapper for a StatusBarNotification object that allows transfer across a oneway
4217 * binder without sending large amounts of data over a oneway transaction.
4219 private static final class StatusBarNotificationHolder
4220 extends IStatusBarNotificationHolder.Stub {
4221 private StatusBarNotification mValue;
4223 public StatusBarNotificationHolder(StatusBarNotification value) {
4227 /** Get the held value and clear it. This function should only be called once per holder */
4229 public StatusBarNotification get() {
4230 StatusBarNotification value = mValue;
4236 private final class PolicyAccess {
4237 private static final String SEPARATOR = ":";
4238 private final String[] PERM = {
4239 android.Manifest.permission.ACCESS_NOTIFICATION_POLICY
4242 public boolean isPackageGranted(String pkg) {
4243 return pkg != null && getGrantedPackages().contains(pkg);
4246 public void put(String pkg, boolean granted) {
4247 if (pkg == null) return;
4248 final ArraySet<String> pkgs = getGrantedPackages();
4251 changed = pkgs.add(pkg);
4253 changed = pkgs.remove(pkg);
4255 if (!changed) return;
4256 final String setting = TextUtils.join(SEPARATOR, pkgs);
4257 final int currentUser = ActivityManager.getCurrentUser();
4258 Settings.Secure.putStringForUser(getContext().getContentResolver(),
4259 Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
4262 getContext().sendBroadcastAsUser(new Intent(NotificationManager
4263 .ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
4265 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), new UserHandle(currentUser), null);
4268 public ArraySet<String> getGrantedPackages() {
4269 final ArraySet<String> pkgs = new ArraySet<>();
4271 long identity = Binder.clearCallingIdentity();
4273 final String setting = Settings.Secure.getStringForUser(
4274 getContext().getContentResolver(),
4275 Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
4276 ActivityManager.getCurrentUser());
4277 if (setting != null) {
4278 final String[] tokens = setting.split(SEPARATOR);
4279 for (int i = 0; i < tokens.length; i++) {
4280 String token = tokens[i];
4281 if (token != null) {
4282 token = token.trim();
4284 if (TextUtils.isEmpty(token)) {
4291 Binder.restoreCallingIdentity(identity);
4296 public String[] getRequestingPackages() throws RemoteException {
4297 final ParceledListSlice list = AppGlobals.getPackageManager()
4298 .getPackagesHoldingPermissions(PERM, 0 /*flags*/,
4299 ActivityManager.getCurrentUser());
4300 final List<PackageInfo> pkgs = list.getList();
4301 if (pkgs == null || pkgs.isEmpty()) return new String[0];
4302 final int N = pkgs.size();
4303 final String[] rt = new String[N];
4304 for (int i = 0; i < N; i++) {
4305 rt[i] = pkgs.get(i).packageName;