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;
43 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
45 import android.Manifest;
46 import android.annotation.Nullable;
47 import android.app.ActivityManager;
48 import android.app.ActivityManagerNative;
49 import android.app.AppGlobals;
50 import android.app.AppOpsManager;
51 import android.app.AutomaticZenRule;
52 import android.app.IActivityManager;
53 import android.app.INotificationManager;
54 import android.app.ITransientNotification;
55 import android.app.Notification;
56 import android.app.NotificationManager;
57 import android.app.NotificationManager.Policy;
58 import android.app.PendingIntent;
59 import android.app.StatusBarManager;
60 import android.app.backup.BackupManager;
61 import android.app.usage.UsageEvents;
62 import android.app.usage.UsageStatsManagerInternal;
63 import android.content.BroadcastReceiver;
64 import android.content.ComponentName;
65 import android.content.ContentResolver;
66 import android.content.Context;
67 import android.content.Intent;
68 import android.content.IntentFilter;
69 import android.content.pm.ApplicationInfo;
70 import android.content.pm.IPackageManager;
71 import android.content.pm.PackageInfo;
72 import android.content.pm.PackageManager;
73 import android.content.pm.PackageManager.NameNotFoundException;
74 import android.content.pm.ParceledListSlice;
75 import android.content.pm.UserInfo;
76 import android.content.res.Resources;
77 import android.database.ContentObserver;
78 import android.media.AudioAttributes;
79 import android.media.AudioManager;
80 import android.media.AudioManagerInternal;
81 import android.media.AudioSystem;
82 import android.media.IRingtonePlayer;
83 import android.net.Uri;
84 import android.os.Binder;
85 import android.os.Bundle;
86 import android.os.Environment;
87 import android.os.Handler;
88 import android.os.HandlerThread;
89 import android.os.IBinder;
90 import android.os.IInterface;
91 import android.os.Looper;
92 import android.os.Message;
93 import android.os.Process;
94 import android.os.RemoteException;
95 import android.os.SystemClock;
96 import android.os.SystemProperties;
97 import android.os.UserHandle;
98 import android.os.UserManager;
99 import android.os.Vibrator;
100 import android.provider.Settings;
101 import android.service.notification.Adjustment;
102 import android.service.notification.Condition;
103 import android.service.notification.IConditionProvider;
104 import android.service.notification.INotificationListener;
105 import android.service.notification.IStatusBarNotificationHolder;
106 import android.service.notification.NotificationRankerService;
107 import android.service.notification.NotificationListenerService;
108 import android.service.notification.NotificationRankingUpdate;
109 import android.service.notification.StatusBarNotification;
110 import android.service.notification.ZenModeConfig;
111 import android.telephony.PhoneStateListener;
112 import android.telephony.TelephonyManager;
113 import android.text.TextUtils;
114 import android.util.ArrayMap;
115 import android.util.ArraySet;
116 import android.util.AtomicFile;
117 import android.util.Log;
118 import android.util.Slog;
119 import android.util.SparseArray;
120 import android.util.Xml;
121 import android.view.accessibility.AccessibilityEvent;
122 import android.view.accessibility.AccessibilityManager;
123 import android.widget.Toast;
125 import com.android.internal.R;
126 import com.android.internal.annotations.VisibleForTesting;
127 import com.android.internal.statusbar.NotificationVisibility;
128 import com.android.internal.util.FastXmlSerializer;
129 import com.android.internal.util.Preconditions;
130 import com.android.server.EventLogTags;
131 import com.android.server.LocalServices;
132 import com.android.server.SystemService;
133 import com.android.server.lights.Light;
134 import com.android.server.lights.LightsManager;
135 import com.android.server.notification.ManagedServices.ManagedServiceInfo;
136 import com.android.server.statusbar.StatusBarManagerInternal;
137 import com.android.server.vr.VrManagerInternal;
138 import com.android.server.notification.ManagedServices.UserProfiles;
140 import libcore.io.IoUtils;
142 import org.json.JSONException;
143 import org.json.JSONObject;
144 import org.xmlpull.v1.XmlPullParser;
145 import org.xmlpull.v1.XmlPullParserException;
146 import org.xmlpull.v1.XmlSerializer;
148 import java.io.ByteArrayInputStream;
149 import java.io.ByteArrayOutputStream;
151 import java.io.FileDescriptor;
152 import java.io.FileInputStream;
153 import java.io.FileNotFoundException;
154 import java.io.FileOutputStream;
155 import java.io.IOException;
156 import java.io.InputStream;
157 import java.io.OutputStream;
158 import java.io.PrintWriter;
159 import java.nio.charset.StandardCharsets;
160 import java.util.ArrayDeque;
161 import java.util.ArrayList;
162 import java.util.Arrays;
163 import java.util.Iterator;
164 import java.util.List;
165 import java.util.Map;
166 import java.util.Map.Entry;
167 import java.util.Set;
168 import java.util.concurrent.TimeUnit;
171 public class NotificationManagerService extends SystemService {
172 static final String TAG = "NotificationService";
173 static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
174 public static final boolean ENABLE_CHILD_NOTIFICATIONS
175 = SystemProperties.getBoolean("debug.child_notifs", true);
177 static final int MAX_PACKAGE_NOTIFICATIONS = 50;
178 static final float MAX_PACKAGE_ENQUEUE_RATE = 50f;
181 static final int MESSAGE_TIMEOUT = 2;
182 static final int MESSAGE_SAVE_POLICY_FILE = 3;
183 static final int MESSAGE_SEND_RANKING_UPDATE = 4;
184 static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
185 static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
187 // ranking thread messages
188 private static final int MESSAGE_RECONSIDER_RANKING = 1000;
189 private static final int MESSAGE_RANKING_SORT = 1001;
191 static final int LONG_DELAY = 3500; // 3.5 seconds
192 static final int SHORT_DELAY = 2000; // 2 seconds
194 static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
196 static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
198 static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
200 static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true;
201 static final boolean ENABLE_BLOCKED_TOASTS = true;
203 // When #matchesCallFilter is called from the ringer, wait at most
204 // 3s to resolve the contacts. This timeout is required since
205 // ContactsProvider might take a long time to start up.
207 // Return STARRED_CONTACT when the timeout is hit in order to avoid
208 // missed calls in ZEN mode "Important".
209 static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
210 static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
211 ValidateNotificationPeople.STARRED_CONTACT;
213 /** notification_enqueue status value for a newly enqueued notification. */
214 private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
216 /** notification_enqueue status value for an existing notification. */
217 private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
219 /** notification_enqueue status value for an ignored notification. */
220 private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
221 private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
222 private String mRankerServicePackageName;
224 private IActivityManager mAm;
225 AudioManager mAudioManager;
226 AudioManagerInternal mAudioManagerInternal;
227 @Nullable StatusBarManagerInternal mStatusBar;
229 private VrManagerInternal mVrManagerInternal;
231 final IBinder mForegroundToken = new Binder();
232 private Handler mHandler;
233 private final HandlerThread mRankingThread = new HandlerThread("ranker",
234 Process.THREAD_PRIORITY_BACKGROUND);
236 private Light mNotificationLight;
237 Light mAttentionLight;
238 private int mDefaultNotificationColor;
239 private int mDefaultNotificationLedOn;
241 private int mDefaultNotificationLedOff;
242 private long[] mDefaultVibrationPattern;
244 private long[] mFallbackVibrationPattern;
245 private boolean mUseAttentionLight;
246 boolean mSystemReady;
248 private boolean mDisableNotificationEffects;
249 private int mCallState;
250 private String mSoundNotificationKey;
251 private String mVibrateNotificationKey;
253 private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
254 new SparseArray<ArraySet<ManagedServiceInfo>>();
255 private List<ComponentName> mEffectsSuppressors = new ArrayList<ComponentName>();
256 private int mListenerHints; // right now, all hints are global
257 private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
259 // for enabling and disabling notification pulse behavior
260 private boolean mScreenOn = true;
261 private boolean mInCall = false;
262 private boolean mNotificationPulseEnabled;
264 // used as a mutex for access to all active notifications & listeners
265 final ArrayList<NotificationRecord> mNotificationList =
266 new ArrayList<NotificationRecord>();
267 final ArrayMap<String, NotificationRecord> mNotificationsByKey =
268 new ArrayMap<String, NotificationRecord>();
269 final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
270 final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();
271 final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
272 final PolicyAccess mPolicyAccess = new PolicyAccess();
274 // The last key in this list owns the hardware.
275 ArrayList<String> mLights = new ArrayList<>();
277 private AppOpsManager mAppOps;
278 private UsageStatsManagerInternal mAppUsageStats;
280 private Archive mArchive;
282 // Persistent storage for notification policy
283 private AtomicFile mPolicyFile;
285 private static final int DB_VERSION = 1;
287 private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
288 private static final String ATTR_VERSION = "version";
290 private RankingHelper mRankingHelper;
292 private final UserProfiles mUserProfiles = new UserProfiles();
293 private NotificationListeners mListeners;
294 private NotificationRankers mRankerServices;
295 private ConditionProviders mConditionProviders;
296 private NotificationUsageStats mUsageStats;
298 private static final int MY_UID = Process.myUid();
299 private static final int MY_PID = Process.myPid();
300 private RankingHandler mRankingHandler;
301 private long mLastOverRateLogTime;
303 private static class Archive {
304 final int mBufferSize;
305 final ArrayDeque<StatusBarNotification> mBuffer;
307 public Archive(int size) {
309 mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
312 public String toString() {
313 final StringBuilder sb = new StringBuilder();
314 final int N = mBuffer.size();
315 sb.append("Archive (");
317 sb.append(" notification");
318 sb.append((N==1)?")":"s)");
319 return sb.toString();
322 public void record(StatusBarNotification nr) {
323 if (mBuffer.size() == mBufferSize) {
324 mBuffer.removeFirst();
327 // We don't want to store the heavy bits of the notification in the archive,
328 // but other clients in the system process might be using the object, so we
329 // store a (lightened) copy.
330 mBuffer.addLast(nr.cloneLight());
333 public Iterator<StatusBarNotification> descendingIterator() {
334 return mBuffer.descendingIterator();
337 public StatusBarNotification[] getArray(int count) {
338 if (count == 0) count = mBufferSize;
339 final StatusBarNotification[] a
340 = new StatusBarNotification[Math.min(count, mBuffer.size())];
341 Iterator<StatusBarNotification> iter = descendingIterator();
343 while (iter.hasNext() && i < count) {
344 a[i++] = iter.next();
351 private void readPolicyXml(InputStream stream, boolean forRestore)
352 throws XmlPullParserException, NumberFormatException, IOException {
353 final XmlPullParser parser = Xml.newPullParser();
354 parser.setInput(stream, StandardCharsets.UTF_8.name());
356 while (parser.next() != END_DOCUMENT) {
357 mZenModeHelper.readXml(parser, forRestore);
358 mRankingHelper.readXml(parser, forRestore);
362 private void loadPolicyFile() {
363 if (DBG) Slog.d(TAG, "loadPolicyFile");
364 synchronized(mPolicyFile) {
366 FileInputStream infile = null;
368 infile = mPolicyFile.openRead();
369 readPolicyXml(infile, false /*forRestore*/);
370 } catch (FileNotFoundException e) {
372 } catch (IOException e) {
373 Log.wtf(TAG, "Unable to read notification policy", e);
374 } catch (NumberFormatException e) {
375 Log.wtf(TAG, "Unable to parse notification policy", e);
376 } catch (XmlPullParserException e) {
377 Log.wtf(TAG, "Unable to parse notification policy", e);
379 IoUtils.closeQuietly(infile);
384 public void savePolicyFile() {
385 mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
386 mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
389 private void handleSavePolicyFile() {
390 if (DBG) Slog.d(TAG, "handleSavePolicyFile");
391 synchronized (mPolicyFile) {
392 final FileOutputStream stream;
394 stream = mPolicyFile.startWrite();
395 } catch (IOException e) {
396 Slog.w(TAG, "Failed to save policy file", e);
401 writePolicyXml(stream, false /*forBackup*/);
402 mPolicyFile.finishWrite(stream);
403 } catch (IOException e) {
404 Slog.w(TAG, "Failed to save policy file, restoring backup", e);
405 mPolicyFile.failWrite(stream);
408 BackupManager.dataChanged(getContext().getPackageName());
411 private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
412 final XmlSerializer out = new FastXmlSerializer();
413 out.setOutput(stream, StandardCharsets.UTF_8.name());
414 out.startDocument(null, true);
415 out.startTag(null, TAG_NOTIFICATION_POLICY);
416 out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
417 mZenModeHelper.writeXml(out, forBackup);
418 mRankingHelper.writeXml(out, forBackup);
419 out.endTag(null, TAG_NOTIFICATION_POLICY);
423 /** Use this when you actually want to post a notification or toast.
425 * Unchecked. Not exposed via Binder, but can be called in the course of enqueue*().
427 private boolean noteNotificationOp(String pkg, int uid) {
428 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
429 != AppOpsManager.MODE_ALLOWED) {
430 Slog.v(TAG, "notifications are disabled by AppOps for " + pkg);
436 /** Use this to check if a package can post a notification or toast. */
437 private boolean checkNotificationOp(String pkg, int uid) {
438 return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
439 == AppOpsManager.MODE_ALLOWED && !isPackageSuspendedForUser(pkg, uid);
442 private static final class ToastRecord
446 final ITransientNotification callback;
449 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration)
453 this.callback = callback;
454 this.duration = duration;
457 void update(int duration) {
458 this.duration = duration;
461 void dump(PrintWriter pw, String prefix, DumpFilter filter) {
462 if (filter != null && !filter.matches(pkg)) return;
463 pw.println(prefix + this);
467 public final String toString()
469 return "ToastRecord{"
470 + Integer.toHexString(System.identityHashCode(this))
472 + " callback=" + callback
473 + " duration=" + duration;
477 private final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
480 public void onSetDisabled(int status) {
481 synchronized (mNotificationList) {
482 mDisableNotificationEffects =
483 (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
484 if (disableNotificationEffects(null) != null) {
485 // cancel whatever's going on
486 long identity = Binder.clearCallingIdentity();
488 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
489 if (player != null) {
492 } catch (RemoteException e) {
494 Binder.restoreCallingIdentity(identity);
497 identity = Binder.clearCallingIdentity();
501 Binder.restoreCallingIdentity(identity);
508 public void onClearAll(int callingUid, int callingPid, int userId) {
509 synchronized (mNotificationList) {
510 cancelAllLocked(callingUid, callingPid, userId, REASON_DELEGATE_CANCEL_ALL, null,
511 /*includeCurrentProfiles*/ true);
516 public void onNotificationClick(int callingUid, int callingPid, String key) {
517 synchronized (mNotificationList) {
518 NotificationRecord r = mNotificationsByKey.get(key);
520 Log.w(TAG, "No notification with key: " + key);
523 final long now = System.currentTimeMillis();
524 EventLogTags.writeNotificationClicked(key,
525 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
527 StatusBarNotification sbn = r.sbn;
528 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
529 sbn.getId(), Notification.FLAG_AUTO_CANCEL,
530 Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
531 REASON_DELEGATE_CLICK, null);
536 public void onNotificationActionClick(int callingUid, int callingPid, String key,
538 synchronized (mNotificationList) {
539 NotificationRecord r = mNotificationsByKey.get(key);
541 Log.w(TAG, "No notification with key: " + key);
544 final long now = System.currentTimeMillis();
545 EventLogTags.writeNotificationActionClicked(key, actionIndex,
546 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
547 // TODO: Log action click via UsageStats.
552 public void onNotificationClear(int callingUid, int callingPid,
553 String pkg, String tag, int id, int userId) {
554 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
555 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
556 true, userId, REASON_DELEGATE_CANCEL, null);
560 public void onPanelRevealed(boolean clearEffects, int items) {
561 EventLogTags.writeNotificationPanelRevealed(items);
568 public void onPanelHidden() {
569 EventLogTags.writeNotificationPanelHidden();
573 public void clearEffects() {
574 synchronized (mNotificationList) {
575 if (DBG) Slog.d(TAG, "clearEffects");
577 clearVibrateLocked();
583 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
584 int uid, int initialPid, String message, int userId) {
585 Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
586 + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
587 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
588 REASON_DELEGATE_ERROR, null);
589 long ident = Binder.clearCallingIdentity();
591 ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg,
592 "Bad notification posted from package " + pkg
594 } catch (RemoteException e) {
596 Binder.restoreCallingIdentity(ident);
600 public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
601 NotificationVisibility[] noLongerVisibleKeys) {
602 synchronized (mNotificationList) {
603 for (NotificationVisibility nv : newlyVisibleKeys) {
604 NotificationRecord r = mNotificationsByKey.get(nv.key);
605 if (r == null) continue;
606 r.setVisibility(true, nv.rank);
609 // Note that we might receive this event after notifications
610 // have already left the system, e.g. after dismissing from the
611 // shade. Hence not finding notifications in
612 // mNotificationsByKey is not an exceptional condition.
613 for (NotificationVisibility nv : noLongerVisibleKeys) {
614 NotificationRecord r = mNotificationsByKey.get(nv.key);
615 if (r == null) continue;
616 r.setVisibility(false, nv.rank);
623 public void onNotificationExpansionChanged(String key,
624 boolean userAction, boolean expanded) {
625 synchronized (mNotificationList) {
626 NotificationRecord r = mNotificationsByKey.get(key);
628 r.stats.onExpansionChanged(userAction, expanded);
629 final long now = System.currentTimeMillis();
630 EventLogTags.writeNotificationExpansion(key,
631 userAction ? 1 : 0, expanded ? 1 : 0,
632 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
638 private void clearSoundLocked() {
639 mSoundNotificationKey = null;
640 long identity = Binder.clearCallingIdentity();
642 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
643 if (player != null) {
646 } catch (RemoteException e) {
648 Binder.restoreCallingIdentity(identity);
652 private void clearVibrateLocked() {
653 mVibrateNotificationKey = null;
654 long identity = Binder.clearCallingIdentity();
658 Binder.restoreCallingIdentity(identity);
662 private void clearLightsLocked() {
665 updateLightsLocked();
668 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
670 public void onReceive(Context context, Intent intent) {
671 String action = intent.getAction();
672 if (action == null) {
676 boolean queryRestart = false;
677 boolean queryRemove = false;
678 boolean packageChanged = false;
679 boolean cancelNotifications = true;
680 int reason = REASON_PACKAGE_CHANGED;
682 if (action.equals(Intent.ACTION_PACKAGE_ADDED)
683 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
684 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
685 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
686 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
687 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
688 || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
689 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
690 UserHandle.USER_ALL);
691 String pkgList[] = null;
692 boolean queryReplace = queryRemove &&
693 intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
694 if (DBG) Slog.i(TAG, "action=" + action + " queryReplace=" + queryReplace);
695 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
696 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
697 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
698 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
699 reason = REASON_PACKAGE_SUSPENDED;
700 } else if (queryRestart) {
701 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
703 Uri uri = intent.getData();
707 String pkgName = uri.getSchemeSpecificPart();
708 if (pkgName == null) {
711 if (packageChanged) {
712 // We cancel notifications for packages which have just been disabled
714 final IPackageManager pm = AppGlobals.getPackageManager();
715 final int enabled = pm.getApplicationEnabledSetting(pkgName,
716 changeUserId != UserHandle.USER_ALL ? changeUserId :
717 UserHandle.USER_SYSTEM);
718 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
719 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
720 cancelNotifications = false;
722 } catch (IllegalArgumentException e) {
723 // Package doesn't exist; probably racing with uninstall.
724 // cancelNotifications is already true, so nothing to do here.
726 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
728 } catch (RemoteException e) {
729 // Failed to talk to PackageManagerService Should never happen!
732 pkgList = new String[]{pkgName};
735 if (pkgList != null && (pkgList.length > 0)) {
736 for (String pkgName : pkgList) {
737 if (cancelNotifications) {
738 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart,
739 changeUserId, reason, null);
743 mListeners.onPackagesChanged(queryReplace, pkgList);
744 mRankerServices.onPackagesChanged(queryReplace, pkgList);
745 mConditionProviders.onPackagesChanged(queryReplace, pkgList);
746 mRankingHelper.onPackagesChanged(queryReplace, pkgList);
751 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
753 public void onReceive(Context context, Intent intent) {
754 String action = intent.getAction();
756 if (action.equals(Intent.ACTION_SCREEN_ON)) {
757 // Keep track of screen on/off state, but do not turn off the notification light
758 // until user passes through the lock screen or views the notification.
760 updateNotificationPulse();
761 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
763 updateNotificationPulse();
764 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
765 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
766 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
767 updateNotificationPulse();
768 } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
769 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
770 if (userHandle >= 0) {
771 cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
772 REASON_USER_STOPPED, null);
774 } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
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_PROFILE_TURNED_OFF, null);
780 } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
781 // turn off LED when user passes through lock screen
782 mNotificationLight.turnOff();
783 if (mStatusBar != null) {
784 mStatusBar.notificationLightOff();
786 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
787 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
788 // reload per-user settings
789 mSettingsObserver.update(null);
790 mUserProfiles.updateCache(context);
791 // Refresh managed services
792 mConditionProviders.onUserSwitched(user);
793 mListeners.onUserSwitched(user);
794 mRankerServices.onUserSwitched(user);
795 mZenModeHelper.onUserSwitched(user);
796 } else if (action.equals(Intent.ACTION_USER_ADDED)) {
797 mUserProfiles.updateCache(context);
798 } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
799 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
800 mZenModeHelper.onUserRemoved(user);
801 } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
802 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
803 mConditionProviders.onUserUnlocked(user);
804 mListeners.onUserUnlocked(user);
805 mRankerServices.onUserUnlocked(user);
806 mZenModeHelper.onUserUnlocked(user);
811 private final class SettingsObserver extends ContentObserver {
812 private final Uri NOTIFICATION_LIGHT_PULSE_URI
813 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
815 SettingsObserver(Handler handler) {
820 ContentResolver resolver = getContext().getContentResolver();
821 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
822 false, this, UserHandle.USER_ALL);
826 @Override public void onChange(boolean selfChange, Uri uri) {
830 public void update(Uri uri) {
831 ContentResolver resolver = getContext().getContentResolver();
832 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
833 boolean pulseEnabled = Settings.System.getInt(resolver,
834 Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
835 if (mNotificationPulseEnabled != pulseEnabled) {
836 mNotificationPulseEnabled = pulseEnabled;
837 updateNotificationPulse();
843 private SettingsObserver mSettingsObserver;
844 private ZenModeHelper mZenModeHelper;
846 private final Runnable mBuzzBeepBlinked = new Runnable() {
849 if (mStatusBar != null) {
850 mStatusBar.buzzBeepBlinked();
855 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
856 int[] ar = r.getIntArray(resid);
860 final int len = ar.length > maxlen ? maxlen : ar.length;
861 long[] out = new long[len];
862 for (int i=0; i<len; i++) {
868 public NotificationManagerService(Context context) {
873 void setAudioManager(AudioManager audioMananger) {
874 mAudioManager = audioMananger;
878 void setVibrator(Vibrator vibrator) {
879 mVibrator = vibrator;
883 void setSystemReady(boolean systemReady) {
884 mSystemReady = systemReady;
888 void setHandler(Handler handler) {
893 public void onStart() {
894 Resources resources = getContext().getResources();
896 mAm = ActivityManagerNative.getDefault();
897 mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
898 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
899 mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
901 // This is the package that contains the AOSP framework update.
902 mRankerServicePackageName = getContext().getPackageManager()
903 .getServicesSystemSharedLibraryPackageName();
905 mHandler = new WorkerHandler();
906 mRankingThread.start();
907 String[] extractorNames;
909 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
910 } catch (Resources.NotFoundException e) {
911 extractorNames = new String[0];
913 mUsageStats = new NotificationUsageStats(getContext());
914 mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
915 mRankingHelper = new RankingHelper(getContext(),
919 mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles);
920 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
921 mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
923 public void onConfigChanged() {
928 void onZenModeChanged() {
929 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
930 getContext().sendBroadcastAsUser(
931 new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
932 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
933 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
934 synchronized(mNotificationList) {
935 updateInterruptionFilterLocked();
940 void onPolicyChanged() {
941 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
944 final File systemDir = new File(Environment.getDataDirectory(), "system");
945 mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
949 // This is a MangedServices object that keeps track of the listeners.
950 mListeners = new NotificationListeners();
952 // This is a MangedServices object that keeps track of the ranker.
953 mRankerServices = new NotificationRankers();
954 // Find the updatable ranker and register it.
955 mRankerServices.registerRanker();
957 mStatusBar = getLocalService(StatusBarManagerInternal.class);
958 if (mStatusBar != null) {
959 mStatusBar.setNotificationDelegate(mNotificationDelegate);
962 final LightsManager lights = getLocalService(LightsManager.class);
963 mNotificationLight = lights.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
964 mAttentionLight = lights.getLight(LightsManager.LIGHT_ID_ATTENTION);
966 mDefaultNotificationColor = resources.getColor(
967 R.color.config_defaultNotificationColor);
968 mDefaultNotificationLedOn = resources.getInteger(
969 R.integer.config_defaultNotificationLedOn);
970 mDefaultNotificationLedOff = resources.getInteger(
971 R.integer.config_defaultNotificationLedOff);
973 mDefaultVibrationPattern = getLongArray(resources,
974 R.array.config_defaultNotificationVibePattern,
975 VIBRATE_PATTERN_MAXLEN,
976 DEFAULT_VIBRATE_PATTERN);
978 mFallbackVibrationPattern = getLongArray(resources,
979 R.array.config_notificationFallbackVibePattern,
980 VIBRATE_PATTERN_MAXLEN,
981 DEFAULT_VIBRATE_PATTERN);
983 mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
985 // Don't start allowing notifications until the setup wizard has run once.
986 // After that, including subsequent boots, init with notifications turned on.
987 // This works on the first boot because the setup wizard will toggle this
988 // flag at least once and we'll go back to 0 after that.
989 if (0 == Settings.Global.getInt(getContext().getContentResolver(),
990 Settings.Global.DEVICE_PROVISIONED, 0)) {
991 mDisableNotificationEffects = true;
993 mZenModeHelper.initZenMode();
994 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
996 mUserProfiles.updateCache(getContext());
997 listenForCallState();
999 // register for various Intents
1000 IntentFilter filter = new IntentFilter();
1001 filter.addAction(Intent.ACTION_SCREEN_ON);
1002 filter.addAction(Intent.ACTION_SCREEN_OFF);
1003 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
1004 filter.addAction(Intent.ACTION_USER_PRESENT);
1005 filter.addAction(Intent.ACTION_USER_STOPPED);
1006 filter.addAction(Intent.ACTION_USER_SWITCHED);
1007 filter.addAction(Intent.ACTION_USER_ADDED);
1008 filter.addAction(Intent.ACTION_USER_REMOVED);
1009 filter.addAction(Intent.ACTION_USER_UNLOCKED);
1010 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
1011 getContext().registerReceiver(mIntentReceiver, filter);
1013 IntentFilter pkgFilter = new IntentFilter();
1014 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
1015 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1016 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
1017 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1018 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1019 pkgFilter.addDataScheme("package");
1020 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1023 IntentFilter suspendedPkgFilter = new IntentFilter();
1024 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
1025 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1026 suspendedPkgFilter, null, null);
1028 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
1029 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1032 mSettingsObserver = new SettingsObserver(mHandler);
1034 mArchive = new Archive(resources.getInteger(
1035 R.integer.config_notificationServiceArchiveSize));
1037 publishBinderService(Context.NOTIFICATION_SERVICE, mService);
1038 publishLocalService(NotificationManagerInternal.class, mInternalService);
1041 private void sendRegisteredOnlyBroadcast(String action) {
1042 getContext().sendBroadcastAsUser(new Intent(action)
1043 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
1047 * Make sure the XML config and the the AppOps system agree about blocks.
1049 private void syncBlockDb() {
1052 // sync bans from ranker into app opps
1053 Map<Integer, String> packageBans = mRankingHelper.getPackageBans();
1054 for(Entry<Integer, String> ban : packageBans.entrySet()) {
1055 final int uid = ban.getKey();
1056 final String packageName = ban.getValue();
1057 setNotificationsEnabledForPackageImpl(packageName, uid, false);
1060 // sync bans from app opps into ranker
1061 packageBans.clear();
1062 for (UserInfo user : UserManager.get(getContext()).getUsers()) {
1063 final int userId = user.getUserHandle().getIdentifier();
1064 final PackageManager packageManager = getContext().getPackageManager();
1065 List<PackageInfo> packages = packageManager.getInstalledPackagesAsUser(0, userId);
1066 final int packageCount = packages.size();
1067 for (int p = 0; p < packageCount; p++) {
1068 final String packageName = packages.get(p).packageName;
1070 final int uid = packageManager.getPackageUidAsUser(packageName, userId);
1071 if (!checkNotificationOp(packageName, uid)) {
1072 packageBans.put(uid, packageName);
1074 } catch (NameNotFoundException e) {
1079 for (Entry<Integer, String> ban : packageBans.entrySet()) {
1080 mRankingHelper.setImportance(ban.getValue(), ban.getKey(), IMPORTANCE_NONE);
1087 public void onBootPhase(int phase) {
1088 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1089 // no beeping until we're basically done booting
1090 mSystemReady = true;
1092 // Grab our optional AudioService
1093 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
1094 mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
1095 mVrManagerInternal = getLocalService(VrManagerInternal.class);
1096 mZenModeHelper.onSystemReady();
1097 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1098 // This observer will force an update when observe is called, causing us to
1099 // bind to listener services.
1100 mSettingsObserver.observe();
1101 mListeners.onBootPhaseAppsCanStart();
1102 mRankerServices.onBootPhaseAppsCanStart();
1103 mConditionProviders.onBootPhaseAppsCanStart();
1107 void setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled) {
1108 Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
1110 mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
1111 enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
1113 // Now, cancel any outstanding notifications that are part of a just-disabled app
1114 if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
1115 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true, UserHandle.getUserId(uid),
1116 REASON_PACKAGE_BANNED, null);
1120 private void updateListenerHintsLocked() {
1121 final int hints = calculateHints();
1122 if (hints == mListenerHints) return;
1123 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
1124 mListenerHints = hints;
1125 scheduleListenerHintsChanged(hints);
1128 private void updateEffectsSuppressorLocked() {
1129 final long updatedSuppressedEffects = calculateSuppressedEffects();
1130 if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1131 final List<ComponentName> suppressors = getSuppressors();
1132 ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1133 mEffectsSuppressors = suppressors;
1134 mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
1135 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
1138 private ArrayList<ComponentName> getSuppressors() {
1139 ArrayList<ComponentName> names = new ArrayList<ComponentName>();
1140 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1141 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1143 for (ManagedServiceInfo info : serviceInfoList) {
1144 names.add(info.component);
1151 private boolean removeDisabledHints(ManagedServiceInfo info) {
1152 return removeDisabledHints(info, 0);
1155 private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
1156 boolean removed = false;
1158 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1159 final int hint = mListenersDisablingEffects.keyAt(i);
1160 final ArraySet<ManagedServiceInfo> listeners =
1161 mListenersDisablingEffects.valueAt(i);
1163 if (hints == 0 || (hint & hints) == hint) {
1164 removed = removed || listeners.remove(info);
1171 private void addDisabledHints(ManagedServiceInfo info, int hints) {
1172 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1173 addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
1176 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1177 addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1180 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1181 addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
1185 private void addDisabledHint(ManagedServiceInfo info, int hint) {
1186 if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
1187 mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
1190 ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
1191 hintListeners.add(info);
1194 private int calculateHints() {
1196 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1197 int hint = mListenersDisablingEffects.keyAt(i);
1198 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1200 if (!serviceInfoList.isEmpty()) {
1208 private long calculateSuppressedEffects() {
1209 int hints = calculateHints();
1210 long suppressedEffects = 0;
1212 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1213 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
1216 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1217 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
1220 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1221 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
1224 return suppressedEffects;
1227 private void updateInterruptionFilterLocked() {
1228 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1229 if (interruptionFilter == mInterruptionFilter) return;
1230 mInterruptionFilter = interruptionFilter;
1231 scheduleInterruptionFilterChanged(interruptionFilter);
1234 private final IBinder mService = new INotificationManager.Stub() {
1236 // ============================================================================
1239 public void enqueueToast(String pkg, ITransientNotification callback, int duration)
1242 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1243 + " duration=" + duration);
1246 if (pkg == null || callback == null) {
1247 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1251 final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg));
1252 final boolean isPackageSuspended =
1253 isPackageSuspendedForUser(pkg, Binder.getCallingUid());
1255 if (ENABLE_BLOCKED_TOASTS && (!noteNotificationOp(pkg, Binder.getCallingUid())
1256 || isPackageSuspended)) {
1257 if (!isSystemToast) {
1258 Slog.e(TAG, "Suppressing toast from package " + pkg
1259 + (isPackageSuspended
1260 ? " due to package suspended by administrator."
1261 : " by user request."));
1266 synchronized (mToastQueue) {
1267 int callingPid = Binder.getCallingPid();
1268 long callingId = Binder.clearCallingIdentity();
1271 int index = indexOfToastLocked(pkg, callback);
1272 // If it's already in the queue, we update it in place, we don't
1273 // move it to the end of the queue.
1275 record = mToastQueue.get(index);
1276 record.update(duration);
1278 // Limit the number of toasts that any given package except the android
1279 // package can enqueue. Prevents DOS attacks and deals with leaks.
1280 if (!isSystemToast) {
1282 final int N = mToastQueue.size();
1283 for (int i=0; i<N; i++) {
1284 final ToastRecord r = mToastQueue.get(i);
1285 if (r.pkg.equals(pkg)) {
1287 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
1288 Slog.e(TAG, "Package has already posted " + count
1289 + " toasts. Not showing more. Package=" + pkg);
1296 record = new ToastRecord(callingPid, pkg, callback, duration);
1297 mToastQueue.add(record);
1298 index = mToastQueue.size() - 1;
1299 keepProcessAliveLocked(callingPid);
1301 // If it's at index 0, it's the current toast. It doesn't matter if it's
1302 // new or just been updated. Call back and tell it to show itself.
1303 // If the callback fails, this will remove it from the list, so don't
1304 // assume that it's valid after this.
1306 showNextToastLocked();
1309 Binder.restoreCallingIdentity(callingId);
1315 public void cancelToast(String pkg, ITransientNotification callback) {
1316 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
1318 if (pkg == null || callback == null) {
1319 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
1323 synchronized (mToastQueue) {
1324 long callingId = Binder.clearCallingIdentity();
1326 int index = indexOfToastLocked(pkg, callback);
1328 cancelToastLocked(index);
1330 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
1331 + " callback=" + callback);
1334 Binder.restoreCallingIdentity(callingId);
1340 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
1341 Notification notification, int[] idOut, int userId) throws RemoteException {
1342 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
1343 Binder.getCallingPid(), tag, id, notification, idOut, userId);
1347 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
1348 checkCallerIsSystemOrSameApp(pkg);
1349 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1350 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
1351 // Don't allow client applications to cancel foreground service notis or autobundled
1353 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
1354 (Binder.getCallingUid() == Process.SYSTEM_UID
1355 ? 0 : Notification.FLAG_FOREGROUND_SERVICE)
1356 | (Binder.getCallingUid() == Process.SYSTEM_UID
1357 ? 0 : Notification.FLAG_AUTOGROUP_SUMMARY), false, userId,
1358 REASON_APP_CANCEL, null);
1362 public void cancelAllNotifications(String pkg, int userId) {
1363 checkCallerIsSystemOrSameApp(pkg);
1365 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1366 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
1368 // Calling from user space, don't allow the canceling of actively
1369 // running foreground services.
1370 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
1371 pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
1372 REASON_APP_CANCEL_ALL, null);
1376 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
1377 checkCallerIsSystem();
1379 setNotificationsEnabledForPackageImpl(pkg, uid, enabled);
1380 mRankingHelper.setEnabled(pkg, uid, enabled);
1385 * Use this when you just want to know if notifications are OK for this package.
1388 public boolean areNotificationsEnabled(String pkg) {
1389 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
1393 * Use this when you just want to know if notifications are OK for this package.
1396 public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
1397 checkCallerIsSystemOrSameApp(pkg);
1398 return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
1399 == AppOpsManager.MODE_ALLOWED) && !isPackageSuspendedForUser(pkg, uid);
1403 public void setPriority(String pkg, int uid, int priority) {
1404 checkCallerIsSystem();
1405 mRankingHelper.setPriority(pkg, uid, priority);
1410 public int getPriority(String pkg, int uid) {
1411 checkCallerIsSystem();
1412 return mRankingHelper.getPriority(pkg, uid);
1416 public void setVisibilityOverride(String pkg, int uid, int visibility) {
1417 checkCallerIsSystem();
1418 mRankingHelper.setVisibilityOverride(pkg, uid, visibility);
1423 public int getVisibilityOverride(String pkg, int uid) {
1424 checkCallerIsSystem();
1425 return mRankingHelper.getVisibilityOverride(pkg, uid);
1429 public void setImportance(String pkg, int uid, int importance) {
1430 enforceSystemOrSystemUI("Caller not system or systemui");
1431 setNotificationsEnabledForPackageImpl(pkg, uid,
1432 importance != NotificationListenerService.Ranking.IMPORTANCE_NONE);
1433 mRankingHelper.setImportance(pkg, uid, importance);
1438 public int getPackageImportance(String pkg) {
1439 checkCallerIsSystemOrSameApp(pkg);
1440 return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
1444 public int getImportance(String pkg, int uid) {
1445 enforceSystemOrSystemUI("Caller not system or systemui");
1446 return mRankingHelper.getImportance(pkg, uid);
1450 * System-only API for getting a list of current (i.e. not cleared) notifications.
1452 * Requires ACCESS_NOTIFICATIONS which is signature|system.
1453 * @returns A list of all the notifications, in natural order.
1456 public StatusBarNotification[] getActiveNotifications(String callingPkg) {
1457 // enforce() will ensure the calling uid has the correct permission
1458 getContext().enforceCallingOrSelfPermission(
1459 android.Manifest.permission.ACCESS_NOTIFICATIONS,
1460 "NotificationManagerService.getActiveNotifications");
1462 StatusBarNotification[] tmp = null;
1463 int uid = Binder.getCallingUid();
1465 // noteOp will check to make sure the callingPkg matches the uid
1466 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1467 == AppOpsManager.MODE_ALLOWED) {
1468 synchronized (mNotificationList) {
1469 tmp = new StatusBarNotification[mNotificationList.size()];
1470 final int N = mNotificationList.size();
1471 for (int i=0; i<N; i++) {
1472 tmp[i] = mNotificationList.get(i).sbn;
1480 * Public API for getting a list of current notifications for the calling package/uid.
1482 * @returns A list of all the package's notifications, in natural order.
1485 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
1486 int incomingUserId) {
1487 checkCallerIsSystemOrSameApp(pkg);
1488 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1489 Binder.getCallingUid(), incomingUserId, true, false,
1490 "getAppActiveNotifications", pkg);
1492 final ArrayList<StatusBarNotification> list
1493 = new ArrayList<StatusBarNotification>(mNotificationList.size());
1495 synchronized (mNotificationList) {
1496 final int N = mNotificationList.size();
1497 for (int i = 0; i < N; i++) {
1498 final StatusBarNotification sbn = mNotificationList.get(i).sbn;
1499 if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId
1500 && (sbn.getNotification().flags
1501 & Notification.FLAG_AUTOGROUP_SUMMARY) == 0) {
1502 // We could pass back a cloneLight() but clients might get confused and
1503 // try to send this thing back to notify() again, which would not work
1505 final StatusBarNotification sbnOut = new StatusBarNotification(
1506 sbn.getPackageName(),
1508 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
1509 0, // hide score from apps
1510 sbn.getNotification().clone(),
1511 sbn.getUser(), sbn.getPostTime());
1517 return new ParceledListSlice<StatusBarNotification>(list);
1521 * System-only API for getting a list of recent (cleared, no longer shown) notifications.
1523 * Requires ACCESS_NOTIFICATIONS which is signature|system.
1526 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
1527 // enforce() will ensure the calling uid has the correct permission
1528 getContext().enforceCallingOrSelfPermission(
1529 android.Manifest.permission.ACCESS_NOTIFICATIONS,
1530 "NotificationManagerService.getHistoricalNotifications");
1532 StatusBarNotification[] tmp = null;
1533 int uid = Binder.getCallingUid();
1535 // noteOp will check to make sure the callingPkg matches the uid
1536 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1537 == AppOpsManager.MODE_ALLOWED) {
1538 synchronized (mArchive) {
1539 tmp = mArchive.getArray(count);
1546 * Register a listener binder directly with the notification manager.
1548 * Only works with system callers. Apps should extend
1549 * {@link android.service.notification.NotificationListenerService}.
1552 public void registerListener(final INotificationListener listener,
1553 final ComponentName component, final int userid) {
1554 enforceSystemOrSystemUI("INotificationManager.registerListener");
1555 mListeners.registerService(listener, component, userid);
1559 * Remove a listener binder directly
1562 public void unregisterListener(INotificationListener token, int userid) {
1563 mListeners.unregisterService(token, userid);
1567 * Allow an INotificationListener to simulate a "clear all" operation.
1569 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
1571 * @param token The binder for the listener, to check that the caller is allowed
1574 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
1575 final int callingUid = Binder.getCallingUid();
1576 final int callingPid = Binder.getCallingPid();
1577 long identity = Binder.clearCallingIdentity();
1579 synchronized (mNotificationList) {
1580 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1582 final int N = keys.length;
1583 for (int i = 0; i < N; i++) {
1584 NotificationRecord r = mNotificationsByKey.get(keys[i]);
1585 if (r == null) continue;
1586 final int userId = r.sbn.getUserId();
1587 if (userId != info.userid && userId != UserHandle.USER_ALL &&
1588 !mUserProfiles.isCurrentProfile(userId)) {
1589 throw new SecurityException("Disallowed call from listener: "
1592 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
1593 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
1597 cancelAllLocked(callingUid, callingPid, info.userid,
1598 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
1602 Binder.restoreCallingIdentity(identity);
1607 * Handle request from an approved listener to re-enable itself.
1609 * @param component The componenet to be re-enabled, caller must match package.
1612 public void requestBindListener(ComponentName component) {
1613 checkCallerIsSystemOrSameApp(component.getPackageName());
1614 long identity = Binder.clearCallingIdentity();
1616 ManagedServices manager =
1617 mRankerServices.isComponentEnabledForCurrentProfiles(component)
1620 manager.setComponentState(component, true);
1622 Binder.restoreCallingIdentity(identity);
1627 public void requestUnbindListener(INotificationListener token) {
1628 long identity = Binder.clearCallingIdentity();
1630 // allow bound services to disable themselves
1631 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1632 info.getOwner().setComponentState(info.component, false);
1634 Binder.restoreCallingIdentity(identity);
1639 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
1640 long identity = Binder.clearCallingIdentity();
1642 synchronized (mNotificationList) {
1643 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1645 final int N = keys.length;
1646 for (int i = 0; i < N; i++) {
1647 NotificationRecord r = mNotificationsByKey.get(keys[i]);
1648 if (r == null) continue;
1649 final int userId = r.sbn.getUserId();
1650 if (userId != info.userid && userId != UserHandle.USER_ALL &&
1651 !mUserProfiles.isCurrentProfile(userId)) {
1652 throw new SecurityException("Disallowed call from listener: "
1656 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
1657 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
1658 userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM
1660 UsageEvents.Event.USER_INTERACTION);
1667 Binder.restoreCallingIdentity(identity);
1671 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
1672 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
1673 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
1674 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
1676 userId, REASON_LISTENER_CANCEL, info);
1680 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
1682 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
1684 * @param token The binder for the listener, to check that the caller is allowed
1687 public void cancelNotificationFromListener(INotificationListener token, String pkg,
1688 String tag, int id) {
1689 final int callingUid = Binder.getCallingUid();
1690 final int callingPid = Binder.getCallingPid();
1691 long identity = Binder.clearCallingIdentity();
1693 synchronized (mNotificationList) {
1694 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1695 if (info.supportsProfiles()) {
1696 Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
1697 + "from " + info.component
1698 + " use cancelNotification(key) instead.");
1700 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
1701 pkg, tag, id, info.userid);
1705 Binder.restoreCallingIdentity(identity);
1710 * Allow an INotificationListener to request the list of outstanding notifications seen by
1711 * the current user. Useful when starting up, after which point the listener callbacks
1714 * @param token The binder for the listener, to check that the caller is allowed
1715 * @param keys An array of notification keys to fetch, or null to fetch everything
1716 * @returns The return value will contain the notifications specified in keys, in that
1717 * order, or if keys is null, all the notifications, in natural order.
1720 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
1721 INotificationListener token, String[] keys, int trim) {
1722 synchronized (mNotificationList) {
1723 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1724 final boolean getKeys = keys != null;
1725 final int N = getKeys ? keys.length : mNotificationList.size();
1726 final ArrayList<StatusBarNotification> list
1727 = new ArrayList<StatusBarNotification>(N);
1728 for (int i=0; i<N; i++) {
1729 final NotificationRecord r = getKeys
1730 ? mNotificationsByKey.get(keys[i])
1731 : mNotificationList.get(i);
1732 if (r == null) continue;
1733 StatusBarNotification sbn = r.sbn;
1734 if (!isVisibleToListener(sbn, info)) continue;
1735 StatusBarNotification sbnToSend =
1736 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
1737 list.add(sbnToSend);
1739 return new ParceledListSlice<StatusBarNotification>(list);
1744 public void requestHintsFromListener(INotificationListener token, int hints) {
1745 final long identity = Binder.clearCallingIdentity();
1747 synchronized (mNotificationList) {
1748 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1749 final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
1750 | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
1751 | HINT_HOST_DISABLE_CALL_EFFECTS;
1752 final boolean disableEffects = (hints & disableEffectsMask) != 0;
1753 if (disableEffects) {
1754 addDisabledHints(info, hints);
1756 removeDisabledHints(info, hints);
1758 updateListenerHintsLocked();
1759 updateEffectsSuppressorLocked();
1762 Binder.restoreCallingIdentity(identity);
1767 public int getHintsFromListener(INotificationListener token) {
1768 synchronized (mNotificationList) {
1769 return mListenerHints;
1774 public void requestInterruptionFilterFromListener(INotificationListener token,
1775 int interruptionFilter) throws RemoteException {
1776 final long identity = Binder.clearCallingIdentity();
1778 synchronized (mNotificationList) {
1779 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1780 mZenModeHelper.requestFromListener(info.component, interruptionFilter);
1781 updateInterruptionFilterLocked();
1784 Binder.restoreCallingIdentity(identity);
1789 public int getInterruptionFilterFromListener(INotificationListener token)
1790 throws RemoteException {
1791 synchronized (mNotificationLight) {
1792 return mInterruptionFilter;
1797 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
1798 throws RemoteException {
1799 synchronized (mNotificationList) {
1800 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1801 if (info == null) return;
1802 mListeners.setOnNotificationPostedTrimLocked(info, trim);
1807 public int getZenMode() {
1808 return mZenModeHelper.getZenMode();
1812 public ZenModeConfig getZenModeConfig() {
1813 enforceSystemOrSystemUIOrVolume("INotificationManager.getZenModeConfig");
1814 return mZenModeHelper.getConfig();
1818 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
1819 enforceSystemOrSystemUIOrVolume("INotificationManager.setZenMode");
1820 final long identity = Binder.clearCallingIdentity();
1822 mZenModeHelper.setManualZenMode(mode, conditionId, reason);
1824 Binder.restoreCallingIdentity(identity);
1829 public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
1830 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
1831 return mZenModeHelper.getZenRules();
1835 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
1836 Preconditions.checkNotNull(id, "Id is null");
1837 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
1838 return mZenModeHelper.getAutomaticZenRule(id);
1842 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
1843 throws RemoteException {
1844 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
1845 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
1846 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
1847 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
1848 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
1850 return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
1851 "addAutomaticZenRule");
1855 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
1856 throws RemoteException {
1857 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
1858 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
1859 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
1860 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
1861 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
1863 return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
1864 "updateAutomaticZenRule");
1868 public boolean removeAutomaticZenRule(String id) throws RemoteException {
1869 Preconditions.checkNotNull(id, "Id is null");
1870 // Verify that they can modify zen rules.
1871 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
1873 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
1877 public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
1878 Preconditions.checkNotNull(packageName, "Package name is null");
1879 enforceSystemOrSystemUI("removeAutomaticZenRules");
1881 return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
1885 public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
1886 Preconditions.checkNotNull(owner, "Owner is null");
1887 enforceSystemOrSystemUI("getRuleInstanceCount");
1889 return mZenModeHelper.getCurrentInstanceCount(owner);
1893 public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
1894 enforcePolicyAccess(pkg, "setInterruptionFilter");
1895 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
1896 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
1897 final long identity = Binder.clearCallingIdentity();
1899 mZenModeHelper.setManualZenMode(zen, null, "setInterruptionFilter");
1901 Binder.restoreCallingIdentity(identity);
1906 public void notifyConditions(final String pkg, IConditionProvider provider,
1907 final Condition[] conditions) {
1908 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
1909 checkCallerIsSystemOrSameApp(pkg);
1910 mHandler.post(new Runnable() {
1913 mConditionProviders.notifyConditions(pkg, info, conditions);
1918 private void enforceSystemOrSystemUIOrVolume(String message) {
1919 if (mAudioManagerInternal != null) {
1920 final int vcuid = mAudioManagerInternal.getVolumeControllerUid();
1921 if (vcuid > 0 && Binder.getCallingUid() == vcuid) {
1925 enforceSystemOrSystemUI(message);
1928 private void enforceSystemOrSystemUI(String message) {
1929 if (isCallerSystem()) return;
1930 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
1934 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
1936 checkCallerIsSystemOrSameApp(pkg);
1937 } catch (SecurityException e) {
1938 getContext().enforceCallingPermission(
1939 android.Manifest.permission.STATUS_BAR_SERVICE,
1944 private void enforcePolicyAccess(int uid, String method) {
1945 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
1946 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
1949 boolean accessAllowed = false;
1950 String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
1951 final int packageCount = packages.length;
1952 for (int i = 0; i < packageCount; i++) {
1953 if (checkPolicyAccess(packages[i])) {
1954 accessAllowed = true;
1957 if (!accessAllowed) {
1958 Slog.w(TAG, "Notification policy access denied calling " + method);
1959 throw new SecurityException("Notification policy access denied");
1963 private void enforcePolicyAccess(String pkg, String method) {
1964 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
1965 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
1968 if (!checkPolicyAccess(pkg)) {
1969 Slog.w(TAG, "Notification policy access denied calling " + method);
1970 throw new SecurityException("Notification policy access denied");
1974 private boolean checkPackagePolicyAccess(String pkg) {
1975 return mPolicyAccess.isPackageGranted(pkg);
1978 private boolean checkPolicyAccess(String pkg) {
1980 int uid = getContext().getPackageManager().getPackageUidAsUser(
1981 pkg, UserHandle.getCallingUserId());
1982 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
1983 android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
1987 } catch (NameNotFoundException e) {
1990 return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
1994 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1995 if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1996 != PackageManager.PERMISSION_GRANTED) {
1997 pw.println("Permission Denial: can't dump NotificationManager from pid="
1998 + Binder.getCallingPid()
1999 + ", uid=" + Binder.getCallingUid());
2003 final DumpFilter filter = DumpFilter.parseFromArguments(args);
2004 if (filter != null && filter.stats) {
2005 dumpJson(pw, filter);
2007 dumpImpl(pw, filter);
2012 public ComponentName getEffectsSuppressor() {
2013 enforceSystemOrSystemUIOrVolume("INotificationManager.getEffectsSuppressor");
2014 return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
2018 public boolean matchesCallFilter(Bundle extras) {
2019 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
2020 return mZenModeHelper.matchesCallFilter(
2021 Binder.getCallingUserHandle(),
2023 mRankingHelper.findExtractor(ValidateNotificationPeople.class),
2024 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
2025 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
2029 public boolean isSystemConditionProviderEnabled(String path) {
2030 enforceSystemOrSystemUIOrVolume("INotificationManager.isSystemConditionProviderEnabled");
2031 return mConditionProviders.isSystemProviderEnabled(path);
2034 // Backup/restore interface
2036 public byte[] getBackupPayload(int user) {
2037 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
2038 //TODO: http://b/22388012
2039 if (user != UserHandle.USER_SYSTEM) {
2040 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
2043 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
2045 writePolicyXml(baos, true /*forBackup*/);
2046 return baos.toByteArray();
2047 } catch (IOException e) {
2048 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
2054 public void applyRestore(byte[] payload, int user) {
2055 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
2056 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
2057 if (payload == null) {
2058 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
2061 //TODO: http://b/22388012
2062 if (user != UserHandle.USER_SYSTEM) {
2063 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
2066 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
2068 readPolicyXml(bais, true /*forRestore*/);
2070 } catch (NumberFormatException | XmlPullParserException | IOException e) {
2071 Slog.w(TAG, "applyRestore: error reading payload", e);
2076 public boolean isNotificationPolicyAccessGranted(String pkg) {
2077 return checkPolicyAccess(pkg);
2081 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
2082 enforceSystemOrSystemUIOrSamePackage(pkg,
2083 "request policy access status for another package");
2084 return checkPolicyAccess(pkg);
2088 public String[] getPackagesRequestingNotificationPolicyAccess()
2089 throws RemoteException {
2090 enforceSystemOrSystemUI("request policy access packages");
2091 final long identity = Binder.clearCallingIdentity();
2093 return mPolicyAccess.getRequestingPackages();
2095 Binder.restoreCallingIdentity(identity);
2100 public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
2101 throws RemoteException {
2102 enforceSystemOrSystemUI("grant notification policy access");
2103 final long identity = Binder.clearCallingIdentity();
2105 synchronized (mNotificationList) {
2106 mPolicyAccess.put(pkg, granted);
2109 Binder.restoreCallingIdentity(identity);
2114 public Policy getNotificationPolicy(String pkg) {
2115 enforcePolicyAccess(pkg, "getNotificationPolicy");
2116 final long identity = Binder.clearCallingIdentity();
2118 return mZenModeHelper.getNotificationPolicy();
2120 Binder.restoreCallingIdentity(identity);
2125 public void setNotificationPolicy(String pkg, Policy policy) {
2126 enforcePolicyAccess(pkg, "setNotificationPolicy");
2127 final long identity = Binder.clearCallingIdentity();
2129 mZenModeHelper.setNotificationPolicy(policy);
2131 Binder.restoreCallingIdentity(identity);
2136 public void applyAdjustmentFromRankerService(INotificationListener token,
2137 Adjustment adjustment) throws RemoteException {
2138 final long identity = Binder.clearCallingIdentity();
2140 synchronized (mNotificationList) {
2141 mRankerServices.checkServiceTokenLocked(token);
2142 applyAdjustmentLocked(adjustment);
2144 maybeAddAutobundleSummary(adjustment);
2145 mRankingHandler.requestSort();
2147 Binder.restoreCallingIdentity(identity);
2152 public void applyAdjustmentsFromRankerService(INotificationListener token,
2153 List<Adjustment> adjustments) throws RemoteException {
2155 final long identity = Binder.clearCallingIdentity();
2157 synchronized (mNotificationList) {
2158 mRankerServices.checkServiceTokenLocked(token);
2159 for (Adjustment adjustment : adjustments) {
2160 applyAdjustmentLocked(adjustment);
2163 for (Adjustment adjustment : adjustments) {
2164 maybeAddAutobundleSummary(adjustment);
2166 mRankingHandler.requestSort();
2168 Binder.restoreCallingIdentity(identity);
2173 private void applyAdjustmentLocked(Adjustment adjustment) {
2174 maybeClearAutobundleSummaryLocked(adjustment);
2175 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2179 if (adjustment.getImportance() != IMPORTANCE_NONE) {
2180 n.setImportance(adjustment.getImportance(), adjustment.getExplanation());
2182 if (adjustment.getSignals() != null) {
2183 Bundle.setDefusable(adjustment.getSignals(), true);
2184 final String autoGroupKey = adjustment.getSignals().getString(
2185 Adjustment.GROUP_KEY_OVERRIDE_KEY, null);
2186 if (autoGroupKey == null) {
2187 EventLogTags.writeNotificationUnautogrouped(adjustment.getKey());
2189 EventLogTags.writeNotificationAutogrouped(adjustment.getKey());
2191 n.sbn.setOverrideGroupKey(autoGroupKey);
2195 // Clears the 'fake' auto-bunding summary.
2196 private void maybeClearAutobundleSummaryLocked(Adjustment adjustment) {
2197 if (adjustment.getSignals() != null) {
2198 Bundle.setDefusable(adjustment.getSignals(), true);
2199 if (adjustment.getSignals().containsKey(Adjustment.NEEDS_AUTOGROUPING_KEY)
2200 && !adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) {
2201 ArrayMap<String, String> summaries =
2202 mAutobundledSummaries.get(adjustment.getUser());
2203 if (summaries != null && summaries.containsKey(adjustment.getPackage())) {
2205 final NotificationRecord removed = mNotificationsByKey.get(
2206 summaries.remove(adjustment.getPackage()));
2207 if (removed != null) {
2208 mNotificationList.remove(removed);
2209 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED);
2216 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
2217 private void maybeAddAutobundleSummary(Adjustment adjustment) {
2218 if (adjustment.getSignals() != null) {
2219 Bundle.setDefusable(adjustment.getSignals(), true);
2220 if (adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) {
2221 final String newAutoBundleKey =
2222 adjustment.getSignals().getString(Adjustment.GROUP_KEY_OVERRIDE_KEY, null);
2224 NotificationRecord summaryRecord = null;
2225 synchronized (mNotificationList) {
2226 NotificationRecord notificationRecord =
2227 mNotificationsByKey.get(adjustment.getKey());
2228 if (notificationRecord == null) {
2229 // The notification could have been cancelled again already. A successive
2230 // adjustment will post a summary if needed.
2233 final StatusBarNotification adjustedSbn = notificationRecord.sbn;
2234 userId = adjustedSbn.getUser().getIdentifier();
2235 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
2236 if (summaries == null) {
2237 summaries = new ArrayMap<>();
2239 mAutobundledSummaries.put(userId, summaries);
2240 if (!summaries.containsKey(adjustment.getPackage())
2241 && newAutoBundleKey != null) {
2243 final ApplicationInfo appInfo =
2244 adjustedSbn.getNotification().extras.getParcelable(
2245 Notification.EXTRA_BUILDER_APPLICATION_INFO);
2246 final Bundle extras = new Bundle();
2247 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
2248 final Notification summaryNotification =
2249 new Notification.Builder(getContext()).setSmallIcon(
2250 adjustedSbn.getNotification().getSmallIcon())
2251 .setGroupSummary(true)
2252 .setGroup(newAutoBundleKey)
2253 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
2254 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
2255 .setColor(adjustedSbn.getNotification().color)
2257 summaryNotification.extras.putAll(extras);
2258 Intent appIntent = getContext().getPackageManager()
2259 .getLaunchIntentForPackage(adjustment.getPackage());
2260 if (appIntent != null) {
2261 summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
2262 getContext(), 0, appIntent, 0, null,
2263 UserHandle.of(userId));
2265 final StatusBarNotification summarySbn =
2266 new StatusBarNotification(adjustedSbn.getPackageName(),
2267 adjustedSbn.getOpPkg(),
2268 Integer.MAX_VALUE, Adjustment.GROUP_KEY_OVERRIDE_KEY,
2269 adjustedSbn.getUid(), adjustedSbn.getInitialPid(),
2270 summaryNotification, adjustedSbn.getUser(),
2272 System.currentTimeMillis());
2273 summaryRecord = new NotificationRecord(getContext(), summarySbn);
2274 summaries.put(adjustment.getPackage(), summarySbn.getKey());
2277 if (summaryRecord != null) {
2278 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
2284 private String disableNotificationEffects(NotificationRecord record) {
2285 if (mDisableNotificationEffects) {
2286 return "booleanState";
2288 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
2289 return "listenerHints";
2291 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
2297 private void dumpJson(PrintWriter pw, DumpFilter filter) {
2298 JSONObject dump = new JSONObject();
2300 dump.put("service", "Notification Manager");
2301 dump.put("bans", mRankingHelper.dumpBansJson(filter));
2302 dump.put("ranking", mRankingHelper.dumpJson(filter));
2303 dump.put("stats", mUsageStats.dumpJson(filter));
2304 } catch (JSONException e) {
2305 e.printStackTrace();
2310 void dumpImpl(PrintWriter pw, DumpFilter filter) {
2311 pw.print("Current Notification Manager state");
2312 if (filter.filtered) {
2313 pw.print(" (filtered to "); pw.print(filter); pw.print(")");
2317 final boolean zenOnly = filter.filtered && filter.zen;
2320 synchronized (mToastQueue) {
2321 N = mToastQueue.size();
2323 pw.println(" Toast Queue:");
2324 for (int i=0; i<N; i++) {
2325 mToastQueue.get(i).dump(pw, " ", filter);
2332 synchronized (mNotificationList) {
2334 N = mNotificationList.size();
2336 pw.println(" Notification List:");
2337 for (int i=0; i<N; i++) {
2338 final NotificationRecord nr = mNotificationList.get(i);
2339 if (filter.filtered && !filter.matches(nr.sbn)) continue;
2340 nr.dump(pw, " ", getContext(), filter.redact);
2345 if (!filter.filtered) {
2348 pw.println(" Lights List:");
2349 for (int i=0; i<N; i++) {
2355 pw.println(mLights.get(i));
2359 pw.println(" mUseAttentionLight=" + mUseAttentionLight);
2360 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled);
2361 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey);
2362 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey);
2363 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects);
2364 pw.println(" mCallState=" + callStateToString(mCallState));
2365 pw.println(" mSystemReady=" + mSystemReady);
2367 pw.println(" mArchive=" + mArchive.toString());
2368 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
2370 while (iter.hasNext()) {
2371 final StatusBarNotification sbn = iter.next();
2372 if (filter != null && !filter.matches(sbn)) continue;
2373 pw.println(" " + sbn);
2375 if (iter.hasNext()) pw.println(" ...");
2382 pw.println("\n Usage Stats:");
2383 mUsageStats.dump(pw, " ", filter);
2386 if (!filter.filtered || zenOnly) {
2387 pw.println("\n Zen Mode:");
2388 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter);
2389 mZenModeHelper.dump(pw, " ");
2391 pw.println("\n Zen Log:");
2392 ZenLog.dump(pw, " ");
2396 pw.println("\n Ranking Config:");
2397 mRankingHelper.dump(pw, " ", filter);
2399 pw.println("\n Notification listeners:");
2400 mListeners.dump(pw, filter);
2401 pw.print(" mListenerHints: "); pw.println(mListenerHints);
2402 pw.print(" mListenersDisablingEffects: (");
2403 N = mListenersDisablingEffects.size();
2404 for (int i = 0; i < N; i++) {
2405 final int hint = mListenersDisablingEffects.keyAt(i);
2406 if (i > 0) pw.print(';');
2407 pw.print("hint[" + hint + "]:");
2409 final ArraySet<ManagedServiceInfo> listeners =
2410 mListenersDisablingEffects.valueAt(i);
2411 final int listenerSize = listeners.size();
2413 for (int j = 0; j < listenerSize; j++) {
2414 if (i > 0) pw.print(',');
2415 final ManagedServiceInfo listener = listeners.valueAt(i);
2416 pw.print(listener.component);
2420 pw.println("\n mRankerServicePackageName: " + mRankerServicePackageName);
2421 pw.println("\n Notification ranker services:");
2422 mRankerServices.dump(pw, filter);
2424 pw.println("\n Policy access:");
2425 pw.print(" mPolicyAccess: "); pw.println(mPolicyAccess);
2427 pw.println("\n Condition providers:");
2428 mConditionProviders.dump(pw, filter);
2430 pw.println("\n Group summaries:");
2431 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
2432 NotificationRecord r = entry.getValue();
2433 pw.println(" " + entry.getKey() + " -> " + r.getKey());
2434 if (mNotificationsByKey.get(r.getKey()) != r) {
2435 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
2436 r.dump(pw, " ", getContext(), filter.redact);
2443 * The private API only accessible to the system process.
2445 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
2447 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
2448 String tag, int id, Notification notification, int[] idReceived, int userId) {
2449 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
2450 idReceived, userId);
2454 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
2456 checkCallerIsSystem();
2457 synchronized (mNotificationList) {
2458 int i = indexOfNotificationLocked(pkg, null, notificationId, userId);
2460 Log.d(TAG, "stripForegroundServiceFlag: Could not find notification with "
2461 + "pkg=" + pkg + " / id=" + notificationId + " / userId=" + userId);
2464 NotificationRecord r = mNotificationList.get(i);
2465 StatusBarNotification sbn = r.sbn;
2466 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
2467 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove FLAG_FOREGROUND_SERVICE,
2468 // we have to revert to the flags we received initially *and* force remove
2469 // FLAG_FOREGROUND_SERVICE.
2470 sbn.getNotification().flags =
2471 (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
2472 mRankingHelper.sort(mNotificationList);
2473 mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
2478 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
2479 final int callingPid, final String tag, final int id, final Notification notification,
2480 int[] idOut, int incomingUserId) {
2482 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
2483 + " notification=" + notification);
2485 checkCallerIsSystemOrSameApp(pkg);
2486 final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg));
2487 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
2489 final int userId = ActivityManager.handleIncomingUser(callingPid,
2490 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
2491 final UserHandle user = new UserHandle(userId);
2493 // Fix the notification as best we can.
2495 final ApplicationInfo ai = getContext().getPackageManager().getApplicationInfoAsUser(
2496 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
2497 (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
2498 Notification.addFieldsFromContext(ai, userId, notification);
2499 } catch (NameNotFoundException e) {
2500 Slog.e(TAG, "Cannot create a context for sending app", e);
2504 // Limit the number of notifications that any given package except the android
2505 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
2506 if (!isSystemNotification && !isNotificationFromListener) {
2507 synchronized (mNotificationList) {
2508 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
2509 if (appEnqueueRate > MAX_PACKAGE_ENQUEUE_RATE) {
2510 mUsageStats.registerOverRateQuota(pkg);
2511 final long now = SystemClock.elapsedRealtime();
2512 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
2513 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
2514 + ". Shedding events. package=" + pkg);
2515 mLastOverRateLogTime = now;
2521 final int N = mNotificationList.size();
2522 for (int i=0; i<N; i++) {
2523 final NotificationRecord r = mNotificationList.get(i);
2524 if (r.sbn.getPackageName().equals(pkg) && r.sbn.getUserId() == userId) {
2525 if (r.sbn.getId() == id && TextUtils.equals(r.sbn.getTag(), tag)) {
2526 break; // Allow updating existing notification
2529 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
2530 mUsageStats.registerOverCountQuota(pkg);
2531 Slog.e(TAG, "Package has already posted " + count
2532 + " notifications. Not showing more. package=" + pkg);
2540 if (pkg == null || notification == null) {
2541 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
2542 + " id=" + id + " notification=" + notification);
2546 notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN,
2547 Notification.PRIORITY_MAX);
2549 // setup local book-keeping
2550 final StatusBarNotification n = new StatusBarNotification(
2551 pkg, opPkg, id, tag, callingUid, callingPid, 0, notification,
2553 final NotificationRecord r = new NotificationRecord(getContext(), n);
2554 mHandler.post(new EnqueueNotificationRunnable(userId, r));
2559 private class EnqueueNotificationRunnable implements Runnable {
2560 private final NotificationRecord r;
2561 private final int userId;
2563 EnqueueNotificationRunnable(int userId, NotificationRecord r) {
2564 this.userId = userId;
2571 synchronized (mNotificationList) {
2572 final StatusBarNotification n = r.sbn;
2573 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
2574 NotificationRecord old = mNotificationsByKey.get(n.getKey());
2576 // Retain ranking information from previous record
2577 r.copyRankingInformation(old);
2580 final int callingUid = n.getUid();
2581 final int callingPid = n.getInitialPid();
2582 final Notification notification = n.getNotification();
2583 final String pkg = n.getPackageName();
2584 final int id = n.getId();
2585 final String tag = n.getTag();
2586 final boolean isSystemNotification = isUidSystem(callingUid) ||
2587 ("android".equals(pkg));
2589 // Handle grouped notifications and bail out early if we
2590 // can to avoid extracting signals.
2591 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
2593 // This conditional is a dirty hack to limit the logging done on
2594 // behalf of the download manager without affecting other apps.
2595 if (!pkg.equals("com.android.providers.downloads")
2596 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
2597 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
2599 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
2601 EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
2602 pkg, id, tag, userId, notification.toString(),
2606 mRankingHelper.extractSignals(r);
2608 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
2611 if (r.getImportance() == NotificationListenerService.Ranking.IMPORTANCE_NONE
2612 || !noteNotificationOp(pkg, callingUid) || isPackageSuspended) {
2613 if (!isSystemNotification) {
2614 if (isPackageSuspended) {
2615 Slog.e(TAG, "Suppressing notification from package due to package "
2616 + "suspended by administrator.");
2617 mUsageStats.registerSuspendedByAdmin(r);
2619 Slog.e(TAG, "Suppressing notification from package by user request.");
2620 mUsageStats.registerBlocked(r);
2626 // tell the ranker service about the notification
2627 if (mRankerServices.isEnabled()) {
2628 mRankerServices.onNotificationEnqueued(r);
2629 // TODO delay the code below here for 100ms or until there is an answer
2633 int index = indexOfNotificationLocked(n.getKey());
2635 mNotificationList.add(r);
2636 mUsageStats.registerPostedByApp(r);
2638 old = mNotificationList.get(index);
2639 mNotificationList.set(index, r);
2640 mUsageStats.registerUpdatedByApp(r, old);
2641 // Make sure we don't lose the foreground service state.
2642 notification.flags |=
2643 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
2647 mNotificationsByKey.put(n.getKey(), r);
2649 // Ensure if this is a foreground service that the proper additional
2651 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
2652 notification.flags |= Notification.FLAG_ONGOING_EVENT
2653 | Notification.FLAG_NO_CLEAR;
2656 applyZenModeLocked(r);
2657 mRankingHelper.sort(mNotificationList);
2659 if (notification.getSmallIcon() != null) {
2660 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
2661 mListeners.notifyPostedLocked(n, oldSbn);
2663 Slog.e(TAG, "Not posting notification without small icon: " + notification);
2664 if (old != null && !old.isCanceled) {
2665 mListeners.notifyRemovedLocked(n);
2667 // ATTENTION: in a future release we will bail out here
2668 // so that we do not play sounds, show lights, etc. for invalid
2670 Slog.e(TAG, "WARNING: In a future release this will crash the app: "
2671 + n.getPackageName());
2674 buzzBeepBlinkLocked(r);
2680 * Ensures that grouped notification receive their special treatment.
2682 * <p>Cancels group children if the new notification causes a group to lose
2685 * <p>Updates mSummaryByGroupKey.</p>
2687 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
2688 int callingUid, int callingPid) {
2689 StatusBarNotification sbn = r.sbn;
2690 Notification n = sbn.getNotification();
2691 if (n.isGroupSummary() && !sbn.isAppGroup()) {
2692 // notifications without a group shouldn't be a summary, otherwise autobundling can
2694 n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
2697 String group = sbn.getGroupKey();
2698 boolean isSummary = n.isGroupSummary();
2700 Notification oldN = old != null ? old.sbn.getNotification() : null;
2701 String oldGroup = old != null ? old.sbn.getGroupKey() : null;
2702 boolean oldIsSummary = old != null && oldN.isGroupSummary();
2705 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
2706 if (removedSummary != old) {
2708 removedSummary != null ? removedSummary.getKey() : "<null>";
2709 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
2710 ", removed=" + removedKey);
2714 mSummaryByGroupKey.put(group, r);
2717 // Clear out group children of the old notification if the update
2718 // causes the group summary to go away. This happens when the old
2719 // notification was a summary and the new one isn't, or when the old
2720 // notification was a summary and its group key changed.
2721 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
2722 cancelGroupChildrenLocked(old, callingUid, callingPid, null,
2723 REASON_GROUP_SUMMARY_CANCELED);
2728 void buzzBeepBlinkLocked(NotificationRecord record) {
2729 boolean buzz = false;
2730 boolean beep = false;
2731 boolean blink = false;
2733 final Notification notification = record.sbn.getNotification();
2734 final String key = record.getKey();
2736 // Should this notification make noise, vibe, or use the LED?
2737 final boolean aboveThreshold = record.getImportance() >= IMPORTANCE_DEFAULT;
2738 final boolean canInterrupt = aboveThreshold && !record.isIntercepted();
2739 if (DBG || record.isIntercepted())
2741 "pkg=" + record.sbn.getPackageName() + " canInterrupt=" + canInterrupt +
2742 " intercept=" + record.isIntercepted()
2745 final int currentUser;
2746 final long token = Binder.clearCallingIdentity();
2748 currentUser = ActivityManager.getCurrentUser();
2750 Binder.restoreCallingIdentity(token);
2753 // If we're not supposed to beep, vibrate, etc. then don't.
2754 final String disableEffects = disableNotificationEffects(record);
2755 if (disableEffects != null) {
2756 ZenLog.traceDisableEffects(record, disableEffects);
2759 // Remember if this notification already owns the notification channels.
2760 boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
2761 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
2763 // These are set inside the conditional if the notification is allowed to make noise.
2764 boolean hasValidVibrate = false;
2765 boolean hasValidSound = false;
2766 if (disableEffects == null
2767 && (record.getUserId() == UserHandle.USER_ALL ||
2768 record.getUserId() == currentUser ||
2769 mUserProfiles.isCurrentProfile(record.getUserId()))
2772 && mAudioManager != null) {
2773 if (DBG) Slog.v(TAG, "Interrupting!");
2775 // should we use the default notification sound? (indicated either by
2776 // DEFAULT_SOUND or because notification.sound is pointing at
2777 // Settings.System.NOTIFICATION_SOUND)
2778 final boolean useDefaultSound =
2779 (notification.defaults & Notification.DEFAULT_SOUND) != 0 ||
2780 Settings.System.DEFAULT_NOTIFICATION_URI
2781 .equals(notification.sound);
2783 Uri soundUri = null;
2784 if (useDefaultSound) {
2785 soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
2787 // check to see if the default notification sound is silent
2788 ContentResolver resolver = getContext().getContentResolver();
2789 hasValidSound = Settings.System.getString(resolver,
2790 Settings.System.NOTIFICATION_SOUND) != null;
2791 } else if (notification.sound != null) {
2792 soundUri = notification.sound;
2793 hasValidSound = (soundUri != null);
2796 // Does the notification want to specify its own vibration?
2797 final boolean hasCustomVibrate = notification.vibrate != null;
2799 // new in 4.2: if there was supposed to be a sound and we're in vibrate
2800 // mode, and no other vibration is specified, we fall back to vibration
2801 final boolean convertSoundToVibration =
2804 && (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE);
2806 // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
2807 final boolean useDefaultVibrate =
2808 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
2810 hasValidVibrate = useDefaultVibrate || convertSoundToVibration ||
2813 // We can alert, and we're allowed to alert, but if the developer asked us to only do
2814 // it once, and we already have, then don't.
2815 if (!(record.isUpdate
2816 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0)) {
2818 sendAccessibilityEvent(notification, record.sbn.getPackageName());
2820 if (hasValidSound) {
2822 (notification.flags & Notification.FLAG_INSISTENT) != 0;
2823 AudioAttributes audioAttributes = audioAttributesForNotification(notification);
2824 mSoundNotificationKey = key;
2825 // do not play notifications if stream volume is 0 (typically because
2826 // ringer mode is silent) or if there is a user of exclusive audio focus
2827 if ((mAudioManager.getStreamVolume(
2828 AudioAttributes.toLegacyStreamType(audioAttributes)) != 0)
2829 && !mAudioManager.isAudioFocusExclusive()) {
2830 final long identity = Binder.clearCallingIdentity();
2832 final IRingtonePlayer player =
2833 mAudioManager.getRingtonePlayer();
2834 if (player != null) {
2835 if (DBG) Slog.v(TAG, "Playing sound " + soundUri
2836 + " with attributes " + audioAttributes);
2837 player.playAsync(soundUri, record.sbn.getUser(), looping,
2841 } catch (RemoteException e) {
2843 Binder.restoreCallingIdentity(identity);
2848 if (hasValidVibrate && !(mAudioManager.getRingerModeInternal()
2849 == AudioManager.RINGER_MODE_SILENT)) {
2850 mVibrateNotificationKey = key;
2852 if (useDefaultVibrate || convertSoundToVibration) {
2853 // Escalate privileges so we can use the vibrator even if the
2854 // notifying app does not have the VIBRATE permission.
2855 long identity = Binder.clearCallingIdentity();
2857 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
2858 useDefaultVibrate ? mDefaultVibrationPattern
2859 : mFallbackVibrationPattern,
2860 ((notification.flags & Notification.FLAG_INSISTENT) != 0)
2861 ? 0: -1, audioAttributesForNotification(notification));
2864 Binder.restoreCallingIdentity(identity);
2866 } else if (notification.vibrate.length > 1) {
2867 // If you want your own vibration pattern, you need the VIBRATE
2869 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
2870 notification.vibrate,
2871 ((notification.flags & Notification.FLAG_INSISTENT) != 0)
2872 ? 0: -1, audioAttributesForNotification(notification));
2879 // If a notification is updated to remove the actively playing sound or vibrate,
2880 // cancel that feedback now
2881 if (wasBeep && !hasValidSound) {
2884 if (wasBuzz && !hasValidVibrate) {
2885 clearVibrateLocked();
2889 // release the light
2890 boolean wasShowLights = mLights.remove(key);
2891 if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold
2892 && ((record.getSuppressedVisualEffects()
2893 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
2895 updateLightsLocked();
2896 if (mUseAttentionLight) {
2897 mAttentionLight.pulse();
2900 } else if (wasShowLights) {
2901 updateLightsLocked();
2903 if (buzz || beep || blink) {
2904 if (((record.getSuppressedVisualEffects()
2905 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) != 0)) {
2906 if (DBG) Slog.v(TAG, "Suppressed SystemUI from triggering screen on");
2908 EventLogTags.writeNotificationAlert(key,
2909 buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
2910 mHandler.post(mBuzzBeepBlinked);
2915 private static AudioAttributes audioAttributesForNotification(Notification n) {
2916 if (n.audioAttributes != null
2917 && !Notification.AUDIO_ATTRIBUTES_DEFAULT.equals(n.audioAttributes)) {
2918 // the audio attributes are set and different from the default, use them
2919 return n.audioAttributes;
2920 } else if (n.audioStreamType >= 0 && n.audioStreamType < AudioSystem.getNumStreamTypes()) {
2921 // the stream type is valid, use it
2922 return new AudioAttributes.Builder()
2923 .setInternalLegacyStreamType(n.audioStreamType)
2925 } else if (n.audioStreamType == AudioSystem.STREAM_DEFAULT) {
2926 return Notification.AUDIO_ATTRIBUTES_DEFAULT;
2928 Log.w(TAG, String.format("Invalid stream type: %d", n.audioStreamType));
2929 return Notification.AUDIO_ATTRIBUTES_DEFAULT;
2933 void showNextToastLocked() {
2934 ToastRecord record = mToastQueue.get(0);
2935 while (record != null) {
2936 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
2938 record.callback.show();
2939 scheduleTimeoutLocked(record);
2941 } catch (RemoteException e) {
2942 Slog.w(TAG, "Object died trying to show notification " + record.callback
2943 + " in package " + record.pkg);
2944 // remove it from the list and let the process die
2945 int index = mToastQueue.indexOf(record);
2947 mToastQueue.remove(index);
2949 keepProcessAliveLocked(record.pid);
2950 if (mToastQueue.size() > 0) {
2951 record = mToastQueue.get(0);
2959 void cancelToastLocked(int index) {
2960 ToastRecord record = mToastQueue.get(index);
2962 record.callback.hide();
2963 } catch (RemoteException e) {
2964 Slog.w(TAG, "Object died trying to hide notification " + record.callback
2965 + " in package " + record.pkg);
2966 // don't worry about this, we're about to remove it from
2969 mToastQueue.remove(index);
2970 keepProcessAliveLocked(record.pid);
2971 if (mToastQueue.size() > 0) {
2972 // Show the next one. If the callback fails, this will remove
2973 // it from the list, so don't assume that the list hasn't changed
2974 // after this point.
2975 showNextToastLocked();
2979 private void scheduleTimeoutLocked(ToastRecord r)
2981 mHandler.removeCallbacksAndMessages(r);
2982 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
2983 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
2984 mHandler.sendMessageDelayed(m, delay);
2987 private void handleTimeout(ToastRecord record)
2989 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
2990 synchronized (mToastQueue) {
2991 int index = indexOfToastLocked(record.pkg, record.callback);
2993 cancelToastLocked(index);
2998 // lock on mToastQueue
2999 int indexOfToastLocked(String pkg, ITransientNotification callback)
3001 IBinder cbak = callback.asBinder();
3002 ArrayList<ToastRecord> list = mToastQueue;
3003 int len = list.size();
3004 for (int i=0; i<len; i++) {
3005 ToastRecord r = list.get(i);
3006 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
3013 // lock on mToastQueue
3014 void keepProcessAliveLocked(int pid)
3016 int toastCount = 0; // toasts from this pid
3017 ArrayList<ToastRecord> list = mToastQueue;
3018 int N = list.size();
3019 for (int i=0; i<N; i++) {
3020 ToastRecord r = list.get(i);
3026 mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
3027 } catch (RemoteException e) {
3028 // Shouldn't happen.
3032 private void handleRankingReconsideration(Message message) {
3033 if (!(message.obj instanceof RankingReconsideration)) return;
3034 RankingReconsideration recon = (RankingReconsideration) message.obj;
3037 synchronized (mNotificationList) {
3038 final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
3039 if (record == null) {
3042 int indexBefore = findNotificationRecordIndexLocked(record);
3043 boolean interceptBefore = record.isIntercepted();
3044 int visibilityBefore = record.getPackageVisibilityOverride();
3045 recon.applyChangesLocked(record);
3046 applyZenModeLocked(record);
3047 mRankingHelper.sort(mNotificationList);
3048 int indexAfter = findNotificationRecordIndexLocked(record);
3049 boolean interceptAfter = record.isIntercepted();
3050 int visibilityAfter = record.getPackageVisibilityOverride();
3051 changed = indexBefore != indexAfter || interceptBefore != interceptAfter
3052 || visibilityBefore != visibilityAfter;
3053 if (interceptBefore && !interceptAfter) {
3054 buzzBeepBlinkLocked(record);
3058 scheduleSendRankingUpdate();
3062 private void handleRankingSort() {
3063 synchronized (mNotificationList) {
3064 final int N = mNotificationList.size();
3065 ArrayList<String> orderBefore = new ArrayList<String>(N);
3066 ArrayList<String> groupOverrideBefore = new ArrayList<>(N);
3067 int[] visibilities = new int[N];
3068 int[] importances = new int[N];
3069 for (int i = 0; i < N; i++) {
3070 final NotificationRecord r = mNotificationList.get(i);
3071 orderBefore.add(r.getKey());
3072 groupOverrideBefore.add(r.sbn.getGroupKey());
3073 visibilities[i] = r.getPackageVisibilityOverride();
3074 importances[i] = r.getImportance();
3075 mRankingHelper.extractSignals(r);
3077 mRankingHelper.sort(mNotificationList);
3078 for (int i = 0; i < N; i++) {
3079 final NotificationRecord r = mNotificationList.get(i);
3080 if (!orderBefore.get(i).equals(r.getKey())
3081 || visibilities[i] != r.getPackageVisibilityOverride()
3082 || importances[i] != r.getImportance()
3083 || !groupOverrideBefore.get(i).equals(r.sbn.getGroupKey())) {
3084 scheduleSendRankingUpdate();
3091 // let zen mode evaluate this record
3092 private void applyZenModeLocked(NotificationRecord record) {
3093 record.setIntercepted(mZenModeHelper.shouldIntercept(record));
3094 if (record.isIntercepted()) {
3095 int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
3096 ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
3097 | (mZenModeHelper.shouldSuppressWhenScreenOn()
3098 ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
3099 record.setSuppressedVisualEffects(suppressed);
3103 // lock on mNotificationList
3104 private int findNotificationRecordIndexLocked(NotificationRecord target) {
3105 return mRankingHelper.indexOf(mNotificationList, target);
3108 private void scheduleSendRankingUpdate() {
3109 if (!mHandler.hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
3110 Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE);
3111 mHandler.sendMessage(m);
3115 private void handleSendRankingUpdate() {
3116 synchronized (mNotificationList) {
3117 mListeners.notifyRankingUpdateLocked();
3121 private void scheduleListenerHintsChanged(int state) {
3122 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
3123 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
3126 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
3127 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
3128 mHandler.obtainMessage(
3129 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
3130 listenerInterruptionFilter,
3134 private void handleListenerHintsChanged(int hints) {
3135 synchronized (mNotificationList) {
3136 mListeners.notifyListenerHintsChangedLocked(hints);
3140 private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
3141 synchronized (mNotificationList) {
3142 mListeners.notifyInterruptionFilterChanged(interruptionFilter);
3146 private final class WorkerHandler extends Handler
3149 public void handleMessage(Message msg)
3153 case MESSAGE_TIMEOUT:
3154 handleTimeout((ToastRecord)msg.obj);
3156 case MESSAGE_SAVE_POLICY_FILE:
3157 handleSavePolicyFile();
3159 case MESSAGE_SEND_RANKING_UPDATE:
3160 handleSendRankingUpdate();
3162 case MESSAGE_LISTENER_HINTS_CHANGED:
3163 handleListenerHintsChanged(msg.arg1);
3165 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
3166 handleListenerInterruptionFilterChanged(msg.arg1);
3173 private final class RankingHandlerWorker extends Handler implements RankingHandler
3175 public RankingHandlerWorker(Looper looper) {
3180 public void handleMessage(Message msg) {
3182 case MESSAGE_RECONSIDER_RANKING:
3183 handleRankingReconsideration(msg);
3185 case MESSAGE_RANKING_SORT:
3186 handleRankingSort();
3191 public void requestSort() {
3192 removeMessages(MESSAGE_RANKING_SORT);
3193 sendEmptyMessage(MESSAGE_RANKING_SORT);
3196 public void requestReconsideration(RankingReconsideration recon) {
3197 Message m = Message.obtain(this,
3198 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
3199 long delay = recon.getDelay(TimeUnit.MILLISECONDS);
3200 sendMessageDelayed(m, delay);
3205 // ============================================================================
3206 static int clamp(int x, int low, int high) {
3207 return (x < low) ? low : ((x > high) ? high : x);
3210 void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
3211 AccessibilityManager manager = AccessibilityManager.getInstance(getContext());
3212 if (!manager.isEnabled()) {
3216 AccessibilityEvent event =
3217 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
3218 event.setPackageName(packageName);
3219 event.setClassName(Notification.class.getName());
3220 event.setParcelableData(notification);
3221 CharSequence tickerText = notification.tickerText;
3222 if (!TextUtils.isEmpty(tickerText)) {
3223 event.getText().add(tickerText);
3226 manager.sendAccessibilityEvent(event);
3229 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) {
3232 if (r.getNotification().deleteIntent != null) {
3234 r.getNotification().deleteIntent.send();
3235 } catch (PendingIntent.CanceledException ex) {
3236 // do nothing - there's no relevant way to recover, and
3237 // no reason to let this propagate
3238 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
3244 if (r.getNotification().getSmallIcon() != null) {
3245 r.isCanceled = true;
3246 mListeners.notifyRemovedLocked(r.sbn);
3249 final String canceledKey = r.getKey();
3252 if (canceledKey.equals(mSoundNotificationKey)) {
3253 mSoundNotificationKey = null;
3254 final long identity = Binder.clearCallingIdentity();
3256 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
3257 if (player != null) {
3260 } catch (RemoteException e) {
3262 Binder.restoreCallingIdentity(identity);
3267 if (canceledKey.equals(mVibrateNotificationKey)) {
3268 mVibrateNotificationKey = null;
3269 long identity = Binder.clearCallingIdentity();
3274 Binder.restoreCallingIdentity(identity);
3279 mLights.remove(canceledKey);
3281 // Record usage stats
3282 // TODO: add unbundling stats?
3284 case REASON_DELEGATE_CANCEL:
3285 case REASON_DELEGATE_CANCEL_ALL:
3286 case REASON_LISTENER_CANCEL:
3287 case REASON_LISTENER_CANCEL_ALL:
3288 mUsageStats.registerDismissedByUser(r);
3290 case REASON_APP_CANCEL:
3291 case REASON_APP_CANCEL_ALL:
3292 mUsageStats.registerRemovedByApp(r);
3296 mNotificationsByKey.remove(r.sbn.getKey());
3297 String groupKey = r.getGroupKey();
3298 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
3299 if (groupSummary != null && groupSummary.getKey().equals(r.getKey())) {
3300 mSummaryByGroupKey.remove(groupKey);
3302 final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
3303 if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
3304 summaries.remove(r.sbn.getPackageName());
3307 // Save it for users of getHistoricalNotifications()
3308 mArchive.record(r.sbn);
3310 final long now = System.currentTimeMillis();
3311 EventLogTags.writeNotificationCanceled(canceledKey, reason,
3312 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
3316 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
3317 * and none of the {@code mustNotHaveFlags}.
3319 void cancelNotification(final int callingUid, final int callingPid,
3320 final String pkg, final String tag, final int id,
3321 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
3322 final int userId, final int reason, final ManagedServiceInfo listener) {
3323 // In enqueueNotificationInternal notifications are added by scheduling the
3324 // work on the worker handler. Hence, we also schedule the cancel on this
3325 // handler to avoid a scenario where an add notification call followed by a
3326 // remove notification call ends up in not removing the notification.
3327 mHandler.post(new Runnable() {
3330 String listenerName = listener == null ? null : listener.component.toShortString();
3331 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
3332 userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
3334 synchronized (mNotificationList) {
3335 int index = indexOfNotificationLocked(pkg, tag, id, userId);
3337 NotificationRecord r = mNotificationList.get(index);
3339 // Ideally we'd do this in the caller of this method. However, that would
3340 // require the caller to also find the notification.
3341 if (reason == REASON_DELEGATE_CLICK) {
3342 mUsageStats.registerClickedByUser(r);
3345 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
3348 if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
3352 mNotificationList.remove(index);
3354 cancelNotificationLocked(r, sendDelete, reason);
3355 cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
3356 REASON_GROUP_SUMMARY_CANCELED);
3357 updateLightsLocked();
3365 * Determine whether the userId applies to the notification in question, either because
3366 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
3368 private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
3370 // looking for USER_ALL notifications? match everything
3371 userId == UserHandle.USER_ALL
3372 // a notification sent to USER_ALL matches any query
3373 || r.getUserId() == UserHandle.USER_ALL
3374 // an exact user match
3375 || r.getUserId() == userId;
3379 * Determine whether the userId applies to the notification in question, either because
3380 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
3381 * because it matches one of the users profiles.
3383 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
3384 return notificationMatchesUserId(r, userId)
3385 || mUserProfiles.isCurrentProfile(r.getUserId());
3389 * Cancels all notifications from a given package that have all of the
3390 * {@code mustHaveFlags}.
3392 boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags,
3393 int mustNotHaveFlags, boolean doit, int userId, int reason,
3394 ManagedServiceInfo listener) {
3395 String listenerName = listener == null ? null : listener.component.toShortString();
3396 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
3397 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
3400 synchronized (mNotificationList) {
3401 final int N = mNotificationList.size();
3402 ArrayList<NotificationRecord> canceledNotifications = null;
3403 for (int i = N-1; i >= 0; --i) {
3404 NotificationRecord r = mNotificationList.get(i);
3405 if (!notificationMatchesUserId(r, userId)) {
3408 // Don't remove notifications to all, if there's no package name specified
3409 if (r.getUserId() == UserHandle.USER_ALL && pkg == null) {
3412 if ((r.getFlags() & mustHaveFlags) != mustHaveFlags) {
3415 if ((r.getFlags() & mustNotHaveFlags) != 0) {
3418 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
3421 if (canceledNotifications == null) {
3422 canceledNotifications = new ArrayList<>();
3424 canceledNotifications.add(r);
3428 mNotificationList.remove(i);
3429 cancelNotificationLocked(r, false, reason);
3431 if (doit && canceledNotifications != null) {
3432 final int M = canceledNotifications.size();
3433 for (int i = 0; i < M; i++) {
3434 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
3435 listenerName, REASON_GROUP_SUMMARY_CANCELED);
3438 if (canceledNotifications != null) {
3439 updateLightsLocked();
3441 return canceledNotifications != null;
3445 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
3446 ManagedServiceInfo listener, boolean includeCurrentProfiles) {
3447 String listenerName = listener == null ? null : listener.component.toShortString();
3448 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
3449 null, userId, 0, 0, reason, listenerName);
3451 ArrayList<NotificationRecord> canceledNotifications = null;
3452 final int N = mNotificationList.size();
3453 for (int i=N-1; i>=0; i--) {
3454 NotificationRecord r = mNotificationList.get(i);
3455 if (includeCurrentProfiles) {
3456 if (!notificationMatchesCurrentProfiles(r, userId)) {
3460 if (!notificationMatchesUserId(r, userId)) {
3465 if ((r.getFlags() & (Notification.FLAG_ONGOING_EVENT
3466 | Notification.FLAG_NO_CLEAR)) == 0) {
3467 mNotificationList.remove(i);
3468 cancelNotificationLocked(r, true, reason);
3469 // Make a note so we can cancel children later.
3470 if (canceledNotifications == null) {
3471 canceledNotifications = new ArrayList<>();
3473 canceledNotifications.add(r);
3476 int M = canceledNotifications != null ? canceledNotifications.size() : 0;
3477 for (int i = 0; i < M; i++) {
3478 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
3479 listenerName, REASON_GROUP_SUMMARY_CANCELED);
3481 updateLightsLocked();
3484 // Warning: The caller is responsible for invoking updateLightsLocked().
3485 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
3486 String listenerName, int reason) {
3487 Notification n = r.getNotification();
3488 if (!n.isGroupSummary()) {
3492 String pkg = r.sbn.getPackageName();
3493 int userId = r.getUserId();
3496 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
3500 final int N = mNotificationList.size();
3501 for (int i = N - 1; i >= 0; i--) {
3502 NotificationRecord childR = mNotificationList.get(i);
3503 StatusBarNotification childSbn = childR.sbn;
3504 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
3505 childR.getGroupKey().equals(r.getGroupKey())) {
3506 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
3507 childSbn.getTag(), userId, 0, 0, reason, listenerName);
3508 mNotificationList.remove(i);
3509 cancelNotificationLocked(childR, false, reason);
3514 // lock on mNotificationList
3515 void updateLightsLocked()
3517 // handle notification lights
3518 NotificationRecord ledNotification = null;
3519 while (ledNotification == null && !mLights.isEmpty()) {
3520 final String owner = mLights.get(mLights.size() - 1);
3521 ledNotification = mNotificationsByKey.get(owner);
3522 if (ledNotification == null) {
3523 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
3524 mLights.remove(owner);
3528 // Don't flash while we are in a call or screen is on
3529 if (ledNotification == null || mInCall || mScreenOn) {
3530 mNotificationLight.turnOff();
3531 if (mStatusBar != null) {
3532 mStatusBar.notificationLightOff();
3535 final Notification ledno = ledNotification.sbn.getNotification();
3536 int ledARGB = ledno.ledARGB;
3537 int ledOnMS = ledno.ledOnMS;
3538 int ledOffMS = ledno.ledOffMS;
3539 if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0) {
3540 ledARGB = mDefaultNotificationColor;
3541 ledOnMS = mDefaultNotificationLedOn;
3542 ledOffMS = mDefaultNotificationLedOff;
3544 if (mNotificationPulseEnabled) {
3546 mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED,
3549 if (mStatusBar != null) {
3550 // let SystemUI make an independent decision
3551 mStatusBar.notificationLightPulse(ledARGB, ledOnMS, ledOffMS);
3556 // lock on mNotificationList
3557 int indexOfNotificationLocked(String pkg, String tag, int id, int userId)
3559 ArrayList<NotificationRecord> list = mNotificationList;
3560 final int len = list.size();
3561 for (int i=0; i<len; i++) {
3562 NotificationRecord r = list.get(i);
3563 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
3564 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
3571 // lock on mNotificationList
3572 int indexOfNotificationLocked(String key) {
3573 final int N = mNotificationList.size();
3574 for (int i = 0; i < N; i++) {
3575 if (key.equals(mNotificationList.get(i).getKey())) {
3582 private void updateNotificationPulse() {
3583 synchronized (mNotificationList) {
3584 updateLightsLocked();
3588 private static boolean isUidSystem(int uid) {
3589 final int appid = UserHandle.getAppId(uid);
3590 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
3593 private static boolean isCallerSystem() {
3594 return isUidSystem(Binder.getCallingUid());
3597 private static void checkCallerIsSystem() {
3598 if (isCallerSystem()) {
3601 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
3604 private static void checkCallerIsSystemOrSameApp(String pkg) {
3605 if (isCallerSystem()) {
3608 final int uid = Binder.getCallingUid();
3610 ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
3611 pkg, 0, UserHandle.getCallingUserId());
3613 throw new SecurityException("Unknown package " + pkg);
3615 if (!UserHandle.isSameApp(ai.uid, uid)) {
3616 throw new SecurityException("Calling uid " + uid + " gave package"
3617 + pkg + " which is owned by uid " + ai.uid);
3619 } catch (RemoteException re) {
3620 throw new SecurityException("Unknown package " + pkg + "\n" + re);
3624 private static String callStateToString(int state) {
3626 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
3627 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
3628 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
3629 default: return "CALL_STATE_UNKNOWN_" + state;
3633 private void listenForCallState() {
3634 TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
3636 public void onCallStateChanged(int state, String incomingNumber) {
3637 if (mCallState == state) return;
3638 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
3641 }, PhoneStateListener.LISTEN_CALL_STATE);
3645 * Generates a NotificationRankingUpdate from 'sbns', considering only
3646 * notifications visible to the given listener.
3648 * <p>Caller must hold a lock on mNotificationList.</p>
3650 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
3651 final int N = mNotificationList.size();
3652 ArrayList<String> keys = new ArrayList<String>(N);
3653 ArrayList<String> interceptedKeys = new ArrayList<String>(N);
3654 ArrayList<Integer> importance = new ArrayList<>(N);
3655 Bundle overrideGroupKeys = new Bundle();
3656 Bundle visibilityOverrides = new Bundle();
3657 Bundle suppressedVisualEffects = new Bundle();
3658 Bundle explanation = new Bundle();
3659 for (int i = 0; i < N; i++) {
3660 NotificationRecord record = mNotificationList.get(i);
3661 if (!isVisibleToListener(record.sbn, info)) {
3664 final String key = record.sbn.getKey();
3666 importance.add(record.getImportance());
3667 if (record.getImportanceExplanation() != null) {
3668 explanation.putCharSequence(key, record.getImportanceExplanation());
3670 if (record.isIntercepted()) {
3671 interceptedKeys.add(key);
3674 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
3675 if (record.getPackageVisibilityOverride()
3676 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
3677 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
3679 overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
3681 final int M = keys.size();
3682 String[] keysAr = keys.toArray(new String[M]);
3683 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
3684 int[] importanceAr = new int[M];
3685 for (int i = 0; i < M; i++) {
3686 importanceAr[i] = importance.get(i);
3688 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
3689 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys);
3692 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
3693 if (!listener.enabledAndUserMatches(sbn.getUserId())) {
3696 // TODO: remove this for older listeners.
3700 private boolean isPackageSuspendedForUser(String pkg, int uid) {
3701 int userId = UserHandle.getUserId(uid);
3703 return AppGlobals.getPackageManager().isPackageSuspendedForUser(pkg, userId);
3704 } catch (RemoteException re) {
3705 throw new SecurityException("Could not talk to package manager service");
3706 } catch (IllegalArgumentException ex) {
3707 // Package not found.
3712 private class TrimCache {
3713 StatusBarNotification heavy;
3714 StatusBarNotification sbnClone;
3715 StatusBarNotification sbnCloneLight;
3717 TrimCache(StatusBarNotification sbn) {
3721 StatusBarNotification ForListener(ManagedServiceInfo info) {
3722 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
3723 if (sbnCloneLight == null) {
3724 sbnCloneLight = heavy.cloneLight();
3726 return sbnCloneLight;
3728 if (sbnClone == null) {
3729 sbnClone = heavy.clone();
3736 public class NotificationRankers extends ManagedServices {
3738 public NotificationRankers() {
3739 super(getContext(), mHandler, mNotificationList, mUserProfiles);
3743 protected Config getConfig() {
3744 Config c = new Config();
3745 c.caption = "notification ranker service";
3746 c.serviceInterface = NotificationRankerService.SERVICE_INTERFACE;
3747 c.secureSettingName = null;
3748 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_RANKER_SERVICE;
3749 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
3750 c.clientLabel = R.string.notification_ranker_binding_label;
3755 protected IInterface asInterface(IBinder binder) {
3756 return INotificationListener.Stub.asInterface(binder);
3760 protected boolean checkType(IInterface service) {
3761 return service instanceof INotificationListener;
3765 protected void onServiceAdded(ManagedServiceInfo info) {
3766 mListeners.registerGuestService(info);
3770 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
3771 mListeners.unregisterService(removed.service, removed.userid);
3774 public void onNotificationEnqueued(final NotificationRecord r) {
3775 final StatusBarNotification sbn = r.sbn;
3776 TrimCache trimCache = new TrimCache(sbn);
3778 // mServices is the list inside ManagedServices of all the rankers,
3779 // There should be only one, but it's a list, so while we enforce
3780 // singularity elsewhere, we keep it general here, to avoid surprises.
3781 for (final ManagedServiceInfo info : NotificationRankers.this.mServices) {
3782 boolean sbnVisible = isVisibleToListener(sbn, info);
3787 final int importance = r.getImportance();
3788 final boolean fromUser = r.isImportanceFromUser();
3789 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
3790 mHandler.post(new Runnable() {
3793 notifyEnqueued(info, sbnToPost, importance, fromUser);
3799 private void notifyEnqueued(final ManagedServiceInfo info,
3800 final StatusBarNotification sbn, int importance, boolean fromUser) {
3801 final INotificationListener ranker = (INotificationListener) info.service;
3802 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
3804 ranker.onNotificationEnqueued(sbnHolder, importance, fromUser);
3805 } catch (RemoteException ex) {
3806 Log.e(TAG, "unable to notify ranker (enqueued): " + ranker, ex);
3810 public boolean isEnabled() {
3811 return !mServices.isEmpty();
3815 public void onUserSwitched(int user) {
3816 for (ManagedServiceInfo info : mServices) {
3817 unregisterService(info.service, info.userid);
3823 public void onPackagesChanged(boolean queryReplace, String[] pkgList) {
3824 if (DEBUG) Slog.d(TAG, "onPackagesChanged queryReplace=" + queryReplace
3825 + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList)));
3826 if (mRankerServicePackageName == null) {
3830 if (pkgList != null && (pkgList.length > 0)) {
3831 for (String pkgName : pkgList) {
3832 if (mRankerServicePackageName.equals(pkgName)) {
3839 protected void registerRanker() {
3840 // Find the updatable ranker and register it.
3841 if (mRankerServicePackageName == null) {
3842 Slog.w(TAG, "could not start ranker service: no package specified!");
3845 Set<ComponentName> rankerComponents = queryPackageForServices(
3846 mRankerServicePackageName, UserHandle.USER_SYSTEM);
3847 Iterator<ComponentName> iterator = rankerComponents.iterator();
3848 if (iterator.hasNext()) {
3849 ComponentName rankerComponent = iterator.next();
3850 if (iterator.hasNext()) {
3851 Slog.e(TAG, "found multiple ranker services:" + rankerComponents);
3853 registerSystemService(rankerComponent, UserHandle.USER_SYSTEM);
3856 Slog.w(TAG, "could not start ranker service: none found");
3861 public class NotificationListeners extends ManagedServices {
3863 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
3865 public NotificationListeners() {
3866 super(getContext(), mHandler, mNotificationList, mUserProfiles);
3870 protected Config getConfig() {
3871 Config c = new Config();
3872 c.caption = "notification listener";
3873 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
3874 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
3875 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
3876 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
3877 c.clientLabel = R.string.notification_listener_binding_label;
3882 protected IInterface asInterface(IBinder binder) {
3883 return INotificationListener.Stub.asInterface(binder);
3887 protected boolean checkType(IInterface service) {
3888 return service instanceof INotificationListener;
3892 public void onServiceAdded(ManagedServiceInfo info) {
3893 final INotificationListener listener = (INotificationListener) info.service;
3894 final NotificationRankingUpdate update;
3895 synchronized (mNotificationList) {
3896 update = makeRankingUpdateLocked(info);
3899 listener.onListenerConnected(update);
3900 } catch (RemoteException e) {
3906 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
3907 if (removeDisabledHints(removed)) {
3908 updateListenerHintsLocked();
3909 updateEffectsSuppressorLocked();
3911 mLightTrimListeners.remove(removed);
3914 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
3915 if (trim == TRIM_LIGHT) {
3916 mLightTrimListeners.add(info);
3918 mLightTrimListeners.remove(info);
3922 public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
3923 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
3927 * asynchronously notify all listeners about a new notification
3930 * Also takes care of removing a notification that has been visible to a listener before,
3931 * but isn't anymore.
3933 public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
3934 // Lazily initialized snapshots of the notification.
3935 TrimCache trimCache = new TrimCache(sbn);
3937 for (final ManagedServiceInfo info : mServices) {
3938 boolean sbnVisible = isVisibleToListener(sbn, info);
3939 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
3940 // This notification hasn't been and still isn't visible -> ignore.
3941 if (!oldSbnVisible && !sbnVisible) {
3944 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
3946 // This notification became invisible -> remove the old one.
3947 if (oldSbnVisible && !sbnVisible) {
3948 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
3949 mHandler.post(new Runnable() {
3952 notifyRemoved(info, oldSbnLightClone, update);
3958 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
3959 mHandler.post(new Runnable() {
3962 notifyPosted(info, sbnToPost, update);
3969 * asynchronously notify all listeners about a removed notification
3971 public void notifyRemovedLocked(StatusBarNotification sbn) {
3972 // make a copy in case changes are made to the underlying Notification object
3973 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
3975 final StatusBarNotification sbnLight = sbn.cloneLight();
3976 for (final ManagedServiceInfo info : mServices) {
3977 if (!isVisibleToListener(sbn, info)) {
3980 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
3981 mHandler.post(new Runnable() {
3984 notifyRemoved(info, sbnLight, update);
3991 * asynchronously notify all listeners about a reordering of notifications
3993 public void notifyRankingUpdateLocked() {
3994 for (final ManagedServiceInfo serviceInfo : mServices) {
3995 if (!serviceInfo.isEnabledForCurrentProfiles()) {
3998 final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
3999 mHandler.post(new Runnable() {
4002 notifyRankingUpdate(serviceInfo, update);
4008 public void notifyListenerHintsChangedLocked(final int hints) {
4009 for (final ManagedServiceInfo serviceInfo : mServices) {
4010 if (!serviceInfo.isEnabledForCurrentProfiles()) {
4013 mHandler.post(new Runnable() {
4016 notifyListenerHintsChanged(serviceInfo, hints);
4022 public void notifyInterruptionFilterChanged(final int interruptionFilter) {
4023 for (final ManagedServiceInfo serviceInfo : mServices) {
4024 if (!serviceInfo.isEnabledForCurrentProfiles()) {
4027 mHandler.post(new Runnable() {
4030 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
4036 private void notifyPosted(final ManagedServiceInfo info,
4037 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
4038 final INotificationListener listener = (INotificationListener)info.service;
4039 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
4041 listener.onNotificationPosted(sbnHolder, rankingUpdate);
4042 } catch (RemoteException ex) {
4043 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
4047 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
4048 NotificationRankingUpdate rankingUpdate) {
4049 if (!info.enabledAndUserMatches(sbn.getUserId())) {
4052 final INotificationListener listener = (INotificationListener) info.service;
4053 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
4055 listener.onNotificationRemoved(sbnHolder, rankingUpdate);
4056 } catch (RemoteException ex) {
4057 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
4061 private void notifyRankingUpdate(ManagedServiceInfo info,
4062 NotificationRankingUpdate rankingUpdate) {
4063 final INotificationListener listener = (INotificationListener) info.service;
4065 listener.onNotificationRankingUpdate(rankingUpdate);
4066 } catch (RemoteException ex) {
4067 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
4071 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
4072 final INotificationListener listener = (INotificationListener) info.service;
4074 listener.onListenerHintsChanged(hints);
4075 } catch (RemoteException ex) {
4076 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
4080 private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
4081 int interruptionFilter) {
4082 final INotificationListener listener = (INotificationListener) info.service;
4084 listener.onInterruptionFilterChanged(interruptionFilter);
4085 } catch (RemoteException ex) {
4086 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
4090 private boolean isListenerPackage(String packageName) {
4091 if (packageName == null) {
4094 // TODO: clean up locking object later
4095 synchronized (mNotificationList) {
4096 for (final ManagedServiceInfo serviceInfo : mServices) {
4097 if (packageName.equals(serviceInfo.component.getPackageName())) {
4106 public static final class DumpFilter {
4107 public boolean filtered = false;
4108 public String pkgFilter;
4111 public boolean stats;
4112 public boolean redact = true;
4114 public static DumpFilter parseFromArguments(String[] args) {
4115 final DumpFilter filter = new DumpFilter();
4116 for (int ai = 0; ai < args.length; ai++) {
4117 final String a = args[ai];
4118 if ("--noredact".equals(a) || "--reveal".equals(a)) {
4119 filter.redact = false;
4120 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
4121 if (ai < args.length-1) {
4123 filter.pkgFilter = args[ai].trim().toLowerCase();
4124 if (filter.pkgFilter.isEmpty()) {
4125 filter.pkgFilter = null;
4127 filter.filtered = true;
4130 } else if ("--zen".equals(a) || "zen".equals(a)) {
4131 filter.filtered = true;
4133 } else if ("--stats".equals(a)) {
4134 filter.stats = true;
4135 if (ai < args.length-1) {
4137 filter.since = Long.valueOf(args[ai]);
4146 public boolean matches(StatusBarNotification sbn) {
4147 if (!filtered) return true;
4148 return zen ? true : sbn != null
4149 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
4152 public boolean matches(ComponentName component) {
4153 if (!filtered) return true;
4154 return zen ? true : component != null && matches(component.getPackageName());
4157 public boolean matches(String pkg) {
4158 if (!filtered) return true;
4159 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
4163 public String toString() {
4164 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
4169 * Wrapper for a StatusBarNotification object that allows transfer across a oneway
4170 * binder without sending large amounts of data over a oneway transaction.
4172 private static final class StatusBarNotificationHolder
4173 extends IStatusBarNotificationHolder.Stub {
4174 private StatusBarNotification mValue;
4176 public StatusBarNotificationHolder(StatusBarNotification value) {
4180 /** Get the held value and clear it. This function should only be called once per holder */
4182 public StatusBarNotification get() {
4183 StatusBarNotification value = mValue;
4189 private final class PolicyAccess {
4190 private static final String SEPARATOR = ":";
4191 private final String[] PERM = {
4192 android.Manifest.permission.ACCESS_NOTIFICATION_POLICY
4195 public boolean isPackageGranted(String pkg) {
4196 return pkg != null && getGrantedPackages().contains(pkg);
4199 public void put(String pkg, boolean granted) {
4200 if (pkg == null) return;
4201 final ArraySet<String> pkgs = getGrantedPackages();
4204 changed = pkgs.add(pkg);
4206 changed = pkgs.remove(pkg);
4208 if (!changed) return;
4209 final String setting = TextUtils.join(SEPARATOR, pkgs);
4210 final int currentUser = ActivityManager.getCurrentUser();
4211 Settings.Secure.putStringForUser(getContext().getContentResolver(),
4212 Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
4215 getContext().sendBroadcastAsUser(new Intent(NotificationManager
4216 .ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
4218 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), new UserHandle(currentUser), null);
4221 public ArraySet<String> getGrantedPackages() {
4222 final ArraySet<String> pkgs = new ArraySet<>();
4224 long identity = Binder.clearCallingIdentity();
4226 final String setting = Settings.Secure.getStringForUser(
4227 getContext().getContentResolver(),
4228 Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
4229 ActivityManager.getCurrentUser());
4230 if (setting != null) {
4231 final String[] tokens = setting.split(SEPARATOR);
4232 for (int i = 0; i < tokens.length; i++) {
4233 String token = tokens[i];
4234 if (token != null) {
4235 token = token.trim();
4237 if (TextUtils.isEmpty(token)) {
4244 Binder.restoreCallingIdentity(identity);
4249 public String[] getRequestingPackages() throws RemoteException {
4250 final ParceledListSlice list = AppGlobals.getPackageManager()
4251 .getPackagesHoldingPermissions(PERM, 0 /*flags*/,
4252 ActivityManager.getCurrentUser());
4253 final List<PackageInfo> pkgs = list.getList();
4254 if (pkgs == null || pkgs.isEmpty()) return new String[0];
4255 final int N = pkgs.size();
4256 final String[] rt = new String[N];
4257 for (int i = 0; i < N; i++) {
4258 rt[i] = pkgs.get(i).packageName;