NotificationManagerService.java revision a1b79bfd7a15006a93da933695359765e0fee495
1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 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 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 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. 15 */ 16 17package com.android.server.notification; 18 19import static android.service.notification.NotificationRankerService.REASON_APP_CANCEL; 20import static android.service.notification.NotificationRankerService.REASON_APP_CANCEL_ALL; 21import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CANCEL; 22import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CANCEL_ALL; 23import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CLICK; 24import static android.service.notification.NotificationRankerService.REASON_DELEGATE_ERROR; 25import static android.service.notification.NotificationRankerService.REASON_GROUP_SUMMARY_CANCELED; 26import static android.service.notification.NotificationRankerService.REASON_LISTENER_CANCEL; 27import static android.service.notification.NotificationRankerService.REASON_LISTENER_CANCEL_ALL; 28import static android.service.notification.NotificationRankerService.REASON_PACKAGE_BANNED; 29import static android.service.notification.NotificationRankerService.REASON_PACKAGE_CHANGED; 30import static android.service.notification.NotificationRankerService.REASON_PACKAGE_SUSPENDED; 31import static android.service.notification.NotificationRankerService.REASON_PROFILE_TURNED_OFF; 32import static android.service.notification.NotificationRankerService.REASON_UNAUTOBUNDLED; 33import static android.service.notification.NotificationRankerService.REASON_USER_STOPPED; 34import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS; 35import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS; 36import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS; 37import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF; 38import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON; 39import static android.service.notification.NotificationListenerService.TRIM_FULL; 40import static android.service.notification.NotificationListenerService.TRIM_LIGHT; 41import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_DEFAULT; 42import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_NONE; 43 44import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; 45 46import android.Manifest; 47import android.annotation.Nullable; 48import android.app.ActivityManager; 49import android.app.ActivityManagerInternal; 50import android.app.ActivityManagerNative; 51import android.app.AppGlobals; 52import android.app.AppOpsManager; 53import android.app.AutomaticZenRule; 54import android.app.IActivityManager; 55import android.app.INotificationManager; 56import android.app.ITransientNotification; 57import android.app.Notification; 58import android.app.NotificationManager; 59import android.app.NotificationManager.Policy; 60import android.app.PendingIntent; 61import android.app.RemoteInput; 62import android.app.StatusBarManager; 63import android.app.backup.BackupManager; 64import android.app.usage.UsageEvents; 65import android.app.usage.UsageStatsManagerInternal; 66import android.content.BroadcastReceiver; 67import android.content.ComponentName; 68import android.content.ContentResolver; 69import android.content.Context; 70import android.content.IIntentSender; 71import android.content.Intent; 72import android.content.IntentFilter; 73import android.content.pm.ApplicationInfo; 74import android.content.pm.IPackageManager; 75import android.content.pm.PackageInfo; 76import android.content.pm.PackageManager; 77import android.content.pm.PackageManager.NameNotFoundException; 78import android.content.pm.ParceledListSlice; 79import android.content.pm.UserInfo; 80import android.content.res.Resources; 81import android.database.ContentObserver; 82import android.media.AudioAttributes; 83import android.media.AudioManager; 84import android.media.AudioManagerInternal; 85import android.media.AudioSystem; 86import android.media.IRingtonePlayer; 87import android.net.Uri; 88import android.os.Binder; 89import android.os.Bundle; 90import android.os.Environment; 91import android.os.Handler; 92import android.os.HandlerThread; 93import android.os.IBinder; 94import android.os.IInterface; 95import android.os.Looper; 96import android.os.Message; 97import android.os.Parcelable; 98import android.os.Process; 99import android.os.RemoteException; 100import android.os.SystemClock; 101import android.os.SystemProperties; 102import android.os.UserHandle; 103import android.os.UserManager; 104import android.os.Vibrator; 105import android.provider.Settings; 106import android.service.notification.Adjustment; 107import android.service.notification.Condition; 108import android.service.notification.IConditionProvider; 109import android.service.notification.INotificationListener; 110import android.service.notification.IStatusBarNotificationHolder; 111import android.service.notification.NotificationRankerService; 112import android.service.notification.NotificationListenerService; 113import android.service.notification.NotificationRankingUpdate; 114import android.service.notification.StatusBarNotification; 115import android.service.notification.ZenModeConfig; 116import android.telephony.PhoneStateListener; 117import android.telephony.TelephonyManager; 118import android.text.TextUtils; 119import android.util.ArrayMap; 120import android.util.ArraySet; 121import android.util.AtomicFile; 122import android.util.Log; 123import android.util.Slog; 124import android.util.SparseArray; 125import android.util.Xml; 126import android.view.accessibility.AccessibilityEvent; 127import android.view.accessibility.AccessibilityManager; 128import android.widget.Toast; 129 130import com.android.internal.R; 131import com.android.internal.annotations.VisibleForTesting; 132import com.android.internal.statusbar.NotificationVisibility; 133import com.android.internal.util.FastXmlSerializer; 134import com.android.internal.util.Preconditions; 135import com.android.server.DeviceIdleController; 136import com.android.server.EventLogTags; 137import com.android.server.LocalServices; 138import com.android.server.SystemService; 139import com.android.server.lights.Light; 140import com.android.server.lights.LightsManager; 141import com.android.server.notification.ManagedServices.ManagedServiceInfo; 142import com.android.server.statusbar.StatusBarManagerInternal; 143import com.android.server.vr.VrManagerInternal; 144import com.android.server.notification.ManagedServices.UserProfiles; 145 146import libcore.io.IoUtils; 147 148import org.json.JSONException; 149import org.json.JSONObject; 150import org.xmlpull.v1.XmlPullParser; 151import org.xmlpull.v1.XmlPullParserException; 152import org.xmlpull.v1.XmlSerializer; 153 154import java.io.ByteArrayInputStream; 155import java.io.ByteArrayOutputStream; 156import java.io.File; 157import java.io.FileDescriptor; 158import java.io.FileInputStream; 159import java.io.FileNotFoundException; 160import java.io.FileOutputStream; 161import java.io.IOException; 162import java.io.InputStream; 163import java.io.OutputStream; 164import java.io.PrintWriter; 165import java.nio.charset.StandardCharsets; 166import java.util.ArrayDeque; 167import java.util.ArrayList; 168import java.util.Arrays; 169import java.util.Iterator; 170import java.util.List; 171import java.util.Map; 172import java.util.Map.Entry; 173import java.util.Set; 174import java.util.concurrent.TimeUnit; 175 176/** {@hide} */ 177public class NotificationManagerService extends SystemService { 178 static final String TAG = "NotificationService"; 179 static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); 180 public static final boolean ENABLE_CHILD_NOTIFICATIONS 181 = SystemProperties.getBoolean("debug.child_notifs", true); 182 183 static final int MAX_PACKAGE_NOTIFICATIONS = 50; 184 static final float MAX_PACKAGE_ENQUEUE_RATE = 50f; 185 186 // message codes 187 static final int MESSAGE_TIMEOUT = 2; 188 static final int MESSAGE_SAVE_POLICY_FILE = 3; 189 static final int MESSAGE_SEND_RANKING_UPDATE = 4; 190 static final int MESSAGE_LISTENER_HINTS_CHANGED = 5; 191 static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6; 192 193 // ranking thread messages 194 private static final int MESSAGE_RECONSIDER_RANKING = 1000; 195 private static final int MESSAGE_RANKING_SORT = 1001; 196 197 static final int LONG_DELAY = 3500; // 3.5 seconds 198 static final int SHORT_DELAY = 2000; // 2 seconds 199 200 static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250}; 201 202 static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps 203 204 static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION; 205 206 static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true; 207 static final boolean ENABLE_BLOCKED_TOASTS = true; 208 209 // When #matchesCallFilter is called from the ringer, wait at most 210 // 3s to resolve the contacts. This timeout is required since 211 // ContactsProvider might take a long time to start up. 212 // 213 // Return STARRED_CONTACT when the timeout is hit in order to avoid 214 // missed calls in ZEN mode "Important". 215 static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000; 216 static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY = 217 ValidateNotificationPeople.STARRED_CONTACT; 218 219 /** notification_enqueue status value for a newly enqueued notification. */ 220 private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0; 221 222 /** notification_enqueue status value for an existing notification. */ 223 private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1; 224 225 /** notification_enqueue status value for an ignored notification. */ 226 private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2; 227 private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds 228 private String mRankerServicePackageName; 229 230 private IActivityManager mAm; 231 AudioManager mAudioManager; 232 AudioManagerInternal mAudioManagerInternal; 233 @Nullable StatusBarManagerInternal mStatusBar; 234 Vibrator mVibrator; 235 private VrManagerInternal mVrManagerInternal; 236 237 final IBinder mForegroundToken = new Binder(); 238 private Handler mHandler; 239 private final HandlerThread mRankingThread = new HandlerThread("ranker", 240 Process.THREAD_PRIORITY_BACKGROUND); 241 242 private Light mNotificationLight; 243 Light mAttentionLight; 244 private int mDefaultNotificationColor; 245 private int mDefaultNotificationLedOn; 246 247 private int mDefaultNotificationLedOff; 248 private long[] mDefaultVibrationPattern; 249 250 private long[] mFallbackVibrationPattern; 251 private boolean mUseAttentionLight; 252 boolean mSystemReady; 253 254 private boolean mDisableNotificationEffects; 255 private int mCallState; 256 private String mSoundNotificationKey; 257 private String mVibrateNotificationKey; 258 259 private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects = 260 new SparseArray<ArraySet<ManagedServiceInfo>>(); 261 private List<ComponentName> mEffectsSuppressors = new ArrayList<ComponentName>(); 262 private int mListenerHints; // right now, all hints are global 263 private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN; 264 265 // for enabling and disabling notification pulse behavior 266 private boolean mScreenOn = true; 267 private boolean mInCall = false; 268 private boolean mNotificationPulseEnabled; 269 270 // used as a mutex for access to all active notifications & listeners 271 final ArrayList<NotificationRecord> mNotificationList = 272 new ArrayList<NotificationRecord>(); 273 final ArrayMap<String, NotificationRecord> mNotificationsByKey = 274 new ArrayMap<String, NotificationRecord>(); 275 final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>(); 276 final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>(); 277 final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>(); 278 final PolicyAccess mPolicyAccess = new PolicyAccess(); 279 280 // The last key in this list owns the hardware. 281 ArrayList<String> mLights = new ArrayList<>(); 282 283 private AppOpsManager mAppOps; 284 private UsageStatsManagerInternal mAppUsageStats; 285 286 private Archive mArchive; 287 288 // Persistent storage for notification policy 289 private AtomicFile mPolicyFile; 290 291 private static final int DB_VERSION = 1; 292 293 private static final String TAG_NOTIFICATION_POLICY = "notification-policy"; 294 private static final String ATTR_VERSION = "version"; 295 296 private RankingHelper mRankingHelper; 297 298 private final UserProfiles mUserProfiles = new UserProfiles(); 299 private NotificationListeners mListeners; 300 private NotificationRankers mRankerServices; 301 private ConditionProviders mConditionProviders; 302 private NotificationUsageStats mUsageStats; 303 304 private static final int MY_UID = Process.myUid(); 305 private static final int MY_PID = Process.myPid(); 306 private RankingHandler mRankingHandler; 307 private long mLastOverRateLogTime; 308 309 private static class Archive { 310 final int mBufferSize; 311 final ArrayDeque<StatusBarNotification> mBuffer; 312 313 public Archive(int size) { 314 mBufferSize = size; 315 mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize); 316 } 317 318 public String toString() { 319 final StringBuilder sb = new StringBuilder(); 320 final int N = mBuffer.size(); 321 sb.append("Archive ("); 322 sb.append(N); 323 sb.append(" notification"); 324 sb.append((N==1)?")":"s)"); 325 return sb.toString(); 326 } 327 328 public void record(StatusBarNotification nr) { 329 if (mBuffer.size() == mBufferSize) { 330 mBuffer.removeFirst(); 331 } 332 333 // We don't want to store the heavy bits of the notification in the archive, 334 // but other clients in the system process might be using the object, so we 335 // store a (lightened) copy. 336 mBuffer.addLast(nr.cloneLight()); 337 } 338 339 public Iterator<StatusBarNotification> descendingIterator() { 340 return mBuffer.descendingIterator(); 341 } 342 343 public StatusBarNotification[] getArray(int count) { 344 if (count == 0) count = mBufferSize; 345 final StatusBarNotification[] a 346 = new StatusBarNotification[Math.min(count, mBuffer.size())]; 347 Iterator<StatusBarNotification> iter = descendingIterator(); 348 int i=0; 349 while (iter.hasNext() && i < count) { 350 a[i++] = iter.next(); 351 } 352 return a; 353 } 354 355 } 356 357 private void readPolicyXml(InputStream stream, boolean forRestore) 358 throws XmlPullParserException, NumberFormatException, IOException { 359 final XmlPullParser parser = Xml.newPullParser(); 360 parser.setInput(stream, StandardCharsets.UTF_8.name()); 361 362 while (parser.next() != END_DOCUMENT) { 363 mZenModeHelper.readXml(parser, forRestore); 364 mRankingHelper.readXml(parser, forRestore); 365 } 366 } 367 368 private void loadPolicyFile() { 369 if (DBG) Slog.d(TAG, "loadPolicyFile"); 370 synchronized(mPolicyFile) { 371 372 FileInputStream infile = null; 373 try { 374 infile = mPolicyFile.openRead(); 375 readPolicyXml(infile, false /*forRestore*/); 376 } catch (FileNotFoundException e) { 377 // No data yet 378 } catch (IOException e) { 379 Log.wtf(TAG, "Unable to read notification policy", e); 380 } catch (NumberFormatException e) { 381 Log.wtf(TAG, "Unable to parse notification policy", e); 382 } catch (XmlPullParserException e) { 383 Log.wtf(TAG, "Unable to parse notification policy", e); 384 } finally { 385 IoUtils.closeQuietly(infile); 386 } 387 } 388 } 389 390 public void savePolicyFile() { 391 mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE); 392 mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE); 393 } 394 395 private void handleSavePolicyFile() { 396 if (DBG) Slog.d(TAG, "handleSavePolicyFile"); 397 synchronized (mPolicyFile) { 398 final FileOutputStream stream; 399 try { 400 stream = mPolicyFile.startWrite(); 401 } catch (IOException e) { 402 Slog.w(TAG, "Failed to save policy file", e); 403 return; 404 } 405 406 try { 407 writePolicyXml(stream, false /*forBackup*/); 408 mPolicyFile.finishWrite(stream); 409 } catch (IOException e) { 410 Slog.w(TAG, "Failed to save policy file, restoring backup", e); 411 mPolicyFile.failWrite(stream); 412 } 413 } 414 BackupManager.dataChanged(getContext().getPackageName()); 415 } 416 417 private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException { 418 final XmlSerializer out = new FastXmlSerializer(); 419 out.setOutput(stream, StandardCharsets.UTF_8.name()); 420 out.startDocument(null, true); 421 out.startTag(null, TAG_NOTIFICATION_POLICY); 422 out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION)); 423 mZenModeHelper.writeXml(out, forBackup); 424 mRankingHelper.writeXml(out, forBackup); 425 out.endTag(null, TAG_NOTIFICATION_POLICY); 426 out.endDocument(); 427 } 428 429 /** Use this when you actually want to post a notification or toast. 430 * 431 * Unchecked. Not exposed via Binder, but can be called in the course of enqueue*(). 432 */ 433 private boolean noteNotificationOp(String pkg, int uid) { 434 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg) 435 != AppOpsManager.MODE_ALLOWED) { 436 Slog.v(TAG, "notifications are disabled by AppOps for " + pkg); 437 return false; 438 } 439 return true; 440 } 441 442 /** Use this to check if a package can post a notification or toast. */ 443 private boolean checkNotificationOp(String pkg, int uid) { 444 return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg) 445 == AppOpsManager.MODE_ALLOWED && !isPackageSuspendedForUser(pkg, uid); 446 } 447 448 private static final class ToastRecord 449 { 450 final int pid; 451 final String pkg; 452 final ITransientNotification callback; 453 int duration; 454 455 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration) 456 { 457 this.pid = pid; 458 this.pkg = pkg; 459 this.callback = callback; 460 this.duration = duration; 461 } 462 463 void update(int duration) { 464 this.duration = duration; 465 } 466 467 void dump(PrintWriter pw, String prefix, DumpFilter filter) { 468 if (filter != null && !filter.matches(pkg)) return; 469 pw.println(prefix + this); 470 } 471 472 @Override 473 public final String toString() 474 { 475 return "ToastRecord{" 476 + Integer.toHexString(System.identityHashCode(this)) 477 + " pkg=" + pkg 478 + " callback=" + callback 479 + " duration=" + duration; 480 } 481 } 482 483 private final NotificationDelegate mNotificationDelegate = new NotificationDelegate() { 484 485 @Override 486 public void onSetDisabled(int status) { 487 synchronized (mNotificationList) { 488 mDisableNotificationEffects = 489 (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0; 490 if (disableNotificationEffects(null) != null) { 491 // cancel whatever's going on 492 long identity = Binder.clearCallingIdentity(); 493 try { 494 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 495 if (player != null) { 496 player.stopAsync(); 497 } 498 } catch (RemoteException e) { 499 } finally { 500 Binder.restoreCallingIdentity(identity); 501 } 502 503 identity = Binder.clearCallingIdentity(); 504 try { 505 mVibrator.cancel(); 506 } finally { 507 Binder.restoreCallingIdentity(identity); 508 } 509 } 510 } 511 } 512 513 @Override 514 public void onClearAll(int callingUid, int callingPid, int userId) { 515 synchronized (mNotificationList) { 516 cancelAllLocked(callingUid, callingPid, userId, REASON_DELEGATE_CANCEL_ALL, null, 517 /*includeCurrentProfiles*/ true); 518 } 519 } 520 521 @Override 522 public void onNotificationClick(int callingUid, int callingPid, String key) { 523 synchronized (mNotificationList) { 524 NotificationRecord r = mNotificationsByKey.get(key); 525 if (r == null) { 526 Log.w(TAG, "No notification with key: " + key); 527 return; 528 } 529 final long now = System.currentTimeMillis(); 530 EventLogTags.writeNotificationClicked(key, 531 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now)); 532 533 StatusBarNotification sbn = r.sbn; 534 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(), 535 sbn.getId(), Notification.FLAG_AUTO_CANCEL, 536 Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(), 537 REASON_DELEGATE_CLICK, null); 538 } 539 } 540 541 @Override 542 public void onNotificationActionClick(int callingUid, int callingPid, String key, 543 int actionIndex) { 544 synchronized (mNotificationList) { 545 NotificationRecord r = mNotificationsByKey.get(key); 546 if (r == null) { 547 Log.w(TAG, "No notification with key: " + key); 548 return; 549 } 550 final long now = System.currentTimeMillis(); 551 EventLogTags.writeNotificationActionClicked(key, actionIndex, 552 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now)); 553 // TODO: Log action click via UsageStats. 554 } 555 } 556 557 @Override 558 public void onNotificationClear(int callingUid, int callingPid, 559 String pkg, String tag, int id, int userId) { 560 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 561 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE, 562 true, userId, REASON_DELEGATE_CANCEL, null); 563 } 564 565 @Override 566 public void onPanelRevealed(boolean clearEffects, int items) { 567 EventLogTags.writeNotificationPanelRevealed(items); 568 if (clearEffects) { 569 clearEffects(); 570 } 571 } 572 573 @Override 574 public void onPanelHidden() { 575 EventLogTags.writeNotificationPanelHidden(); 576 } 577 578 @Override 579 public void clearEffects() { 580 synchronized (mNotificationList) { 581 if (DBG) Slog.d(TAG, "clearEffects"); 582 clearSoundLocked(); 583 clearVibrateLocked(); 584 clearLightsLocked(); 585 } 586 } 587 588 @Override 589 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id, 590 int uid, int initialPid, String message, int userId) { 591 Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id 592 + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")"); 593 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId, 594 REASON_DELEGATE_ERROR, null); 595 long ident = Binder.clearCallingIdentity(); 596 try { 597 ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg, 598 "Bad notification posted from package " + pkg 599 + ": " + message); 600 } catch (RemoteException e) { 601 } 602 Binder.restoreCallingIdentity(ident); 603 } 604 605 @Override 606 public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys, 607 NotificationVisibility[] noLongerVisibleKeys) { 608 synchronized (mNotificationList) { 609 for (NotificationVisibility nv : newlyVisibleKeys) { 610 NotificationRecord r = mNotificationsByKey.get(nv.key); 611 if (r == null) continue; 612 r.setVisibility(true, nv.rank); 613 nv.recycle(); 614 } 615 // Note that we might receive this event after notifications 616 // have already left the system, e.g. after dismissing from the 617 // shade. Hence not finding notifications in 618 // mNotificationsByKey is not an exceptional condition. 619 for (NotificationVisibility nv : noLongerVisibleKeys) { 620 NotificationRecord r = mNotificationsByKey.get(nv.key); 621 if (r == null) continue; 622 r.setVisibility(false, nv.rank); 623 nv.recycle(); 624 } 625 } 626 } 627 628 @Override 629 public void onNotificationExpansionChanged(String key, 630 boolean userAction, boolean expanded) { 631 synchronized (mNotificationList) { 632 NotificationRecord r = mNotificationsByKey.get(key); 633 if (r != null) { 634 r.stats.onExpansionChanged(userAction, expanded); 635 final long now = System.currentTimeMillis(); 636 EventLogTags.writeNotificationExpansion(key, 637 userAction ? 1 : 0, expanded ? 1 : 0, 638 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now)); 639 } 640 } 641 } 642 }; 643 644 private void clearSoundLocked() { 645 mSoundNotificationKey = null; 646 long identity = Binder.clearCallingIdentity(); 647 try { 648 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 649 if (player != null) { 650 player.stopAsync(); 651 } 652 } catch (RemoteException e) { 653 } finally { 654 Binder.restoreCallingIdentity(identity); 655 } 656 } 657 658 private void clearVibrateLocked() { 659 mVibrateNotificationKey = null; 660 long identity = Binder.clearCallingIdentity(); 661 try { 662 mVibrator.cancel(); 663 } finally { 664 Binder.restoreCallingIdentity(identity); 665 } 666 } 667 668 private void clearLightsLocked() { 669 // light 670 mLights.clear(); 671 updateLightsLocked(); 672 } 673 674 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() { 675 @Override 676 public void onReceive(Context context, Intent intent) { 677 String action = intent.getAction(); 678 if (action == null) { 679 return; 680 } 681 682 boolean queryRestart = false; 683 boolean queryRemove = false; 684 boolean packageChanged = false; 685 boolean cancelNotifications = true; 686 int reason = REASON_PACKAGE_CHANGED; 687 688 if (action.equals(Intent.ACTION_PACKAGE_ADDED) 689 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED)) 690 || action.equals(Intent.ACTION_PACKAGE_RESTARTED) 691 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED)) 692 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART)) 693 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE) 694 || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) { 695 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 696 UserHandle.USER_ALL); 697 String pkgList[] = null; 698 boolean queryReplace = queryRemove && 699 intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); 700 if (DBG) Slog.i(TAG, "action=" + action + " queryReplace=" + queryReplace); 701 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { 702 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 703 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) { 704 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 705 reason = REASON_PACKAGE_SUSPENDED; 706 } else if (queryRestart) { 707 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES); 708 } else { 709 Uri uri = intent.getData(); 710 if (uri == null) { 711 return; 712 } 713 String pkgName = uri.getSchemeSpecificPart(); 714 if (pkgName == null) { 715 return; 716 } 717 if (packageChanged) { 718 // We cancel notifications for packages which have just been disabled 719 try { 720 final IPackageManager pm = AppGlobals.getPackageManager(); 721 final int enabled = pm.getApplicationEnabledSetting(pkgName, 722 changeUserId != UserHandle.USER_ALL ? changeUserId : 723 UserHandle.USER_SYSTEM); 724 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED 725 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { 726 cancelNotifications = false; 727 } 728 } catch (IllegalArgumentException e) { 729 // Package doesn't exist; probably racing with uninstall. 730 // cancelNotifications is already true, so nothing to do here. 731 if (DBG) { 732 Slog.i(TAG, "Exception trying to look up app enabled setting", e); 733 } 734 } catch (RemoteException e) { 735 // Failed to talk to PackageManagerService Should never happen! 736 } 737 } 738 pkgList = new String[]{pkgName}; 739 } 740 741 if (pkgList != null && (pkgList.length > 0)) { 742 for (String pkgName : pkgList) { 743 if (cancelNotifications) { 744 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart, 745 changeUserId, reason, null); 746 } 747 } 748 } 749 mListeners.onPackagesChanged(queryReplace, pkgList); 750 mRankerServices.onPackagesChanged(queryReplace, pkgList); 751 mConditionProviders.onPackagesChanged(queryReplace, pkgList); 752 mRankingHelper.onPackagesChanged(queryReplace, pkgList); 753 } 754 } 755 }; 756 757 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 758 @Override 759 public void onReceive(Context context, Intent intent) { 760 String action = intent.getAction(); 761 762 if (action.equals(Intent.ACTION_SCREEN_ON)) { 763 // Keep track of screen on/off state, but do not turn off the notification light 764 // until user passes through the lock screen or views the notification. 765 mScreenOn = true; 766 updateNotificationPulse(); 767 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 768 mScreenOn = false; 769 updateNotificationPulse(); 770 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) { 771 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK 772 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE)); 773 updateNotificationPulse(); 774 } else if (action.equals(Intent.ACTION_USER_STOPPED)) { 775 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 776 if (userHandle >= 0) { 777 cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle, 778 REASON_USER_STOPPED, null); 779 } 780 } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) { 781 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 782 if (userHandle >= 0) { 783 cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle, 784 REASON_PROFILE_TURNED_OFF, null); 785 } 786 } else if (action.equals(Intent.ACTION_USER_PRESENT)) { 787 // turn off LED when user passes through lock screen 788 mNotificationLight.turnOff(); 789 if (mStatusBar != null) { 790 mStatusBar.notificationLightOff(); 791 } 792 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) { 793 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); 794 // reload per-user settings 795 mSettingsObserver.update(null); 796 mUserProfiles.updateCache(context); 797 // Refresh managed services 798 mConditionProviders.onUserSwitched(user); 799 mListeners.onUserSwitched(user); 800 mRankerServices.onUserSwitched(user); 801 mZenModeHelper.onUserSwitched(user); 802 } else if (action.equals(Intent.ACTION_USER_ADDED)) { 803 mUserProfiles.updateCache(context); 804 } else if (action.equals(Intent.ACTION_USER_REMOVED)) { 805 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); 806 mZenModeHelper.onUserRemoved(user); 807 } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) { 808 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); 809 mConditionProviders.onUserUnlocked(user); 810 mListeners.onUserUnlocked(user); 811 mRankerServices.onUserUnlocked(user); 812 mZenModeHelper.onUserUnlocked(user); 813 } 814 } 815 }; 816 817 private final class SettingsObserver extends ContentObserver { 818 private final Uri NOTIFICATION_LIGHT_PULSE_URI 819 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE); 820 821 SettingsObserver(Handler handler) { 822 super(handler); 823 } 824 825 void observe() { 826 ContentResolver resolver = getContext().getContentResolver(); 827 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI, 828 false, this, UserHandle.USER_ALL); 829 update(null); 830 } 831 832 @Override public void onChange(boolean selfChange, Uri uri) { 833 update(uri); 834 } 835 836 public void update(Uri uri) { 837 ContentResolver resolver = getContext().getContentResolver(); 838 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) { 839 boolean pulseEnabled = Settings.System.getInt(resolver, 840 Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0; 841 if (mNotificationPulseEnabled != pulseEnabled) { 842 mNotificationPulseEnabled = pulseEnabled; 843 updateNotificationPulse(); 844 } 845 } 846 } 847 } 848 849 private SettingsObserver mSettingsObserver; 850 private ZenModeHelper mZenModeHelper; 851 852 private final Runnable mBuzzBeepBlinked = new Runnable() { 853 @Override 854 public void run() { 855 if (mStatusBar != null) { 856 mStatusBar.buzzBeepBlinked(); 857 } 858 } 859 }; 860 861 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) { 862 int[] ar = r.getIntArray(resid); 863 if (ar == null) { 864 return def; 865 } 866 final int len = ar.length > maxlen ? maxlen : ar.length; 867 long[] out = new long[len]; 868 for (int i=0; i<len; i++) { 869 out[i] = ar[i]; 870 } 871 return out; 872 } 873 874 public NotificationManagerService(Context context) { 875 super(context); 876 } 877 878 @VisibleForTesting 879 void setAudioManager(AudioManager audioMananger) { 880 mAudioManager = audioMananger; 881 } 882 883 @VisibleForTesting 884 void setVibrator(Vibrator vibrator) { 885 mVibrator = vibrator; 886 } 887 888 @VisibleForTesting 889 void setSystemReady(boolean systemReady) { 890 mSystemReady = systemReady; 891 } 892 893 @VisibleForTesting 894 void setHandler(Handler handler) { 895 mHandler = handler; 896 } 897 898 @Override 899 public void onStart() { 900 Resources resources = getContext().getResources(); 901 902 mAm = ActivityManagerNative.getDefault(); 903 mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE); 904 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE); 905 mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class); 906 907 // This is the package that contains the AOSP framework update. 908 mRankerServicePackageName = getContext().getPackageManager() 909 .getServicesSystemSharedLibraryPackageName(); 910 911 mHandler = new WorkerHandler(); 912 mRankingThread.start(); 913 String[] extractorNames; 914 try { 915 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors); 916 } catch (Resources.NotFoundException e) { 917 extractorNames = new String[0]; 918 } 919 mUsageStats = new NotificationUsageStats(getContext()); 920 mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper()); 921 mRankingHelper = new RankingHelper(getContext(), 922 mRankingHandler, 923 mUsageStats, 924 extractorNames); 925 mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles); 926 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders); 927 mZenModeHelper.addCallback(new ZenModeHelper.Callback() { 928 @Override 929 public void onConfigChanged() { 930 savePolicyFile(); 931 } 932 933 @Override 934 void onZenModeChanged() { 935 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED); 936 getContext().sendBroadcastAsUser( 937 new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL) 938 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT), 939 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS); 940 synchronized(mNotificationList) { 941 updateInterruptionFilterLocked(); 942 } 943 } 944 945 @Override 946 void onPolicyChanged() { 947 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED); 948 } 949 }); 950 final File systemDir = new File(Environment.getDataDirectory(), "system"); 951 mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml")); 952 953 syncBlockDb(); 954 955 // This is a MangedServices object that keeps track of the listeners. 956 mListeners = new NotificationListeners(); 957 958 // This is a MangedServices object that keeps track of the ranker. 959 mRankerServices = new NotificationRankers(); 960 // Find the updatable ranker and register it. 961 mRankerServices.registerRanker(); 962 963 mStatusBar = getLocalService(StatusBarManagerInternal.class); 964 if (mStatusBar != null) { 965 mStatusBar.setNotificationDelegate(mNotificationDelegate); 966 } 967 968 final LightsManager lights = getLocalService(LightsManager.class); 969 mNotificationLight = lights.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS); 970 mAttentionLight = lights.getLight(LightsManager.LIGHT_ID_ATTENTION); 971 972 mDefaultNotificationColor = resources.getColor( 973 R.color.config_defaultNotificationColor); 974 mDefaultNotificationLedOn = resources.getInteger( 975 R.integer.config_defaultNotificationLedOn); 976 mDefaultNotificationLedOff = resources.getInteger( 977 R.integer.config_defaultNotificationLedOff); 978 979 mDefaultVibrationPattern = getLongArray(resources, 980 R.array.config_defaultNotificationVibePattern, 981 VIBRATE_PATTERN_MAXLEN, 982 DEFAULT_VIBRATE_PATTERN); 983 984 mFallbackVibrationPattern = getLongArray(resources, 985 R.array.config_notificationFallbackVibePattern, 986 VIBRATE_PATTERN_MAXLEN, 987 DEFAULT_VIBRATE_PATTERN); 988 989 mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight); 990 991 // Don't start allowing notifications until the setup wizard has run once. 992 // After that, including subsequent boots, init with notifications turned on. 993 // This works on the first boot because the setup wizard will toggle this 994 // flag at least once and we'll go back to 0 after that. 995 if (0 == Settings.Global.getInt(getContext().getContentResolver(), 996 Settings.Global.DEVICE_PROVISIONED, 0)) { 997 mDisableNotificationEffects = true; 998 } 999 mZenModeHelper.initZenMode(); 1000 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter(); 1001 1002 mUserProfiles.updateCache(getContext()); 1003 listenForCallState(); 1004 1005 // register for various Intents 1006 IntentFilter filter = new IntentFilter(); 1007 filter.addAction(Intent.ACTION_SCREEN_ON); 1008 filter.addAction(Intent.ACTION_SCREEN_OFF); 1009 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); 1010 filter.addAction(Intent.ACTION_USER_PRESENT); 1011 filter.addAction(Intent.ACTION_USER_STOPPED); 1012 filter.addAction(Intent.ACTION_USER_SWITCHED); 1013 filter.addAction(Intent.ACTION_USER_ADDED); 1014 filter.addAction(Intent.ACTION_USER_REMOVED); 1015 filter.addAction(Intent.ACTION_USER_UNLOCKED); 1016 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE); 1017 getContext().registerReceiver(mIntentReceiver, filter); 1018 1019 IntentFilter pkgFilter = new IntentFilter(); 1020 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 1021 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 1022 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 1023 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED); 1024 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); 1025 pkgFilter.addDataScheme("package"); 1026 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null, 1027 null); 1028 1029 IntentFilter suspendedPkgFilter = new IntentFilter(); 1030 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED); 1031 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, 1032 suspendedPkgFilter, null, null); 1033 1034 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 1035 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null, 1036 null); 1037 1038 mSettingsObserver = new SettingsObserver(mHandler); 1039 1040 mArchive = new Archive(resources.getInteger( 1041 R.integer.config_notificationServiceArchiveSize)); 1042 1043 publishBinderService(Context.NOTIFICATION_SERVICE, mService); 1044 publishLocalService(NotificationManagerInternal.class, mInternalService); 1045 } 1046 1047 private void sendRegisteredOnlyBroadcast(String action) { 1048 getContext().sendBroadcastAsUser(new Intent(action) 1049 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null); 1050 } 1051 1052 /** 1053 * Make sure the XML config and the the AppOps system agree about blocks. 1054 */ 1055 private void syncBlockDb() { 1056 loadPolicyFile(); 1057 1058 // sync bans from ranker into app opps 1059 Map<Integer, String> packageBans = mRankingHelper.getPackageBans(); 1060 for(Entry<Integer, String> ban : packageBans.entrySet()) { 1061 final int uid = ban.getKey(); 1062 final String packageName = ban.getValue(); 1063 setNotificationsEnabledForPackageImpl(packageName, uid, false); 1064 } 1065 1066 // sync bans from app opps into ranker 1067 packageBans.clear(); 1068 for (UserInfo user : UserManager.get(getContext()).getUsers()) { 1069 final int userId = user.getUserHandle().getIdentifier(); 1070 final PackageManager packageManager = getContext().getPackageManager(); 1071 List<PackageInfo> packages = packageManager.getInstalledPackagesAsUser(0, userId); 1072 final int packageCount = packages.size(); 1073 for (int p = 0; p < packageCount; p++) { 1074 final String packageName = packages.get(p).packageName; 1075 try { 1076 final int uid = packageManager.getPackageUidAsUser(packageName, userId); 1077 if (!checkNotificationOp(packageName, uid)) { 1078 packageBans.put(uid, packageName); 1079 } 1080 } catch (NameNotFoundException e) { 1081 // forget you 1082 } 1083 } 1084 } 1085 for (Entry<Integer, String> ban : packageBans.entrySet()) { 1086 mRankingHelper.setImportance(ban.getValue(), ban.getKey(), IMPORTANCE_NONE); 1087 } 1088 1089 savePolicyFile(); 1090 } 1091 1092 @Override 1093 public void onBootPhase(int phase) { 1094 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 1095 // no beeping until we're basically done booting 1096 mSystemReady = true; 1097 1098 // Grab our optional AudioService 1099 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); 1100 mAudioManagerInternal = getLocalService(AudioManagerInternal.class); 1101 mVrManagerInternal = getLocalService(VrManagerInternal.class); 1102 mZenModeHelper.onSystemReady(); 1103 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { 1104 // This observer will force an update when observe is called, causing us to 1105 // bind to listener services. 1106 mSettingsObserver.observe(); 1107 mListeners.onBootPhaseAppsCanStart(); 1108 mRankerServices.onBootPhaseAppsCanStart(); 1109 mConditionProviders.onBootPhaseAppsCanStart(); 1110 } 1111 } 1112 1113 void setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled) { 1114 Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg); 1115 1116 mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg, 1117 enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED); 1118 1119 // Now, cancel any outstanding notifications that are part of a just-disabled app 1120 if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) { 1121 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true, UserHandle.getUserId(uid), 1122 REASON_PACKAGE_BANNED, null); 1123 } 1124 } 1125 1126 private void updateListenerHintsLocked() { 1127 final int hints = calculateHints(); 1128 if (hints == mListenerHints) return; 1129 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size()); 1130 mListenerHints = hints; 1131 scheduleListenerHintsChanged(hints); 1132 } 1133 1134 private void updateEffectsSuppressorLocked() { 1135 final long updatedSuppressedEffects = calculateSuppressedEffects(); 1136 if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return; 1137 final List<ComponentName> suppressors = getSuppressors(); 1138 ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects); 1139 mEffectsSuppressors = suppressors; 1140 mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects); 1141 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED); 1142 } 1143 1144 private ArrayList<ComponentName> getSuppressors() { 1145 ArrayList<ComponentName> names = new ArrayList<ComponentName>(); 1146 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) { 1147 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i); 1148 1149 for (ManagedServiceInfo info : serviceInfoList) { 1150 names.add(info.component); 1151 } 1152 } 1153 1154 return names; 1155 } 1156 1157 private boolean removeDisabledHints(ManagedServiceInfo info) { 1158 return removeDisabledHints(info, 0); 1159 } 1160 1161 private boolean removeDisabledHints(ManagedServiceInfo info, int hints) { 1162 boolean removed = false; 1163 1164 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) { 1165 final int hint = mListenersDisablingEffects.keyAt(i); 1166 final ArraySet<ManagedServiceInfo> listeners = 1167 mListenersDisablingEffects.valueAt(i); 1168 1169 if (hints == 0 || (hint & hints) == hint) { 1170 removed = removed || listeners.remove(info); 1171 } 1172 } 1173 1174 return removed; 1175 } 1176 1177 private void addDisabledHints(ManagedServiceInfo info, int hints) { 1178 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) { 1179 addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS); 1180 } 1181 1182 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) { 1183 addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS); 1184 } 1185 1186 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) { 1187 addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS); 1188 } 1189 } 1190 1191 private void addDisabledHint(ManagedServiceInfo info, int hint) { 1192 if (mListenersDisablingEffects.indexOfKey(hint) < 0) { 1193 mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>()); 1194 } 1195 1196 ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint); 1197 hintListeners.add(info); 1198 } 1199 1200 private int calculateHints() { 1201 int hints = 0; 1202 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) { 1203 int hint = mListenersDisablingEffects.keyAt(i); 1204 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i); 1205 1206 if (!serviceInfoList.isEmpty()) { 1207 hints |= hint; 1208 } 1209 } 1210 1211 return hints; 1212 } 1213 1214 private long calculateSuppressedEffects() { 1215 int hints = calculateHints(); 1216 long suppressedEffects = 0; 1217 1218 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) { 1219 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL; 1220 } 1221 1222 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) { 1223 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS; 1224 } 1225 1226 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) { 1227 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS; 1228 } 1229 1230 return suppressedEffects; 1231 } 1232 1233 private void updateInterruptionFilterLocked() { 1234 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter(); 1235 if (interruptionFilter == mInterruptionFilter) return; 1236 mInterruptionFilter = interruptionFilter; 1237 scheduleInterruptionFilterChanged(interruptionFilter); 1238 } 1239 1240 private final IBinder mService = new INotificationManager.Stub() { 1241 // Toasts 1242 // ============================================================================ 1243 1244 @Override 1245 public void enqueueToast(String pkg, ITransientNotification callback, int duration) 1246 { 1247 if (DBG) { 1248 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback 1249 + " duration=" + duration); 1250 } 1251 1252 if (pkg == null || callback == null) { 1253 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback); 1254 return ; 1255 } 1256 1257 final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg)); 1258 final boolean isPackageSuspended = 1259 isPackageSuspendedForUser(pkg, Binder.getCallingUid()); 1260 1261 if (ENABLE_BLOCKED_TOASTS && (!noteNotificationOp(pkg, Binder.getCallingUid()) 1262 || isPackageSuspended)) { 1263 if (!isSystemToast) { 1264 Slog.e(TAG, "Suppressing toast from package " + pkg 1265 + (isPackageSuspended 1266 ? " due to package suspended by administrator." 1267 : " by user request.")); 1268 return; 1269 } 1270 } 1271 1272 synchronized (mToastQueue) { 1273 int callingPid = Binder.getCallingPid(); 1274 long callingId = Binder.clearCallingIdentity(); 1275 try { 1276 ToastRecord record; 1277 int index = indexOfToastLocked(pkg, callback); 1278 // If it's already in the queue, we update it in place, we don't 1279 // move it to the end of the queue. 1280 if (index >= 0) { 1281 record = mToastQueue.get(index); 1282 record.update(duration); 1283 } else { 1284 // Limit the number of toasts that any given package except the android 1285 // package can enqueue. Prevents DOS attacks and deals with leaks. 1286 if (!isSystemToast) { 1287 int count = 0; 1288 final int N = mToastQueue.size(); 1289 for (int i=0; i<N; i++) { 1290 final ToastRecord r = mToastQueue.get(i); 1291 if (r.pkg.equals(pkg)) { 1292 count++; 1293 if (count >= MAX_PACKAGE_NOTIFICATIONS) { 1294 Slog.e(TAG, "Package has already posted " + count 1295 + " toasts. Not showing more. Package=" + pkg); 1296 return; 1297 } 1298 } 1299 } 1300 } 1301 1302 record = new ToastRecord(callingPid, pkg, callback, duration); 1303 mToastQueue.add(record); 1304 index = mToastQueue.size() - 1; 1305 keepProcessAliveLocked(callingPid); 1306 } 1307 // If it's at index 0, it's the current toast. It doesn't matter if it's 1308 // new or just been updated. Call back and tell it to show itself. 1309 // If the callback fails, this will remove it from the list, so don't 1310 // assume that it's valid after this. 1311 if (index == 0) { 1312 showNextToastLocked(); 1313 } 1314 } finally { 1315 Binder.restoreCallingIdentity(callingId); 1316 } 1317 } 1318 } 1319 1320 @Override 1321 public void cancelToast(String pkg, ITransientNotification callback) { 1322 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback); 1323 1324 if (pkg == null || callback == null) { 1325 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback); 1326 return ; 1327 } 1328 1329 synchronized (mToastQueue) { 1330 long callingId = Binder.clearCallingIdentity(); 1331 try { 1332 int index = indexOfToastLocked(pkg, callback); 1333 if (index >= 0) { 1334 cancelToastLocked(index); 1335 } else { 1336 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg 1337 + " callback=" + callback); 1338 } 1339 } finally { 1340 Binder.restoreCallingIdentity(callingId); 1341 } 1342 } 1343 } 1344 1345 @Override 1346 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id, 1347 Notification notification, int[] idOut, int userId) throws RemoteException { 1348 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(), 1349 Binder.getCallingPid(), tag, id, notification, idOut, userId); 1350 } 1351 1352 @Override 1353 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) { 1354 checkCallerIsSystemOrSameApp(pkg); 1355 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 1356 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg); 1357 // Don't allow client applications to cancel foreground service notis or autobundled 1358 // summaries. 1359 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0, 1360 (Binder.getCallingUid() == Process.SYSTEM_UID 1361 ? 0 : Notification.FLAG_FOREGROUND_SERVICE) 1362 | (Binder.getCallingUid() == Process.SYSTEM_UID 1363 ? 0 : Notification.FLAG_AUTOGROUP_SUMMARY), false, userId, 1364 REASON_APP_CANCEL, null); 1365 } 1366 1367 @Override 1368 public void cancelAllNotifications(String pkg, int userId) { 1369 checkCallerIsSystemOrSameApp(pkg); 1370 1371 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 1372 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg); 1373 1374 // Calling from user space, don't allow the canceling of actively 1375 // running foreground services. 1376 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(), 1377 pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId, 1378 REASON_APP_CANCEL_ALL, null); 1379 } 1380 1381 @Override 1382 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) { 1383 checkCallerIsSystem(); 1384 1385 setNotificationsEnabledForPackageImpl(pkg, uid, enabled); 1386 mRankingHelper.setEnabled(pkg, uid, enabled); 1387 savePolicyFile(); 1388 } 1389 1390 /** 1391 * Use this when you just want to know if notifications are OK for this package. 1392 */ 1393 @Override 1394 public boolean areNotificationsEnabled(String pkg) { 1395 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid()); 1396 } 1397 1398 /** 1399 * Use this when you just want to know if notifications are OK for this package. 1400 */ 1401 @Override 1402 public boolean areNotificationsEnabledForPackage(String pkg, int uid) { 1403 checkCallerIsSystemOrSameApp(pkg); 1404 return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg) 1405 == AppOpsManager.MODE_ALLOWED) && !isPackageSuspendedForUser(pkg, uid); 1406 } 1407 1408 @Override 1409 public void setPriority(String pkg, int uid, int priority) { 1410 checkCallerIsSystem(); 1411 mRankingHelper.setPriority(pkg, uid, priority); 1412 savePolicyFile(); 1413 } 1414 1415 @Override 1416 public int getPriority(String pkg, int uid) { 1417 checkCallerIsSystem(); 1418 return mRankingHelper.getPriority(pkg, uid); 1419 } 1420 1421 @Override 1422 public void setVisibilityOverride(String pkg, int uid, int visibility) { 1423 checkCallerIsSystem(); 1424 mRankingHelper.setVisibilityOverride(pkg, uid, visibility); 1425 savePolicyFile(); 1426 } 1427 1428 @Override 1429 public int getVisibilityOverride(String pkg, int uid) { 1430 checkCallerIsSystem(); 1431 return mRankingHelper.getVisibilityOverride(pkg, uid); 1432 } 1433 1434 @Override 1435 public void setImportance(String pkg, int uid, int importance) { 1436 enforceSystemOrSystemUI("Caller not system or systemui"); 1437 setNotificationsEnabledForPackageImpl(pkg, uid, 1438 importance != NotificationListenerService.Ranking.IMPORTANCE_NONE); 1439 mRankingHelper.setImportance(pkg, uid, importance); 1440 savePolicyFile(); 1441 } 1442 1443 @Override 1444 public int getPackageImportance(String pkg) { 1445 checkCallerIsSystemOrSameApp(pkg); 1446 return mRankingHelper.getImportance(pkg, Binder.getCallingUid()); 1447 } 1448 1449 @Override 1450 public int getImportance(String pkg, int uid) { 1451 enforceSystemOrSystemUI("Caller not system or systemui"); 1452 return mRankingHelper.getImportance(pkg, uid); 1453 } 1454 1455 /** 1456 * System-only API for getting a list of current (i.e. not cleared) notifications. 1457 * 1458 * Requires ACCESS_NOTIFICATIONS which is signature|system. 1459 * @returns A list of all the notifications, in natural order. 1460 */ 1461 @Override 1462 public StatusBarNotification[] getActiveNotifications(String callingPkg) { 1463 // enforce() will ensure the calling uid has the correct permission 1464 getContext().enforceCallingOrSelfPermission( 1465 android.Manifest.permission.ACCESS_NOTIFICATIONS, 1466 "NotificationManagerService.getActiveNotifications"); 1467 1468 StatusBarNotification[] tmp = null; 1469 int uid = Binder.getCallingUid(); 1470 1471 // noteOp will check to make sure the callingPkg matches the uid 1472 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg) 1473 == AppOpsManager.MODE_ALLOWED) { 1474 synchronized (mNotificationList) { 1475 tmp = new StatusBarNotification[mNotificationList.size()]; 1476 final int N = mNotificationList.size(); 1477 for (int i=0; i<N; i++) { 1478 tmp[i] = mNotificationList.get(i).sbn; 1479 } 1480 } 1481 } 1482 return tmp; 1483 } 1484 1485 /** 1486 * Public API for getting a list of current notifications for the calling package/uid. 1487 * 1488 * @returns A list of all the package's notifications, in natural order. 1489 */ 1490 @Override 1491 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg, 1492 int incomingUserId) { 1493 checkCallerIsSystemOrSameApp(pkg); 1494 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 1495 Binder.getCallingUid(), incomingUserId, true, false, 1496 "getAppActiveNotifications", pkg); 1497 1498 final ArrayList<StatusBarNotification> list 1499 = new ArrayList<StatusBarNotification>(mNotificationList.size()); 1500 1501 synchronized (mNotificationList) { 1502 final int N = mNotificationList.size(); 1503 for (int i = 0; i < N; i++) { 1504 final StatusBarNotification sbn = mNotificationList.get(i).sbn; 1505 if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId 1506 && (sbn.getNotification().flags 1507 & Notification.FLAG_AUTOGROUP_SUMMARY) == 0) { 1508 // We could pass back a cloneLight() but clients might get confused and 1509 // try to send this thing back to notify() again, which would not work 1510 // very well. 1511 final StatusBarNotification sbnOut = new StatusBarNotification( 1512 sbn.getPackageName(), 1513 sbn.getOpPkg(), 1514 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(), 1515 0, // hide score from apps 1516 sbn.getNotification().clone(), 1517 sbn.getUser(), sbn.getPostTime()); 1518 list.add(sbnOut); 1519 } 1520 } 1521 } 1522 1523 return new ParceledListSlice<StatusBarNotification>(list); 1524 } 1525 1526 /** 1527 * System-only API for getting a list of recent (cleared, no longer shown) notifications. 1528 * 1529 * Requires ACCESS_NOTIFICATIONS which is signature|system. 1530 */ 1531 @Override 1532 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) { 1533 // enforce() will ensure the calling uid has the correct permission 1534 getContext().enforceCallingOrSelfPermission( 1535 android.Manifest.permission.ACCESS_NOTIFICATIONS, 1536 "NotificationManagerService.getHistoricalNotifications"); 1537 1538 StatusBarNotification[] tmp = null; 1539 int uid = Binder.getCallingUid(); 1540 1541 // noteOp will check to make sure the callingPkg matches the uid 1542 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg) 1543 == AppOpsManager.MODE_ALLOWED) { 1544 synchronized (mArchive) { 1545 tmp = mArchive.getArray(count); 1546 } 1547 } 1548 return tmp; 1549 } 1550 1551 /** 1552 * Register a listener binder directly with the notification manager. 1553 * 1554 * Only works with system callers. Apps should extend 1555 * {@link android.service.notification.NotificationListenerService}. 1556 */ 1557 @Override 1558 public void registerListener(final INotificationListener listener, 1559 final ComponentName component, final int userid) { 1560 enforceSystemOrSystemUI("INotificationManager.registerListener"); 1561 mListeners.registerService(listener, component, userid); 1562 } 1563 1564 /** 1565 * Remove a listener binder directly 1566 */ 1567 @Override 1568 public void unregisterListener(INotificationListener token, int userid) { 1569 mListeners.unregisterService(token, userid); 1570 } 1571 1572 /** 1573 * Allow an INotificationListener to simulate a "clear all" operation. 1574 * 1575 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications} 1576 * 1577 * @param token The binder for the listener, to check that the caller is allowed 1578 */ 1579 @Override 1580 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) { 1581 final int callingUid = Binder.getCallingUid(); 1582 final int callingPid = Binder.getCallingPid(); 1583 long identity = Binder.clearCallingIdentity(); 1584 try { 1585 synchronized (mNotificationList) { 1586 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 1587 if (keys != null) { 1588 final int N = keys.length; 1589 for (int i = 0; i < N; i++) { 1590 NotificationRecord r = mNotificationsByKey.get(keys[i]); 1591 if (r == null) continue; 1592 final int userId = r.sbn.getUserId(); 1593 if (userId != info.userid && userId != UserHandle.USER_ALL && 1594 !mUserProfiles.isCurrentProfile(userId)) { 1595 throw new SecurityException("Disallowed call from listener: " 1596 + info.service); 1597 } 1598 cancelNotificationFromListenerLocked(info, callingUid, callingPid, 1599 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(), 1600 userId); 1601 } 1602 } else { 1603 cancelAllLocked(callingUid, callingPid, info.userid, 1604 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles()); 1605 } 1606 } 1607 } finally { 1608 Binder.restoreCallingIdentity(identity); 1609 } 1610 } 1611 1612 /** 1613 * Handle request from an approved listener to re-enable itself. 1614 * 1615 * @param component The componenet to be re-enabled, caller must match package. 1616 */ 1617 @Override 1618 public void requestBindListener(ComponentName component) { 1619 checkCallerIsSystemOrSameApp(component.getPackageName()); 1620 long identity = Binder.clearCallingIdentity(); 1621 try { 1622 ManagedServices manager = 1623 mRankerServices.isComponentEnabledForCurrentProfiles(component) 1624 ? mRankerServices 1625 : mListeners; 1626 manager.setComponentState(component, true); 1627 } finally { 1628 Binder.restoreCallingIdentity(identity); 1629 } 1630 } 1631 1632 @Override 1633 public void requestUnbindListener(INotificationListener token) { 1634 long identity = Binder.clearCallingIdentity(); 1635 try { 1636 // allow bound services to disable themselves 1637 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 1638 info.getOwner().setComponentState(info.component, false); 1639 } finally { 1640 Binder.restoreCallingIdentity(identity); 1641 } 1642 } 1643 1644 @Override 1645 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) { 1646 long identity = Binder.clearCallingIdentity(); 1647 try { 1648 synchronized (mNotificationList) { 1649 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 1650 if (keys != null) { 1651 final int N = keys.length; 1652 for (int i = 0; i < N; i++) { 1653 NotificationRecord r = mNotificationsByKey.get(keys[i]); 1654 if (r == null) continue; 1655 final int userId = r.sbn.getUserId(); 1656 if (userId != info.userid && userId != UserHandle.USER_ALL && 1657 !mUserProfiles.isCurrentProfile(userId)) { 1658 throw new SecurityException("Disallowed call from listener: " 1659 + info.service); 1660 } 1661 if (!r.isSeen()) { 1662 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]); 1663 mAppUsageStats.reportEvent(r.sbn.getPackageName(), 1664 userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM 1665 : userId, 1666 UsageEvents.Event.USER_INTERACTION); 1667 r.setSeen(); 1668 } 1669 } 1670 } 1671 } 1672 } finally { 1673 Binder.restoreCallingIdentity(identity); 1674 } 1675 } 1676 1677 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info, 1678 int callingUid, int callingPid, String pkg, String tag, int id, int userId) { 1679 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 1680 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE, 1681 true, 1682 userId, REASON_LISTENER_CANCEL, info); 1683 } 1684 1685 /** 1686 * Allow an INotificationListener to simulate clearing (dismissing) a single notification. 1687 * 1688 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear} 1689 * 1690 * @param token The binder for the listener, to check that the caller is allowed 1691 */ 1692 @Override 1693 public void cancelNotificationFromListener(INotificationListener token, String pkg, 1694 String tag, int id) { 1695 final int callingUid = Binder.getCallingUid(); 1696 final int callingPid = Binder.getCallingPid(); 1697 long identity = Binder.clearCallingIdentity(); 1698 try { 1699 synchronized (mNotificationList) { 1700 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 1701 if (info.supportsProfiles()) { 1702 Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) " 1703 + "from " + info.component 1704 + " use cancelNotification(key) instead."); 1705 } else { 1706 cancelNotificationFromListenerLocked(info, callingUid, callingPid, 1707 pkg, tag, id, info.userid); 1708 } 1709 } 1710 } finally { 1711 Binder.restoreCallingIdentity(identity); 1712 } 1713 } 1714 1715 /** 1716 * Allow an INotificationListener to request the list of outstanding notifications seen by 1717 * the current user. Useful when starting up, after which point the listener callbacks 1718 * should be used. 1719 * 1720 * @param token The binder for the listener, to check that the caller is allowed 1721 * @param keys An array of notification keys to fetch, or null to fetch everything 1722 * @returns The return value will contain the notifications specified in keys, in that 1723 * order, or if keys is null, all the notifications, in natural order. 1724 */ 1725 @Override 1726 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener( 1727 INotificationListener token, String[] keys, int trim) { 1728 synchronized (mNotificationList) { 1729 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 1730 final boolean getKeys = keys != null; 1731 final int N = getKeys ? keys.length : mNotificationList.size(); 1732 final ArrayList<StatusBarNotification> list 1733 = new ArrayList<StatusBarNotification>(N); 1734 for (int i=0; i<N; i++) { 1735 final NotificationRecord r = getKeys 1736 ? mNotificationsByKey.get(keys[i]) 1737 : mNotificationList.get(i); 1738 if (r == null) continue; 1739 StatusBarNotification sbn = r.sbn; 1740 if (!isVisibleToListener(sbn, info)) continue; 1741 StatusBarNotification sbnToSend = 1742 (trim == TRIM_FULL) ? sbn : sbn.cloneLight(); 1743 list.add(sbnToSend); 1744 } 1745 return new ParceledListSlice<StatusBarNotification>(list); 1746 } 1747 } 1748 1749 @Override 1750 public void requestHintsFromListener(INotificationListener token, int hints) { 1751 final long identity = Binder.clearCallingIdentity(); 1752 try { 1753 synchronized (mNotificationList) { 1754 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 1755 final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS 1756 | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS 1757 | HINT_HOST_DISABLE_CALL_EFFECTS; 1758 final boolean disableEffects = (hints & disableEffectsMask) != 0; 1759 if (disableEffects) { 1760 addDisabledHints(info, hints); 1761 } else { 1762 removeDisabledHints(info, hints); 1763 } 1764 updateListenerHintsLocked(); 1765 updateEffectsSuppressorLocked(); 1766 } 1767 } finally { 1768 Binder.restoreCallingIdentity(identity); 1769 } 1770 } 1771 1772 @Override 1773 public int getHintsFromListener(INotificationListener token) { 1774 synchronized (mNotificationList) { 1775 return mListenerHints; 1776 } 1777 } 1778 1779 @Override 1780 public void requestInterruptionFilterFromListener(INotificationListener token, 1781 int interruptionFilter) throws RemoteException { 1782 final long identity = Binder.clearCallingIdentity(); 1783 try { 1784 synchronized (mNotificationList) { 1785 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 1786 mZenModeHelper.requestFromListener(info.component, interruptionFilter); 1787 updateInterruptionFilterLocked(); 1788 } 1789 } finally { 1790 Binder.restoreCallingIdentity(identity); 1791 } 1792 } 1793 1794 @Override 1795 public int getInterruptionFilterFromListener(INotificationListener token) 1796 throws RemoteException { 1797 synchronized (mNotificationLight) { 1798 return mInterruptionFilter; 1799 } 1800 } 1801 1802 @Override 1803 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim) 1804 throws RemoteException { 1805 synchronized (mNotificationList) { 1806 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 1807 if (info == null) return; 1808 mListeners.setOnNotificationPostedTrimLocked(info, trim); 1809 } 1810 } 1811 1812 @Override 1813 public int getZenMode() { 1814 return mZenModeHelper.getZenMode(); 1815 } 1816 1817 @Override 1818 public ZenModeConfig getZenModeConfig() { 1819 enforceSystemOrSystemUIOrVolume("INotificationManager.getZenModeConfig"); 1820 return mZenModeHelper.getConfig(); 1821 } 1822 1823 @Override 1824 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException { 1825 enforceSystemOrSystemUIOrVolume("INotificationManager.setZenMode"); 1826 final long identity = Binder.clearCallingIdentity(); 1827 try { 1828 mZenModeHelper.setManualZenMode(mode, conditionId, reason); 1829 } finally { 1830 Binder.restoreCallingIdentity(identity); 1831 } 1832 } 1833 1834 @Override 1835 public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException { 1836 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules"); 1837 return mZenModeHelper.getZenRules(); 1838 } 1839 1840 @Override 1841 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException { 1842 Preconditions.checkNotNull(id, "Id is null"); 1843 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule"); 1844 return mZenModeHelper.getAutomaticZenRule(id); 1845 } 1846 1847 @Override 1848 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule) 1849 throws RemoteException { 1850 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null"); 1851 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null"); 1852 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null"); 1853 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null"); 1854 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule"); 1855 1856 return mZenModeHelper.addAutomaticZenRule(automaticZenRule, 1857 "addAutomaticZenRule"); 1858 } 1859 1860 @Override 1861 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule) 1862 throws RemoteException { 1863 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null"); 1864 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null"); 1865 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null"); 1866 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null"); 1867 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule"); 1868 1869 return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule, 1870 "updateAutomaticZenRule"); 1871 } 1872 1873 @Override 1874 public boolean removeAutomaticZenRule(String id) throws RemoteException { 1875 Preconditions.checkNotNull(id, "Id is null"); 1876 // Verify that they can modify zen rules. 1877 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule"); 1878 1879 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule"); 1880 } 1881 1882 @Override 1883 public boolean removeAutomaticZenRules(String packageName) throws RemoteException { 1884 Preconditions.checkNotNull(packageName, "Package name is null"); 1885 enforceSystemOrSystemUI("removeAutomaticZenRules"); 1886 1887 return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules"); 1888 } 1889 1890 @Override 1891 public int getRuleInstanceCount(ComponentName owner) throws RemoteException { 1892 Preconditions.checkNotNull(owner, "Owner is null"); 1893 enforceSystemOrSystemUI("getRuleInstanceCount"); 1894 1895 return mZenModeHelper.getCurrentInstanceCount(owner); 1896 } 1897 1898 @Override 1899 public void setInterruptionFilter(String pkg, int filter) throws RemoteException { 1900 enforcePolicyAccess(pkg, "setInterruptionFilter"); 1901 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1); 1902 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter); 1903 final long identity = Binder.clearCallingIdentity(); 1904 try { 1905 mZenModeHelper.setManualZenMode(zen, null, "setInterruptionFilter"); 1906 } finally { 1907 Binder.restoreCallingIdentity(identity); 1908 } 1909 } 1910 1911 @Override 1912 public void notifyConditions(final String pkg, IConditionProvider provider, 1913 final Condition[] conditions) { 1914 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider); 1915 checkCallerIsSystemOrSameApp(pkg); 1916 mHandler.post(new Runnable() { 1917 @Override 1918 public void run() { 1919 mConditionProviders.notifyConditions(pkg, info, conditions); 1920 } 1921 }); 1922 } 1923 1924 private void enforceSystemOrSystemUIOrVolume(String message) { 1925 if (mAudioManagerInternal != null) { 1926 final int vcuid = mAudioManagerInternal.getVolumeControllerUid(); 1927 if (vcuid > 0 && Binder.getCallingUid() == vcuid) { 1928 return; 1929 } 1930 } 1931 enforceSystemOrSystemUI(message); 1932 } 1933 1934 private void enforceSystemOrSystemUI(String message) { 1935 if (isCallerSystem()) return; 1936 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE, 1937 message); 1938 } 1939 1940 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) { 1941 try { 1942 checkCallerIsSystemOrSameApp(pkg); 1943 } catch (SecurityException e) { 1944 getContext().enforceCallingPermission( 1945 android.Manifest.permission.STATUS_BAR_SERVICE, 1946 message); 1947 } 1948 } 1949 1950 private void enforcePolicyAccess(int uid, String method) { 1951 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission( 1952 android.Manifest.permission.MANAGE_NOTIFICATIONS)) { 1953 return; 1954 } 1955 boolean accessAllowed = false; 1956 String[] packages = getContext().getPackageManager().getPackagesForUid(uid); 1957 final int packageCount = packages.length; 1958 for (int i = 0; i < packageCount; i++) { 1959 if (checkPolicyAccess(packages[i])) { 1960 accessAllowed = true; 1961 } 1962 } 1963 if (!accessAllowed) { 1964 Slog.w(TAG, "Notification policy access denied calling " + method); 1965 throw new SecurityException("Notification policy access denied"); 1966 } 1967 } 1968 1969 private void enforcePolicyAccess(String pkg, String method) { 1970 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission( 1971 android.Manifest.permission.MANAGE_NOTIFICATIONS)) { 1972 return; 1973 } 1974 if (!checkPolicyAccess(pkg)) { 1975 Slog.w(TAG, "Notification policy access denied calling " + method); 1976 throw new SecurityException("Notification policy access denied"); 1977 } 1978 } 1979 1980 private boolean checkPackagePolicyAccess(String pkg) { 1981 return mPolicyAccess.isPackageGranted(pkg); 1982 } 1983 1984 private boolean checkPolicyAccess(String pkg) { 1985 try { 1986 int uid = getContext().getPackageManager().getPackageUidAsUser( 1987 pkg, UserHandle.getCallingUserId()); 1988 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission( 1989 android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, 1990 -1, true)) { 1991 return true; 1992 } 1993 } catch (NameNotFoundException e) { 1994 return false; 1995 } 1996 return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg); 1997 } 1998 1999 @Override 2000 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2001 if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 2002 != PackageManager.PERMISSION_GRANTED) { 2003 pw.println("Permission Denial: can't dump NotificationManager from pid=" 2004 + Binder.getCallingPid() 2005 + ", uid=" + Binder.getCallingUid()); 2006 return; 2007 } 2008 2009 final DumpFilter filter = DumpFilter.parseFromArguments(args); 2010 if (filter != null && filter.stats) { 2011 dumpJson(pw, filter); 2012 } else { 2013 dumpImpl(pw, filter); 2014 } 2015 } 2016 2017 @Override 2018 public ComponentName getEffectsSuppressor() { 2019 enforceSystemOrSystemUIOrVolume("INotificationManager.getEffectsSuppressor"); 2020 return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null; 2021 } 2022 2023 @Override 2024 public boolean matchesCallFilter(Bundle extras) { 2025 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter"); 2026 return mZenModeHelper.matchesCallFilter( 2027 Binder.getCallingUserHandle(), 2028 extras, 2029 mRankingHelper.findExtractor(ValidateNotificationPeople.class), 2030 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS, 2031 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY); 2032 } 2033 2034 @Override 2035 public boolean isSystemConditionProviderEnabled(String path) { 2036 enforceSystemOrSystemUIOrVolume("INotificationManager.isSystemConditionProviderEnabled"); 2037 return mConditionProviders.isSystemProviderEnabled(path); 2038 } 2039 2040 // Backup/restore interface 2041 @Override 2042 public byte[] getBackupPayload(int user) { 2043 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user); 2044 //TODO: http://b/22388012 2045 if (user != UserHandle.USER_SYSTEM) { 2046 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user); 2047 return null; 2048 } 2049 final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 2050 try { 2051 writePolicyXml(baos, true /*forBackup*/); 2052 return baos.toByteArray(); 2053 } catch (IOException e) { 2054 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e); 2055 } 2056 return null; 2057 } 2058 2059 @Override 2060 public void applyRestore(byte[] payload, int user) { 2061 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload=" 2062 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null)); 2063 if (payload == null) { 2064 Slog.w(TAG, "applyRestore: no payload to restore for user " + user); 2065 return; 2066 } 2067 //TODO: http://b/22388012 2068 if (user != UserHandle.USER_SYSTEM) { 2069 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user); 2070 return; 2071 } 2072 final ByteArrayInputStream bais = new ByteArrayInputStream(payload); 2073 try { 2074 readPolicyXml(bais, true /*forRestore*/); 2075 savePolicyFile(); 2076 } catch (NumberFormatException | XmlPullParserException | IOException e) { 2077 Slog.w(TAG, "applyRestore: error reading payload", e); 2078 } 2079 } 2080 2081 @Override 2082 public boolean isNotificationPolicyAccessGranted(String pkg) { 2083 return checkPolicyAccess(pkg); 2084 } 2085 2086 @Override 2087 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {; 2088 enforceSystemOrSystemUIOrSamePackage(pkg, 2089 "request policy access status for another package"); 2090 return checkPolicyAccess(pkg); 2091 } 2092 2093 @Override 2094 public String[] getPackagesRequestingNotificationPolicyAccess() 2095 throws RemoteException { 2096 enforceSystemOrSystemUI("request policy access packages"); 2097 final long identity = Binder.clearCallingIdentity(); 2098 try { 2099 return mPolicyAccess.getRequestingPackages(); 2100 } finally { 2101 Binder.restoreCallingIdentity(identity); 2102 } 2103 } 2104 2105 @Override 2106 public void setNotificationPolicyAccessGranted(String pkg, boolean granted) 2107 throws RemoteException { 2108 enforceSystemOrSystemUI("grant notification policy access"); 2109 final long identity = Binder.clearCallingIdentity(); 2110 try { 2111 synchronized (mNotificationList) { 2112 mPolicyAccess.put(pkg, granted); 2113 } 2114 } finally { 2115 Binder.restoreCallingIdentity(identity); 2116 } 2117 } 2118 2119 @Override 2120 public Policy getNotificationPolicy(String pkg) { 2121 enforcePolicyAccess(pkg, "getNotificationPolicy"); 2122 final long identity = Binder.clearCallingIdentity(); 2123 try { 2124 return mZenModeHelper.getNotificationPolicy(); 2125 } finally { 2126 Binder.restoreCallingIdentity(identity); 2127 } 2128 } 2129 2130 @Override 2131 public void setNotificationPolicy(String pkg, Policy policy) { 2132 enforcePolicyAccess(pkg, "setNotificationPolicy"); 2133 final long identity = Binder.clearCallingIdentity(); 2134 try { 2135 mZenModeHelper.setNotificationPolicy(policy); 2136 } finally { 2137 Binder.restoreCallingIdentity(identity); 2138 } 2139 } 2140 2141 @Override 2142 public void applyAdjustmentFromRankerService(INotificationListener token, 2143 Adjustment adjustment) throws RemoteException { 2144 final long identity = Binder.clearCallingIdentity(); 2145 try { 2146 synchronized (mNotificationList) { 2147 mRankerServices.checkServiceTokenLocked(token); 2148 applyAdjustmentLocked(adjustment); 2149 } 2150 maybeAddAutobundleSummary(adjustment); 2151 mRankingHandler.requestSort(); 2152 } finally { 2153 Binder.restoreCallingIdentity(identity); 2154 } 2155 } 2156 2157 @Override 2158 public void applyAdjustmentsFromRankerService(INotificationListener token, 2159 List<Adjustment> adjustments) throws RemoteException { 2160 2161 final long identity = Binder.clearCallingIdentity(); 2162 try { 2163 synchronized (mNotificationList) { 2164 mRankerServices.checkServiceTokenLocked(token); 2165 for (Adjustment adjustment : adjustments) { 2166 applyAdjustmentLocked(adjustment); 2167 } 2168 } 2169 for (Adjustment adjustment : adjustments) { 2170 maybeAddAutobundleSummary(adjustment); 2171 } 2172 mRankingHandler.requestSort(); 2173 } finally { 2174 Binder.restoreCallingIdentity(identity); 2175 } 2176 } 2177 }; 2178 2179 private void applyAdjustmentLocked(Adjustment adjustment) { 2180 maybeClearAutobundleSummaryLocked(adjustment); 2181 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey()); 2182 if (n == null) { 2183 return; 2184 } 2185 if (adjustment.getImportance() != IMPORTANCE_NONE) { 2186 n.setImportance(adjustment.getImportance(), adjustment.getExplanation()); 2187 } 2188 if (adjustment.getSignals() != null) { 2189 Bundle.setDefusable(adjustment.getSignals(), true); 2190 final String autoGroupKey = adjustment.getSignals().getString( 2191 Adjustment.GROUP_KEY_OVERRIDE_KEY, null); 2192 if (autoGroupKey == null) { 2193 EventLogTags.writeNotificationUnautogrouped(adjustment.getKey()); 2194 } else { 2195 EventLogTags.writeNotificationAutogrouped(adjustment.getKey()); 2196 } 2197 n.sbn.setOverrideGroupKey(autoGroupKey); 2198 } 2199 } 2200 2201 // Clears the 'fake' auto-bunding summary. 2202 private void maybeClearAutobundleSummaryLocked(Adjustment adjustment) { 2203 if (adjustment.getSignals() != null) { 2204 Bundle.setDefusable(adjustment.getSignals(), true); 2205 if (adjustment.getSignals().containsKey(Adjustment.NEEDS_AUTOGROUPING_KEY) 2206 && !adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) { 2207 ArrayMap<String, String> summaries = 2208 mAutobundledSummaries.get(adjustment.getUser()); 2209 if (summaries != null && summaries.containsKey(adjustment.getPackage())) { 2210 // Clear summary. 2211 final NotificationRecord removed = mNotificationsByKey.get( 2212 summaries.remove(adjustment.getPackage())); 2213 if (removed != null) { 2214 mNotificationList.remove(removed); 2215 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED); 2216 } 2217 } 2218 } 2219 } 2220 } 2221 2222 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit. 2223 private void maybeAddAutobundleSummary(Adjustment adjustment) { 2224 if (adjustment.getSignals() != null) { 2225 Bundle.setDefusable(adjustment.getSignals(), true); 2226 if (adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) { 2227 final String newAutoBundleKey = 2228 adjustment.getSignals().getString(Adjustment.GROUP_KEY_OVERRIDE_KEY, null); 2229 int userId = -1; 2230 NotificationRecord summaryRecord = null; 2231 synchronized (mNotificationList) { 2232 NotificationRecord notificationRecord = 2233 mNotificationsByKey.get(adjustment.getKey()); 2234 if (notificationRecord == null) { 2235 // The notification could have been cancelled again already. A successive 2236 // adjustment will post a summary if needed. 2237 return; 2238 } 2239 final StatusBarNotification adjustedSbn = notificationRecord.sbn; 2240 userId = adjustedSbn.getUser().getIdentifier(); 2241 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId); 2242 if (summaries == null) { 2243 summaries = new ArrayMap<>(); 2244 } 2245 mAutobundledSummaries.put(userId, summaries); 2246 if (!summaries.containsKey(adjustment.getPackage()) 2247 && newAutoBundleKey != null) { 2248 // Add summary 2249 final ApplicationInfo appInfo = 2250 adjustedSbn.getNotification().extras.getParcelable( 2251 Notification.EXTRA_BUILDER_APPLICATION_INFO); 2252 final Bundle extras = new Bundle(); 2253 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo); 2254 final Notification summaryNotification = 2255 new Notification.Builder(getContext()).setSmallIcon( 2256 adjustedSbn.getNotification().getSmallIcon()) 2257 .setGroupSummary(true) 2258 .setGroup(newAutoBundleKey) 2259 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true) 2260 .setFlag(Notification.FLAG_GROUP_SUMMARY, true) 2261 .setColor(adjustedSbn.getNotification().color) 2262 .build(); 2263 summaryNotification.extras.putAll(extras); 2264 Intent appIntent = getContext().getPackageManager() 2265 .getLaunchIntentForPackage(adjustment.getPackage()); 2266 if (appIntent != null) { 2267 summaryNotification.contentIntent = PendingIntent.getActivityAsUser( 2268 getContext(), 0, appIntent, 0, null, 2269 UserHandle.of(userId)); 2270 } 2271 final StatusBarNotification summarySbn = 2272 new StatusBarNotification(adjustedSbn.getPackageName(), 2273 adjustedSbn.getOpPkg(), 2274 Integer.MAX_VALUE, Adjustment.GROUP_KEY_OVERRIDE_KEY, 2275 adjustedSbn.getUid(), adjustedSbn.getInitialPid(), 2276 summaryNotification, adjustedSbn.getUser(), 2277 newAutoBundleKey, 2278 System.currentTimeMillis()); 2279 summaryRecord = new NotificationRecord(getContext(), summarySbn); 2280 summaries.put(adjustment.getPackage(), summarySbn.getKey()); 2281 } 2282 } 2283 if (summaryRecord != null) { 2284 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord)); 2285 } 2286 } 2287 } 2288 } 2289 2290 private String disableNotificationEffects(NotificationRecord record) { 2291 if (mDisableNotificationEffects) { 2292 return "booleanState"; 2293 } 2294 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) { 2295 return "listenerHints"; 2296 } 2297 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) { 2298 return "callState"; 2299 } 2300 return null; 2301 }; 2302 2303 private void dumpJson(PrintWriter pw, DumpFilter filter) { 2304 JSONObject dump = new JSONObject(); 2305 try { 2306 dump.put("service", "Notification Manager"); 2307 dump.put("bans", mRankingHelper.dumpBansJson(filter)); 2308 dump.put("ranking", mRankingHelper.dumpJson(filter)); 2309 dump.put("stats", mUsageStats.dumpJson(filter)); 2310 } catch (JSONException e) { 2311 e.printStackTrace(); 2312 } 2313 pw.println(dump); 2314 } 2315 2316 void dumpImpl(PrintWriter pw, DumpFilter filter) { 2317 pw.print("Current Notification Manager state"); 2318 if (filter.filtered) { 2319 pw.print(" (filtered to "); pw.print(filter); pw.print(")"); 2320 } 2321 pw.println(':'); 2322 int N; 2323 final boolean zenOnly = filter.filtered && filter.zen; 2324 2325 if (!zenOnly) { 2326 synchronized (mToastQueue) { 2327 N = mToastQueue.size(); 2328 if (N > 0) { 2329 pw.println(" Toast Queue:"); 2330 for (int i=0; i<N; i++) { 2331 mToastQueue.get(i).dump(pw, " ", filter); 2332 } 2333 pw.println(" "); 2334 } 2335 } 2336 } 2337 2338 synchronized (mNotificationList) { 2339 if (!zenOnly) { 2340 N = mNotificationList.size(); 2341 if (N > 0) { 2342 pw.println(" Notification List:"); 2343 for (int i=0; i<N; i++) { 2344 final NotificationRecord nr = mNotificationList.get(i); 2345 if (filter.filtered && !filter.matches(nr.sbn)) continue; 2346 nr.dump(pw, " ", getContext(), filter.redact); 2347 } 2348 pw.println(" "); 2349 } 2350 2351 if (!filter.filtered) { 2352 N = mLights.size(); 2353 if (N > 0) { 2354 pw.println(" Lights List:"); 2355 for (int i=0; i<N; i++) { 2356 if (i == N - 1) { 2357 pw.print(" > "); 2358 } else { 2359 pw.print(" "); 2360 } 2361 pw.println(mLights.get(i)); 2362 } 2363 pw.println(" "); 2364 } 2365 pw.println(" mUseAttentionLight=" + mUseAttentionLight); 2366 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled); 2367 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey); 2368 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey); 2369 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects); 2370 pw.println(" mCallState=" + callStateToString(mCallState)); 2371 pw.println(" mSystemReady=" + mSystemReady); 2372 } 2373 pw.println(" mArchive=" + mArchive.toString()); 2374 Iterator<StatusBarNotification> iter = mArchive.descendingIterator(); 2375 int i=0; 2376 while (iter.hasNext()) { 2377 final StatusBarNotification sbn = iter.next(); 2378 if (filter != null && !filter.matches(sbn)) continue; 2379 pw.println(" " + sbn); 2380 if (++i >= 5) { 2381 if (iter.hasNext()) pw.println(" ..."); 2382 break; 2383 } 2384 } 2385 } 2386 2387 if (!zenOnly) { 2388 pw.println("\n Usage Stats:"); 2389 mUsageStats.dump(pw, " ", filter); 2390 } 2391 2392 if (!filter.filtered || zenOnly) { 2393 pw.println("\n Zen Mode:"); 2394 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter); 2395 mZenModeHelper.dump(pw, " "); 2396 2397 pw.println("\n Zen Log:"); 2398 ZenLog.dump(pw, " "); 2399 } 2400 2401 if (!zenOnly) { 2402 pw.println("\n Ranking Config:"); 2403 mRankingHelper.dump(pw, " ", filter); 2404 2405 pw.println("\n Notification listeners:"); 2406 mListeners.dump(pw, filter); 2407 pw.print(" mListenerHints: "); pw.println(mListenerHints); 2408 pw.print(" mListenersDisablingEffects: ("); 2409 N = mListenersDisablingEffects.size(); 2410 for (int i = 0; i < N; i++) { 2411 final int hint = mListenersDisablingEffects.keyAt(i); 2412 if (i > 0) pw.print(';'); 2413 pw.print("hint[" + hint + "]:"); 2414 2415 final ArraySet<ManagedServiceInfo> listeners = 2416 mListenersDisablingEffects.valueAt(i); 2417 final int listenerSize = listeners.size(); 2418 2419 for (int j = 0; j < listenerSize; j++) { 2420 if (i > 0) pw.print(','); 2421 final ManagedServiceInfo listener = listeners.valueAt(i); 2422 pw.print(listener.component); 2423 } 2424 } 2425 pw.println(')'); 2426 pw.println("\n mRankerServicePackageName: " + mRankerServicePackageName); 2427 pw.println("\n Notification ranker services:"); 2428 mRankerServices.dump(pw, filter); 2429 } 2430 pw.println("\n Policy access:"); 2431 pw.print(" mPolicyAccess: "); pw.println(mPolicyAccess); 2432 2433 pw.println("\n Condition providers:"); 2434 mConditionProviders.dump(pw, filter); 2435 2436 pw.println("\n Group summaries:"); 2437 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) { 2438 NotificationRecord r = entry.getValue(); 2439 pw.println(" " + entry.getKey() + " -> " + r.getKey()); 2440 if (mNotificationsByKey.get(r.getKey()) != r) { 2441 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey."); 2442 r.dump(pw, " ", getContext(), filter.redact); 2443 } 2444 } 2445 } 2446 } 2447 2448 /** 2449 * The private API only accessible to the system process. 2450 */ 2451 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() { 2452 @Override 2453 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid, 2454 String tag, int id, Notification notification, int[] idReceived, int userId) { 2455 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification, 2456 idReceived, userId); 2457 } 2458 2459 @Override 2460 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId, 2461 int userId) { 2462 checkCallerIsSystem(); 2463 synchronized (mNotificationList) { 2464 int i = indexOfNotificationLocked(pkg, null, notificationId, userId); 2465 if (i < 0) { 2466 Log.d(TAG, "stripForegroundServiceFlag: Could not find notification with " 2467 + "pkg=" + pkg + " / id=" + notificationId + " / userId=" + userId); 2468 return; 2469 } 2470 NotificationRecord r = mNotificationList.get(i); 2471 StatusBarNotification sbn = r.sbn; 2472 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees 2473 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove FLAG_FOREGROUND_SERVICE, 2474 // we have to revert to the flags we received initially *and* force remove 2475 // FLAG_FOREGROUND_SERVICE. 2476 sbn.getNotification().flags = 2477 (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE); 2478 mRankingHelper.sort(mNotificationList); 2479 mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */); 2480 } 2481 } 2482 }; 2483 2484 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid, 2485 final int callingPid, final String tag, final int id, final Notification notification, 2486 int[] idOut, int incomingUserId) { 2487 if (DBG) { 2488 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id 2489 + " notification=" + notification); 2490 } 2491 checkCallerIsSystemOrSameApp(pkg); 2492 final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg)); 2493 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg); 2494 2495 final int userId = ActivityManager.handleIncomingUser(callingPid, 2496 callingUid, incomingUserId, true, false, "enqueueNotification", pkg); 2497 final UserHandle user = new UserHandle(userId); 2498 2499 // Fix the notification as best we can. 2500 try { 2501 final ApplicationInfo ai = getContext().getPackageManager().getApplicationInfoAsUser( 2502 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING, 2503 (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId); 2504 Notification.addFieldsFromContext(ai, userId, notification); 2505 } catch (NameNotFoundException e) { 2506 Slog.e(TAG, "Cannot create a context for sending app", e); 2507 return; 2508 } 2509 2510 // Limit the number of notifications that any given package except the android 2511 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks. 2512 if (!isSystemNotification && !isNotificationFromListener) { 2513 synchronized (mNotificationList) { 2514 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg); 2515 if (appEnqueueRate > MAX_PACKAGE_ENQUEUE_RATE) { 2516 mUsageStats.registerOverRateQuota(pkg); 2517 final long now = SystemClock.elapsedRealtime(); 2518 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) { 2519 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate 2520 + ". Shedding events. package=" + pkg); 2521 mLastOverRateLogTime = now; 2522 } 2523 return; 2524 } 2525 2526 int count = 0; 2527 final int N = mNotificationList.size(); 2528 for (int i=0; i<N; i++) { 2529 final NotificationRecord r = mNotificationList.get(i); 2530 if (r.sbn.getPackageName().equals(pkg) && r.sbn.getUserId() == userId) { 2531 if (r.sbn.getId() == id && TextUtils.equals(r.sbn.getTag(), tag)) { 2532 break; // Allow updating existing notification 2533 } 2534 count++; 2535 if (count >= MAX_PACKAGE_NOTIFICATIONS) { 2536 mUsageStats.registerOverCountQuota(pkg); 2537 Slog.e(TAG, "Package has already posted " + count 2538 + " notifications. Not showing more. package=" + pkg); 2539 return; 2540 } 2541 } 2542 } 2543 } 2544 } 2545 2546 if (pkg == null || notification == null) { 2547 throw new IllegalArgumentException("null not allowed: pkg=" + pkg 2548 + " id=" + id + " notification=" + notification); 2549 } 2550 2551 markAsSentFromNotification(notification); 2552 2553 // Sanitize inputs 2554 notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN, 2555 Notification.PRIORITY_MAX); 2556 2557 // setup local book-keeping 2558 final StatusBarNotification n = new StatusBarNotification( 2559 pkg, opPkg, id, tag, callingUid, callingPid, 0, notification, 2560 user); 2561 final NotificationRecord r = new NotificationRecord(getContext(), n); 2562 mHandler.post(new EnqueueNotificationRunnable(userId, r)); 2563 2564 idOut[0] = id; 2565 } 2566 2567 private static void markAsSentFromNotification(Notification notification) { 2568 final ActivityManagerInternal am = LocalServices.getService(ActivityManagerInternal.class); 2569 final long duration = LocalServices.getService(DeviceIdleController.LocalService.class) 2570 .getNotificationWhitelistDuration(); 2571 2572 int size = 0; 2573 if (notification.contentIntent != null) { 2574 am.setPendingIntentWhitelistDuration(notification.contentIntent.getTarget(), duration); 2575 } 2576 if (notification.deleteIntent != null) { 2577 am.setPendingIntentWhitelistDuration(notification.deleteIntent.getTarget(), duration); 2578 } 2579 if (notification.fullScreenIntent != null) { 2580 am.setPendingIntentWhitelistDuration(notification.fullScreenIntent.getTarget(), 2581 duration); 2582 } 2583 if (notification.actions != null) { 2584 for (Notification.Action action: notification.actions) { 2585 am.setPendingIntentWhitelistDuration(action.actionIntent.getTarget(), duration); 2586 setPendingIntentWhitelistDuration(am, duration, action.getExtras()); 2587 final RemoteInput[] remoteInputs = action.getRemoteInputs(); 2588 if (remoteInputs != null) { 2589 for (RemoteInput remoteInput : remoteInputs) { 2590 setPendingIntentWhitelistDuration(am, duration, remoteInput.getExtras()); 2591 } 2592 } 2593 } 2594 } 2595 } 2596 2597 private static void setPendingIntentWhitelistDuration(ActivityManagerInternal am, long duration, 2598 Bundle extras) { 2599 for (String key : extras.keySet()) { 2600 setPendingIntentWhitelistDuration(am, duration, extras.getParcelable(key)); 2601 final Parcelable[] parcelableArray = extras.getParcelableArray(key); 2602 if (parcelableArray != null) { 2603 for (Parcelable parcelable: parcelableArray) { 2604 setPendingIntentWhitelistDuration(am, duration, parcelable); 2605 } 2606 } 2607 final ArrayList<Parcelable> parcelableList = extras.getParcelableArrayList(key); 2608 if (parcelableList != null) { 2609 for (Parcelable parcelable: parcelableList) { 2610 setPendingIntentWhitelistDuration(am, duration, parcelable); 2611 } 2612 } 2613 } 2614 } 2615 2616 private static void setPendingIntentWhitelistDuration(ActivityManagerInternal am, long duration, 2617 Parcelable parcelable) { 2618 if (parcelable instanceof PendingIntent) { 2619 am.setPendingIntentWhitelistDuration(((PendingIntent) parcelable).getTarget(), 2620 duration); 2621 } 2622 } 2623 2624 private class EnqueueNotificationRunnable implements Runnable { 2625 private final NotificationRecord r; 2626 private final int userId; 2627 2628 EnqueueNotificationRunnable(int userId, NotificationRecord r) { 2629 this.userId = userId; 2630 this.r = r; 2631 }; 2632 2633 @Override 2634 public void run() { 2635 2636 synchronized (mNotificationList) { 2637 final StatusBarNotification n = r.sbn; 2638 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey()); 2639 NotificationRecord old = mNotificationsByKey.get(n.getKey()); 2640 if (old != null) { 2641 // Retain ranking information from previous record 2642 r.copyRankingInformation(old); 2643 } 2644 2645 final int callingUid = n.getUid(); 2646 final int callingPid = n.getInitialPid(); 2647 final Notification notification = n.getNotification(); 2648 final String pkg = n.getPackageName(); 2649 final int id = n.getId(); 2650 final String tag = n.getTag(); 2651 final boolean isSystemNotification = isUidSystem(callingUid) || 2652 ("android".equals(pkg)); 2653 2654 // Handle grouped notifications and bail out early if we 2655 // can to avoid extracting signals. 2656 handleGroupedNotificationLocked(r, old, callingUid, callingPid); 2657 2658 // This conditional is a dirty hack to limit the logging done on 2659 // behalf of the download manager without affecting other apps. 2660 if (!pkg.equals("com.android.providers.downloads") 2661 || Log.isLoggable("DownloadManager", Log.VERBOSE)) { 2662 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW; 2663 if (old != null) { 2664 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE; 2665 } 2666 EventLogTags.writeNotificationEnqueue(callingUid, callingPid, 2667 pkg, id, tag, userId, notification.toString(), 2668 enqueueStatus); 2669 } 2670 2671 mRankingHelper.extractSignals(r); 2672 2673 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid); 2674 2675 // blocked apps 2676 if (r.getImportance() == NotificationListenerService.Ranking.IMPORTANCE_NONE 2677 || !noteNotificationOp(pkg, callingUid) || isPackageSuspended) { 2678 if (!isSystemNotification) { 2679 if (isPackageSuspended) { 2680 Slog.e(TAG, "Suppressing notification from package due to package " 2681 + "suspended by administrator."); 2682 mUsageStats.registerSuspendedByAdmin(r); 2683 } else { 2684 Slog.e(TAG, "Suppressing notification from package by user request."); 2685 mUsageStats.registerBlocked(r); 2686 } 2687 return; 2688 } 2689 } 2690 2691 // tell the ranker service about the notification 2692 if (mRankerServices.isEnabled()) { 2693 mRankerServices.onNotificationEnqueued(r); 2694 // TODO delay the code below here for 100ms or until there is an answer 2695 } 2696 2697 2698 int index = indexOfNotificationLocked(n.getKey()); 2699 if (index < 0) { 2700 mNotificationList.add(r); 2701 mUsageStats.registerPostedByApp(r); 2702 } else { 2703 old = mNotificationList.get(index); 2704 mNotificationList.set(index, r); 2705 mUsageStats.registerUpdatedByApp(r, old); 2706 // Make sure we don't lose the foreground service state. 2707 notification.flags |= 2708 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE; 2709 r.isUpdate = true; 2710 } 2711 2712 mNotificationsByKey.put(n.getKey(), r); 2713 2714 // Ensure if this is a foreground service that the proper additional 2715 // flags are set. 2716 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) { 2717 notification.flags |= Notification.FLAG_ONGOING_EVENT 2718 | Notification.FLAG_NO_CLEAR; 2719 } 2720 2721 applyZenModeLocked(r); 2722 mRankingHelper.sort(mNotificationList); 2723 2724 if (notification.getSmallIcon() != null) { 2725 StatusBarNotification oldSbn = (old != null) ? old.sbn : null; 2726 mListeners.notifyPostedLocked(n, oldSbn); 2727 } else { 2728 Slog.e(TAG, "Not posting notification without small icon: " + notification); 2729 if (old != null && !old.isCanceled) { 2730 mListeners.notifyRemovedLocked(n); 2731 } 2732 // ATTENTION: in a future release we will bail out here 2733 // so that we do not play sounds, show lights, etc. for invalid 2734 // notifications 2735 Slog.e(TAG, "WARNING: In a future release this will crash the app: " 2736 + n.getPackageName()); 2737 } 2738 2739 buzzBeepBlinkLocked(r); 2740 } 2741 } 2742 } 2743 2744 /** 2745 * Ensures that grouped notification receive their special treatment. 2746 * 2747 * <p>Cancels group children if the new notification causes a group to lose 2748 * its summary.</p> 2749 * 2750 * <p>Updates mSummaryByGroupKey.</p> 2751 */ 2752 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old, 2753 int callingUid, int callingPid) { 2754 StatusBarNotification sbn = r.sbn; 2755 Notification n = sbn.getNotification(); 2756 if (n.isGroupSummary() && !sbn.isAppGroup()) { 2757 // notifications without a group shouldn't be a summary, otherwise autobundling can 2758 // lead to bugs 2759 n.flags &= ~Notification.FLAG_GROUP_SUMMARY; 2760 } 2761 2762 String group = sbn.getGroupKey(); 2763 boolean isSummary = n.isGroupSummary(); 2764 2765 Notification oldN = old != null ? old.sbn.getNotification() : null; 2766 String oldGroup = old != null ? old.sbn.getGroupKey() : null; 2767 boolean oldIsSummary = old != null && oldN.isGroupSummary(); 2768 2769 if (oldIsSummary) { 2770 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup); 2771 if (removedSummary != old) { 2772 String removedKey = 2773 removedSummary != null ? removedSummary.getKey() : "<null>"; 2774 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() + 2775 ", removed=" + removedKey); 2776 } 2777 } 2778 if (isSummary) { 2779 mSummaryByGroupKey.put(group, r); 2780 } 2781 2782 // Clear out group children of the old notification if the update 2783 // causes the group summary to go away. This happens when the old 2784 // notification was a summary and the new one isn't, or when the old 2785 // notification was a summary and its group key changed. 2786 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) { 2787 cancelGroupChildrenLocked(old, callingUid, callingPid, null, 2788 REASON_GROUP_SUMMARY_CANCELED); 2789 } 2790 } 2791 2792 @VisibleForTesting 2793 void buzzBeepBlinkLocked(NotificationRecord record) { 2794 boolean buzz = false; 2795 boolean beep = false; 2796 boolean blink = false; 2797 2798 final Notification notification = record.sbn.getNotification(); 2799 final String key = record.getKey(); 2800 2801 // Should this notification make noise, vibe, or use the LED? 2802 final boolean aboveThreshold = record.getImportance() >= IMPORTANCE_DEFAULT; 2803 final boolean canInterrupt = aboveThreshold && !record.isIntercepted(); 2804 if (DBG || record.isIntercepted()) 2805 Slog.v(TAG, 2806 "pkg=" + record.sbn.getPackageName() + " canInterrupt=" + canInterrupt + 2807 " intercept=" + record.isIntercepted() 2808 ); 2809 2810 final int currentUser; 2811 final long token = Binder.clearCallingIdentity(); 2812 try { 2813 currentUser = ActivityManager.getCurrentUser(); 2814 } finally { 2815 Binder.restoreCallingIdentity(token); 2816 } 2817 2818 // If we're not supposed to beep, vibrate, etc. then don't. 2819 final String disableEffects = disableNotificationEffects(record); 2820 if (disableEffects != null) { 2821 ZenLog.traceDisableEffects(record, disableEffects); 2822 } 2823 2824 // Remember if this notification already owns the notification channels. 2825 boolean wasBeep = key != null && key.equals(mSoundNotificationKey); 2826 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey); 2827 2828 // These are set inside the conditional if the notification is allowed to make noise. 2829 boolean hasValidVibrate = false; 2830 boolean hasValidSound = false; 2831 if (disableEffects == null 2832 && (record.getUserId() == UserHandle.USER_ALL || 2833 record.getUserId() == currentUser || 2834 mUserProfiles.isCurrentProfile(record.getUserId())) 2835 && canInterrupt 2836 && mSystemReady 2837 && mAudioManager != null) { 2838 if (DBG) Slog.v(TAG, "Interrupting!"); 2839 2840 // should we use the default notification sound? (indicated either by 2841 // DEFAULT_SOUND or because notification.sound is pointing at 2842 // Settings.System.NOTIFICATION_SOUND) 2843 final boolean useDefaultSound = 2844 (notification.defaults & Notification.DEFAULT_SOUND) != 0 || 2845 Settings.System.DEFAULT_NOTIFICATION_URI 2846 .equals(notification.sound); 2847 2848 Uri soundUri = null; 2849 if (useDefaultSound) { 2850 soundUri = Settings.System.DEFAULT_NOTIFICATION_URI; 2851 2852 // check to see if the default notification sound is silent 2853 ContentResolver resolver = getContext().getContentResolver(); 2854 hasValidSound = Settings.System.getString(resolver, 2855 Settings.System.NOTIFICATION_SOUND) != null; 2856 } else if (notification.sound != null) { 2857 soundUri = notification.sound; 2858 hasValidSound = (soundUri != null); 2859 } 2860 2861 // Does the notification want to specify its own vibration? 2862 final boolean hasCustomVibrate = notification.vibrate != null; 2863 2864 // new in 4.2: if there was supposed to be a sound and we're in vibrate 2865 // mode, and no other vibration is specified, we fall back to vibration 2866 final boolean convertSoundToVibration = 2867 !hasCustomVibrate 2868 && hasValidSound 2869 && (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE); 2870 2871 // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback. 2872 final boolean useDefaultVibrate = 2873 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0; 2874 2875 hasValidVibrate = useDefaultVibrate || convertSoundToVibration || 2876 hasCustomVibrate; 2877 2878 // We can alert, and we're allowed to alert, but if the developer asked us to only do 2879 // it once, and we already have, then don't. 2880 if (!(record.isUpdate 2881 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0)) { 2882 2883 sendAccessibilityEvent(notification, record.sbn.getPackageName()); 2884 2885 if (hasValidSound) { 2886 boolean looping = 2887 (notification.flags & Notification.FLAG_INSISTENT) != 0; 2888 AudioAttributes audioAttributes = audioAttributesForNotification(notification); 2889 mSoundNotificationKey = key; 2890 // do not play notifications if stream volume is 0 (typically because 2891 // ringer mode is silent) or if there is a user of exclusive audio focus 2892 if ((mAudioManager.getStreamVolume( 2893 AudioAttributes.toLegacyStreamType(audioAttributes)) != 0) 2894 && !mAudioManager.isAudioFocusExclusive()) { 2895 final long identity = Binder.clearCallingIdentity(); 2896 try { 2897 final IRingtonePlayer player = 2898 mAudioManager.getRingtonePlayer(); 2899 if (player != null) { 2900 if (DBG) Slog.v(TAG, "Playing sound " + soundUri 2901 + " with attributes " + audioAttributes); 2902 player.playAsync(soundUri, record.sbn.getUser(), looping, 2903 audioAttributes); 2904 beep = true; 2905 } 2906 } catch (RemoteException e) { 2907 } finally { 2908 Binder.restoreCallingIdentity(identity); 2909 } 2910 } 2911 } 2912 2913 if (hasValidVibrate && !(mAudioManager.getRingerModeInternal() 2914 == AudioManager.RINGER_MODE_SILENT)) { 2915 mVibrateNotificationKey = key; 2916 2917 if (useDefaultVibrate || convertSoundToVibration) { 2918 // Escalate privileges so we can use the vibrator even if the 2919 // notifying app does not have the VIBRATE permission. 2920 long identity = Binder.clearCallingIdentity(); 2921 try { 2922 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(), 2923 useDefaultVibrate ? mDefaultVibrationPattern 2924 : mFallbackVibrationPattern, 2925 ((notification.flags & Notification.FLAG_INSISTENT) != 0) 2926 ? 0: -1, audioAttributesForNotification(notification)); 2927 buzz = true; 2928 } finally { 2929 Binder.restoreCallingIdentity(identity); 2930 } 2931 } else if (notification.vibrate.length > 1) { 2932 // If you want your own vibration pattern, you need the VIBRATE 2933 // permission 2934 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(), 2935 notification.vibrate, 2936 ((notification.flags & Notification.FLAG_INSISTENT) != 0) 2937 ? 0: -1, audioAttributesForNotification(notification)); 2938 buzz = true; 2939 } 2940 } 2941 } 2942 2943 } 2944 // If a notification is updated to remove the actively playing sound or vibrate, 2945 // cancel that feedback now 2946 if (wasBeep && !hasValidSound) { 2947 clearSoundLocked(); 2948 } 2949 if (wasBuzz && !hasValidVibrate) { 2950 clearVibrateLocked(); 2951 } 2952 2953 // light 2954 // release the light 2955 boolean wasShowLights = mLights.remove(key); 2956 if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold 2957 && ((record.getSuppressedVisualEffects() 2958 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) { 2959 mLights.add(key); 2960 updateLightsLocked(); 2961 if (mUseAttentionLight) { 2962 mAttentionLight.pulse(); 2963 } 2964 blink = true; 2965 } else if (wasShowLights) { 2966 updateLightsLocked(); 2967 } 2968 if (buzz || beep || blink) { 2969 if (((record.getSuppressedVisualEffects() 2970 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) != 0)) { 2971 if (DBG) Slog.v(TAG, "Suppressed SystemUI from triggering screen on"); 2972 } else { 2973 EventLogTags.writeNotificationAlert(key, 2974 buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0); 2975 mHandler.post(mBuzzBeepBlinked); 2976 } 2977 } 2978 } 2979 2980 private static AudioAttributes audioAttributesForNotification(Notification n) { 2981 if (n.audioAttributes != null 2982 && !Notification.AUDIO_ATTRIBUTES_DEFAULT.equals(n.audioAttributes)) { 2983 // the audio attributes are set and different from the default, use them 2984 return n.audioAttributes; 2985 } else if (n.audioStreamType >= 0 && n.audioStreamType < AudioSystem.getNumStreamTypes()) { 2986 // the stream type is valid, use it 2987 return new AudioAttributes.Builder() 2988 .setInternalLegacyStreamType(n.audioStreamType) 2989 .build(); 2990 } else if (n.audioStreamType == AudioSystem.STREAM_DEFAULT) { 2991 return Notification.AUDIO_ATTRIBUTES_DEFAULT; 2992 } else { 2993 Log.w(TAG, String.format("Invalid stream type: %d", n.audioStreamType)); 2994 return Notification.AUDIO_ATTRIBUTES_DEFAULT; 2995 } 2996 } 2997 2998 void showNextToastLocked() { 2999 ToastRecord record = mToastQueue.get(0); 3000 while (record != null) { 3001 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback); 3002 try { 3003 record.callback.show(); 3004 scheduleTimeoutLocked(record); 3005 return; 3006 } catch (RemoteException e) { 3007 Slog.w(TAG, "Object died trying to show notification " + record.callback 3008 + " in package " + record.pkg); 3009 // remove it from the list and let the process die 3010 int index = mToastQueue.indexOf(record); 3011 if (index >= 0) { 3012 mToastQueue.remove(index); 3013 } 3014 keepProcessAliveLocked(record.pid); 3015 if (mToastQueue.size() > 0) { 3016 record = mToastQueue.get(0); 3017 } else { 3018 record = null; 3019 } 3020 } 3021 } 3022 } 3023 3024 void cancelToastLocked(int index) { 3025 ToastRecord record = mToastQueue.get(index); 3026 try { 3027 record.callback.hide(); 3028 } catch (RemoteException e) { 3029 Slog.w(TAG, "Object died trying to hide notification " + record.callback 3030 + " in package " + record.pkg); 3031 // don't worry about this, we're about to remove it from 3032 // the list anyway 3033 } 3034 mToastQueue.remove(index); 3035 keepProcessAliveLocked(record.pid); 3036 if (mToastQueue.size() > 0) { 3037 // Show the next one. If the callback fails, this will remove 3038 // it from the list, so don't assume that the list hasn't changed 3039 // after this point. 3040 showNextToastLocked(); 3041 } 3042 } 3043 3044 private void scheduleTimeoutLocked(ToastRecord r) 3045 { 3046 mHandler.removeCallbacksAndMessages(r); 3047 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r); 3048 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY; 3049 mHandler.sendMessageDelayed(m, delay); 3050 } 3051 3052 private void handleTimeout(ToastRecord record) 3053 { 3054 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback); 3055 synchronized (mToastQueue) { 3056 int index = indexOfToastLocked(record.pkg, record.callback); 3057 if (index >= 0) { 3058 cancelToastLocked(index); 3059 } 3060 } 3061 } 3062 3063 // lock on mToastQueue 3064 int indexOfToastLocked(String pkg, ITransientNotification callback) 3065 { 3066 IBinder cbak = callback.asBinder(); 3067 ArrayList<ToastRecord> list = mToastQueue; 3068 int len = list.size(); 3069 for (int i=0; i<len; i++) { 3070 ToastRecord r = list.get(i); 3071 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) { 3072 return i; 3073 } 3074 } 3075 return -1; 3076 } 3077 3078 // lock on mToastQueue 3079 void keepProcessAliveLocked(int pid) 3080 { 3081 int toastCount = 0; // toasts from this pid 3082 ArrayList<ToastRecord> list = mToastQueue; 3083 int N = list.size(); 3084 for (int i=0; i<N; i++) { 3085 ToastRecord r = list.get(i); 3086 if (r.pid == pid) { 3087 toastCount++; 3088 } 3089 } 3090 try { 3091 mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0); 3092 } catch (RemoteException e) { 3093 // Shouldn't happen. 3094 } 3095 } 3096 3097 private void handleRankingReconsideration(Message message) { 3098 if (!(message.obj instanceof RankingReconsideration)) return; 3099 RankingReconsideration recon = (RankingReconsideration) message.obj; 3100 recon.run(); 3101 boolean changed; 3102 synchronized (mNotificationList) { 3103 final NotificationRecord record = mNotificationsByKey.get(recon.getKey()); 3104 if (record == null) { 3105 return; 3106 } 3107 int indexBefore = findNotificationRecordIndexLocked(record); 3108 boolean interceptBefore = record.isIntercepted(); 3109 int visibilityBefore = record.getPackageVisibilityOverride(); 3110 recon.applyChangesLocked(record); 3111 applyZenModeLocked(record); 3112 mRankingHelper.sort(mNotificationList); 3113 int indexAfter = findNotificationRecordIndexLocked(record); 3114 boolean interceptAfter = record.isIntercepted(); 3115 int visibilityAfter = record.getPackageVisibilityOverride(); 3116 changed = indexBefore != indexAfter || interceptBefore != interceptAfter 3117 || visibilityBefore != visibilityAfter; 3118 if (interceptBefore && !interceptAfter) { 3119 buzzBeepBlinkLocked(record); 3120 } 3121 } 3122 if (changed) { 3123 scheduleSendRankingUpdate(); 3124 } 3125 } 3126 3127 private void handleRankingSort() { 3128 synchronized (mNotificationList) { 3129 final int N = mNotificationList.size(); 3130 ArrayList<String> orderBefore = new ArrayList<String>(N); 3131 ArrayList<String> groupOverrideBefore = new ArrayList<>(N); 3132 int[] visibilities = new int[N]; 3133 int[] importances = new int[N]; 3134 for (int i = 0; i < N; i++) { 3135 final NotificationRecord r = mNotificationList.get(i); 3136 orderBefore.add(r.getKey()); 3137 groupOverrideBefore.add(r.sbn.getGroupKey()); 3138 visibilities[i] = r.getPackageVisibilityOverride(); 3139 importances[i] = r.getImportance(); 3140 mRankingHelper.extractSignals(r); 3141 } 3142 mRankingHelper.sort(mNotificationList); 3143 for (int i = 0; i < N; i++) { 3144 final NotificationRecord r = mNotificationList.get(i); 3145 if (!orderBefore.get(i).equals(r.getKey()) 3146 || visibilities[i] != r.getPackageVisibilityOverride() 3147 || importances[i] != r.getImportance() 3148 || !groupOverrideBefore.get(i).equals(r.sbn.getGroupKey())) { 3149 scheduleSendRankingUpdate(); 3150 return; 3151 } 3152 } 3153 } 3154 } 3155 3156 // let zen mode evaluate this record 3157 private void applyZenModeLocked(NotificationRecord record) { 3158 record.setIntercepted(mZenModeHelper.shouldIntercept(record)); 3159 if (record.isIntercepted()) { 3160 int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff() 3161 ? SUPPRESSED_EFFECT_SCREEN_OFF : 0) 3162 | (mZenModeHelper.shouldSuppressWhenScreenOn() 3163 ? SUPPRESSED_EFFECT_SCREEN_ON : 0); 3164 record.setSuppressedVisualEffects(suppressed); 3165 } 3166 } 3167 3168 // lock on mNotificationList 3169 private int findNotificationRecordIndexLocked(NotificationRecord target) { 3170 return mRankingHelper.indexOf(mNotificationList, target); 3171 } 3172 3173 private void scheduleSendRankingUpdate() { 3174 if (!mHandler.hasMessages(MESSAGE_SEND_RANKING_UPDATE)) { 3175 Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE); 3176 mHandler.sendMessage(m); 3177 } 3178 } 3179 3180 private void handleSendRankingUpdate() { 3181 synchronized (mNotificationList) { 3182 mListeners.notifyRankingUpdateLocked(); 3183 } 3184 } 3185 3186 private void scheduleListenerHintsChanged(int state) { 3187 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED); 3188 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget(); 3189 } 3190 3191 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) { 3192 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED); 3193 mHandler.obtainMessage( 3194 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED, 3195 listenerInterruptionFilter, 3196 0).sendToTarget(); 3197 } 3198 3199 private void handleListenerHintsChanged(int hints) { 3200 synchronized (mNotificationList) { 3201 mListeners.notifyListenerHintsChangedLocked(hints); 3202 } 3203 } 3204 3205 private void handleListenerInterruptionFilterChanged(int interruptionFilter) { 3206 synchronized (mNotificationList) { 3207 mListeners.notifyInterruptionFilterChanged(interruptionFilter); 3208 } 3209 } 3210 3211 private final class WorkerHandler extends Handler 3212 { 3213 @Override 3214 public void handleMessage(Message msg) 3215 { 3216 switch (msg.what) 3217 { 3218 case MESSAGE_TIMEOUT: 3219 handleTimeout((ToastRecord)msg.obj); 3220 break; 3221 case MESSAGE_SAVE_POLICY_FILE: 3222 handleSavePolicyFile(); 3223 break; 3224 case MESSAGE_SEND_RANKING_UPDATE: 3225 handleSendRankingUpdate(); 3226 break; 3227 case MESSAGE_LISTENER_HINTS_CHANGED: 3228 handleListenerHintsChanged(msg.arg1); 3229 break; 3230 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED: 3231 handleListenerInterruptionFilterChanged(msg.arg1); 3232 break; 3233 } 3234 } 3235 3236 } 3237 3238 private final class RankingHandlerWorker extends Handler implements RankingHandler 3239 { 3240 public RankingHandlerWorker(Looper looper) { 3241 super(looper); 3242 } 3243 3244 @Override 3245 public void handleMessage(Message msg) { 3246 switch (msg.what) { 3247 case MESSAGE_RECONSIDER_RANKING: 3248 handleRankingReconsideration(msg); 3249 break; 3250 case MESSAGE_RANKING_SORT: 3251 handleRankingSort(); 3252 break; 3253 } 3254 } 3255 3256 public void requestSort() { 3257 removeMessages(MESSAGE_RANKING_SORT); 3258 sendEmptyMessage(MESSAGE_RANKING_SORT); 3259 } 3260 3261 public void requestReconsideration(RankingReconsideration recon) { 3262 Message m = Message.obtain(this, 3263 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon); 3264 long delay = recon.getDelay(TimeUnit.MILLISECONDS); 3265 sendMessageDelayed(m, delay); 3266 } 3267 } 3268 3269 // Notifications 3270 // ============================================================================ 3271 static int clamp(int x, int low, int high) { 3272 return (x < low) ? low : ((x > high) ? high : x); 3273 } 3274 3275 void sendAccessibilityEvent(Notification notification, CharSequence packageName) { 3276 AccessibilityManager manager = AccessibilityManager.getInstance(getContext()); 3277 if (!manager.isEnabled()) { 3278 return; 3279 } 3280 3281 AccessibilityEvent event = 3282 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED); 3283 event.setPackageName(packageName); 3284 event.setClassName(Notification.class.getName()); 3285 event.setParcelableData(notification); 3286 CharSequence tickerText = notification.tickerText; 3287 if (!TextUtils.isEmpty(tickerText)) { 3288 event.getText().add(tickerText); 3289 } 3290 3291 manager.sendAccessibilityEvent(event); 3292 } 3293 3294 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) { 3295 // tell the app 3296 if (sendDelete) { 3297 if (r.getNotification().deleteIntent != null) { 3298 try { 3299 r.getNotification().deleteIntent.send(); 3300 } catch (PendingIntent.CanceledException ex) { 3301 // do nothing - there's no relevant way to recover, and 3302 // no reason to let this propagate 3303 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex); 3304 } 3305 } 3306 } 3307 3308 // status bar 3309 if (r.getNotification().getSmallIcon() != null) { 3310 r.isCanceled = true; 3311 mListeners.notifyRemovedLocked(r.sbn); 3312 } 3313 3314 final String canceledKey = r.getKey(); 3315 3316 // sound 3317 if (canceledKey.equals(mSoundNotificationKey)) { 3318 mSoundNotificationKey = null; 3319 final long identity = Binder.clearCallingIdentity(); 3320 try { 3321 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 3322 if (player != null) { 3323 player.stopAsync(); 3324 } 3325 } catch (RemoteException e) { 3326 } finally { 3327 Binder.restoreCallingIdentity(identity); 3328 } 3329 } 3330 3331 // vibrate 3332 if (canceledKey.equals(mVibrateNotificationKey)) { 3333 mVibrateNotificationKey = null; 3334 long identity = Binder.clearCallingIdentity(); 3335 try { 3336 mVibrator.cancel(); 3337 } 3338 finally { 3339 Binder.restoreCallingIdentity(identity); 3340 } 3341 } 3342 3343 // light 3344 mLights.remove(canceledKey); 3345 3346 // Record usage stats 3347 // TODO: add unbundling stats? 3348 switch (reason) { 3349 case REASON_DELEGATE_CANCEL: 3350 case REASON_DELEGATE_CANCEL_ALL: 3351 case REASON_LISTENER_CANCEL: 3352 case REASON_LISTENER_CANCEL_ALL: 3353 mUsageStats.registerDismissedByUser(r); 3354 break; 3355 case REASON_APP_CANCEL: 3356 case REASON_APP_CANCEL_ALL: 3357 mUsageStats.registerRemovedByApp(r); 3358 break; 3359 } 3360 3361 mNotificationsByKey.remove(r.sbn.getKey()); 3362 String groupKey = r.getGroupKey(); 3363 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey); 3364 if (groupSummary != null && groupSummary.getKey().equals(r.getKey())) { 3365 mSummaryByGroupKey.remove(groupKey); 3366 } 3367 final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId()); 3368 if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) { 3369 summaries.remove(r.sbn.getPackageName()); 3370 } 3371 3372 // Save it for users of getHistoricalNotifications() 3373 mArchive.record(r.sbn); 3374 3375 final long now = System.currentTimeMillis(); 3376 EventLogTags.writeNotificationCanceled(canceledKey, reason, 3377 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now)); 3378 } 3379 3380 /** 3381 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags} 3382 * and none of the {@code mustNotHaveFlags}. 3383 */ 3384 void cancelNotification(final int callingUid, final int callingPid, 3385 final String pkg, final String tag, final int id, 3386 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete, 3387 final int userId, final int reason, final ManagedServiceInfo listener) { 3388 // In enqueueNotificationInternal notifications are added by scheduling the 3389 // work on the worker handler. Hence, we also schedule the cancel on this 3390 // handler to avoid a scenario where an add notification call followed by a 3391 // remove notification call ends up in not removing the notification. 3392 mHandler.post(new Runnable() { 3393 @Override 3394 public void run() { 3395 String listenerName = listener == null ? null : listener.component.toShortString(); 3396 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag, 3397 userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName); 3398 3399 synchronized (mNotificationList) { 3400 int index = indexOfNotificationLocked(pkg, tag, id, userId); 3401 if (index >= 0) { 3402 NotificationRecord r = mNotificationList.get(index); 3403 3404 // Ideally we'd do this in the caller of this method. However, that would 3405 // require the caller to also find the notification. 3406 if (reason == REASON_DELEGATE_CLICK) { 3407 mUsageStats.registerClickedByUser(r); 3408 } 3409 3410 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) { 3411 return; 3412 } 3413 if ((r.getNotification().flags & mustNotHaveFlags) != 0) { 3414 return; 3415 } 3416 3417 mNotificationList.remove(index); 3418 3419 cancelNotificationLocked(r, sendDelete, reason); 3420 cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName, 3421 REASON_GROUP_SUMMARY_CANCELED); 3422 updateLightsLocked(); 3423 } 3424 } 3425 } 3426 }); 3427 } 3428 3429 /** 3430 * Determine whether the userId applies to the notification in question, either because 3431 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard). 3432 */ 3433 private boolean notificationMatchesUserId(NotificationRecord r, int userId) { 3434 return 3435 // looking for USER_ALL notifications? match everything 3436 userId == UserHandle.USER_ALL 3437 // a notification sent to USER_ALL matches any query 3438 || r.getUserId() == UserHandle.USER_ALL 3439 // an exact user match 3440 || r.getUserId() == userId; 3441 } 3442 3443 /** 3444 * Determine whether the userId applies to the notification in question, either because 3445 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or 3446 * because it matches one of the users profiles. 3447 */ 3448 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) { 3449 return notificationMatchesUserId(r, userId) 3450 || mUserProfiles.isCurrentProfile(r.getUserId()); 3451 } 3452 3453 /** 3454 * Cancels all notifications from a given package that have all of the 3455 * {@code mustHaveFlags}. 3456 */ 3457 boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags, 3458 int mustNotHaveFlags, boolean doit, int userId, int reason, 3459 ManagedServiceInfo listener) { 3460 String listenerName = listener == null ? null : listener.component.toShortString(); 3461 EventLogTags.writeNotificationCancelAll(callingUid, callingPid, 3462 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason, 3463 listenerName); 3464 3465 synchronized (mNotificationList) { 3466 final int N = mNotificationList.size(); 3467 ArrayList<NotificationRecord> canceledNotifications = null; 3468 for (int i = N-1; i >= 0; --i) { 3469 NotificationRecord r = mNotificationList.get(i); 3470 if (!notificationMatchesUserId(r, userId)) { 3471 continue; 3472 } 3473 // Don't remove notifications to all, if there's no package name specified 3474 if (r.getUserId() == UserHandle.USER_ALL && pkg == null) { 3475 continue; 3476 } 3477 if ((r.getFlags() & mustHaveFlags) != mustHaveFlags) { 3478 continue; 3479 } 3480 if ((r.getFlags() & mustNotHaveFlags) != 0) { 3481 continue; 3482 } 3483 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) { 3484 continue; 3485 } 3486 if (canceledNotifications == null) { 3487 canceledNotifications = new ArrayList<>(); 3488 } 3489 canceledNotifications.add(r); 3490 if (!doit) { 3491 return true; 3492 } 3493 mNotificationList.remove(i); 3494 cancelNotificationLocked(r, false, reason); 3495 } 3496 if (doit && canceledNotifications != null) { 3497 final int M = canceledNotifications.size(); 3498 for (int i = 0; i < M; i++) { 3499 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid, 3500 listenerName, REASON_GROUP_SUMMARY_CANCELED); 3501 } 3502 } 3503 if (canceledNotifications != null) { 3504 updateLightsLocked(); 3505 } 3506 return canceledNotifications != null; 3507 } 3508 } 3509 3510 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason, 3511 ManagedServiceInfo listener, boolean includeCurrentProfiles) { 3512 String listenerName = listener == null ? null : listener.component.toShortString(); 3513 EventLogTags.writeNotificationCancelAll(callingUid, callingPid, 3514 null, userId, 0, 0, reason, listenerName); 3515 3516 ArrayList<NotificationRecord> canceledNotifications = null; 3517 final int N = mNotificationList.size(); 3518 for (int i=N-1; i>=0; i--) { 3519 NotificationRecord r = mNotificationList.get(i); 3520 if (includeCurrentProfiles) { 3521 if (!notificationMatchesCurrentProfiles(r, userId)) { 3522 continue; 3523 } 3524 } else { 3525 if (!notificationMatchesUserId(r, userId)) { 3526 continue; 3527 } 3528 } 3529 3530 if ((r.getFlags() & (Notification.FLAG_ONGOING_EVENT 3531 | Notification.FLAG_NO_CLEAR)) == 0) { 3532 mNotificationList.remove(i); 3533 cancelNotificationLocked(r, true, reason); 3534 // Make a note so we can cancel children later. 3535 if (canceledNotifications == null) { 3536 canceledNotifications = new ArrayList<>(); 3537 } 3538 canceledNotifications.add(r); 3539 } 3540 } 3541 int M = canceledNotifications != null ? canceledNotifications.size() : 0; 3542 for (int i = 0; i < M; i++) { 3543 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid, 3544 listenerName, REASON_GROUP_SUMMARY_CANCELED); 3545 } 3546 updateLightsLocked(); 3547 } 3548 3549 // Warning: The caller is responsible for invoking updateLightsLocked(). 3550 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid, 3551 String listenerName, int reason) { 3552 Notification n = r.getNotification(); 3553 if (!n.isGroupSummary()) { 3554 return; 3555 } 3556 3557 String pkg = r.sbn.getPackageName(); 3558 int userId = r.getUserId(); 3559 3560 if (pkg == null) { 3561 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey()); 3562 return; 3563 } 3564 3565 final int N = mNotificationList.size(); 3566 for (int i = N - 1; i >= 0; i--) { 3567 NotificationRecord childR = mNotificationList.get(i); 3568 StatusBarNotification childSbn = childR.sbn; 3569 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) && 3570 childR.getGroupKey().equals(r.getGroupKey())) { 3571 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(), 3572 childSbn.getTag(), userId, 0, 0, reason, listenerName); 3573 mNotificationList.remove(i); 3574 cancelNotificationLocked(childR, false, reason); 3575 } 3576 } 3577 } 3578 3579 // lock on mNotificationList 3580 void updateLightsLocked() 3581 { 3582 // handle notification lights 3583 NotificationRecord ledNotification = null; 3584 while (ledNotification == null && !mLights.isEmpty()) { 3585 final String owner = mLights.get(mLights.size() - 1); 3586 ledNotification = mNotificationsByKey.get(owner); 3587 if (ledNotification == null) { 3588 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner); 3589 mLights.remove(owner); 3590 } 3591 } 3592 3593 // Don't flash while we are in a call or screen is on 3594 if (ledNotification == null || mInCall || mScreenOn) { 3595 mNotificationLight.turnOff(); 3596 if (mStatusBar != null) { 3597 mStatusBar.notificationLightOff(); 3598 } 3599 } else { 3600 final Notification ledno = ledNotification.sbn.getNotification(); 3601 int ledARGB = ledno.ledARGB; 3602 int ledOnMS = ledno.ledOnMS; 3603 int ledOffMS = ledno.ledOffMS; 3604 if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0) { 3605 ledARGB = mDefaultNotificationColor; 3606 ledOnMS = mDefaultNotificationLedOn; 3607 ledOffMS = mDefaultNotificationLedOff; 3608 } 3609 if (mNotificationPulseEnabled) { 3610 // pulse repeatedly 3611 mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED, 3612 ledOnMS, ledOffMS); 3613 } 3614 if (mStatusBar != null) { 3615 // let SystemUI make an independent decision 3616 mStatusBar.notificationLightPulse(ledARGB, ledOnMS, ledOffMS); 3617 } 3618 } 3619 } 3620 3621 // lock on mNotificationList 3622 int indexOfNotificationLocked(String pkg, String tag, int id, int userId) 3623 { 3624 ArrayList<NotificationRecord> list = mNotificationList; 3625 final int len = list.size(); 3626 for (int i=0; i<len; i++) { 3627 NotificationRecord r = list.get(i); 3628 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id && 3629 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) { 3630 return i; 3631 } 3632 } 3633 return -1; 3634 } 3635 3636 // lock on mNotificationList 3637 int indexOfNotificationLocked(String key) { 3638 final int N = mNotificationList.size(); 3639 for (int i = 0; i < N; i++) { 3640 if (key.equals(mNotificationList.get(i).getKey())) { 3641 return i; 3642 } 3643 } 3644 return -1; 3645 } 3646 3647 private void updateNotificationPulse() { 3648 synchronized (mNotificationList) { 3649 updateLightsLocked(); 3650 } 3651 } 3652 3653 private static boolean isUidSystem(int uid) { 3654 final int appid = UserHandle.getAppId(uid); 3655 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0); 3656 } 3657 3658 private static boolean isCallerSystem() { 3659 return isUidSystem(Binder.getCallingUid()); 3660 } 3661 3662 private static void checkCallerIsSystem() { 3663 if (isCallerSystem()) { 3664 return; 3665 } 3666 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid()); 3667 } 3668 3669 private static void checkCallerIsSystemOrSameApp(String pkg) { 3670 if (isCallerSystem()) { 3671 return; 3672 } 3673 final int uid = Binder.getCallingUid(); 3674 try { 3675 ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo( 3676 pkg, 0, UserHandle.getCallingUserId()); 3677 if (ai == null) { 3678 throw new SecurityException("Unknown package " + pkg); 3679 } 3680 if (!UserHandle.isSameApp(ai.uid, uid)) { 3681 throw new SecurityException("Calling uid " + uid + " gave package" 3682 + pkg + " which is owned by uid " + ai.uid); 3683 } 3684 } catch (RemoteException re) { 3685 throw new SecurityException("Unknown package " + pkg + "\n" + re); 3686 } 3687 } 3688 3689 private static String callStateToString(int state) { 3690 switch (state) { 3691 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE"; 3692 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING"; 3693 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK"; 3694 default: return "CALL_STATE_UNKNOWN_" + state; 3695 } 3696 } 3697 3698 private void listenForCallState() { 3699 TelephonyManager.from(getContext()).listen(new PhoneStateListener() { 3700 @Override 3701 public void onCallStateChanged(int state, String incomingNumber) { 3702 if (mCallState == state) return; 3703 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state)); 3704 mCallState = state; 3705 } 3706 }, PhoneStateListener.LISTEN_CALL_STATE); 3707 } 3708 3709 /** 3710 * Generates a NotificationRankingUpdate from 'sbns', considering only 3711 * notifications visible to the given listener. 3712 * 3713 * <p>Caller must hold a lock on mNotificationList.</p> 3714 */ 3715 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) { 3716 final int N = mNotificationList.size(); 3717 ArrayList<String> keys = new ArrayList<String>(N); 3718 ArrayList<String> interceptedKeys = new ArrayList<String>(N); 3719 ArrayList<Integer> importance = new ArrayList<>(N); 3720 Bundle overrideGroupKeys = new Bundle(); 3721 Bundle visibilityOverrides = new Bundle(); 3722 Bundle suppressedVisualEffects = new Bundle(); 3723 Bundle explanation = new Bundle(); 3724 for (int i = 0; i < N; i++) { 3725 NotificationRecord record = mNotificationList.get(i); 3726 if (!isVisibleToListener(record.sbn, info)) { 3727 continue; 3728 } 3729 final String key = record.sbn.getKey(); 3730 keys.add(key); 3731 importance.add(record.getImportance()); 3732 if (record.getImportanceExplanation() != null) { 3733 explanation.putCharSequence(key, record.getImportanceExplanation()); 3734 } 3735 if (record.isIntercepted()) { 3736 interceptedKeys.add(key); 3737 3738 } 3739 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects()); 3740 if (record.getPackageVisibilityOverride() 3741 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) { 3742 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride()); 3743 } 3744 overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey()); 3745 } 3746 final int M = keys.size(); 3747 String[] keysAr = keys.toArray(new String[M]); 3748 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]); 3749 int[] importanceAr = new int[M]; 3750 for (int i = 0; i < M; i++) { 3751 importanceAr[i] = importance.get(i); 3752 } 3753 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides, 3754 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys); 3755 } 3756 3757 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) { 3758 if (!listener.enabledAndUserMatches(sbn.getUserId())) { 3759 return false; 3760 } 3761 // TODO: remove this for older listeners. 3762 return true; 3763 } 3764 3765 private boolean isPackageSuspendedForUser(String pkg, int uid) { 3766 int userId = UserHandle.getUserId(uid); 3767 try { 3768 return AppGlobals.getPackageManager().isPackageSuspendedForUser(pkg, userId); 3769 } catch (RemoteException re) { 3770 throw new SecurityException("Could not talk to package manager service"); 3771 } catch (IllegalArgumentException ex) { 3772 // Package not found. 3773 return false; 3774 } 3775 } 3776 3777 private class TrimCache { 3778 StatusBarNotification heavy; 3779 StatusBarNotification sbnClone; 3780 StatusBarNotification sbnCloneLight; 3781 3782 TrimCache(StatusBarNotification sbn) { 3783 heavy = sbn; 3784 } 3785 3786 StatusBarNotification ForListener(ManagedServiceInfo info) { 3787 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) { 3788 if (sbnCloneLight == null) { 3789 sbnCloneLight = heavy.cloneLight(); 3790 } 3791 return sbnCloneLight; 3792 } else { 3793 if (sbnClone == null) { 3794 sbnClone = heavy.clone(); 3795 } 3796 return sbnClone; 3797 } 3798 } 3799 } 3800 3801 public class NotificationRankers extends ManagedServices { 3802 3803 public NotificationRankers() { 3804 super(getContext(), mHandler, mNotificationList, mUserProfiles); 3805 } 3806 3807 @Override 3808 protected Config getConfig() { 3809 Config c = new Config(); 3810 c.caption = "notification ranker service"; 3811 c.serviceInterface = NotificationRankerService.SERVICE_INTERFACE; 3812 c.secureSettingName = null; 3813 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_RANKER_SERVICE; 3814 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS; 3815 c.clientLabel = R.string.notification_ranker_binding_label; 3816 return c; 3817 } 3818 3819 @Override 3820 protected IInterface asInterface(IBinder binder) { 3821 return INotificationListener.Stub.asInterface(binder); 3822 } 3823 3824 @Override 3825 protected boolean checkType(IInterface service) { 3826 return service instanceof INotificationListener; 3827 } 3828 3829 @Override 3830 protected void onServiceAdded(ManagedServiceInfo info) { 3831 mListeners.registerGuestService(info); 3832 } 3833 3834 @Override 3835 protected void onServiceRemovedLocked(ManagedServiceInfo removed) { 3836 mListeners.unregisterService(removed.service, removed.userid); 3837 } 3838 3839 public void onNotificationEnqueued(final NotificationRecord r) { 3840 final StatusBarNotification sbn = r.sbn; 3841 TrimCache trimCache = new TrimCache(sbn); 3842 3843 // mServices is the list inside ManagedServices of all the rankers, 3844 // There should be only one, but it's a list, so while we enforce 3845 // singularity elsewhere, we keep it general here, to avoid surprises. 3846 for (final ManagedServiceInfo info : NotificationRankers.this.mServices) { 3847 boolean sbnVisible = isVisibleToListener(sbn, info); 3848 if (!sbnVisible) { 3849 continue; 3850 } 3851 3852 final int importance = r.getImportance(); 3853 final boolean fromUser = r.isImportanceFromUser(); 3854 final StatusBarNotification sbnToPost = trimCache.ForListener(info); 3855 mHandler.post(new Runnable() { 3856 @Override 3857 public void run() { 3858 notifyEnqueued(info, sbnToPost, importance, fromUser); 3859 } 3860 }); 3861 } 3862 } 3863 3864 private void notifyEnqueued(final ManagedServiceInfo info, 3865 final StatusBarNotification sbn, int importance, boolean fromUser) { 3866 final INotificationListener ranker = (INotificationListener) info.service; 3867 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); 3868 try { 3869 ranker.onNotificationEnqueued(sbnHolder, importance, fromUser); 3870 } catch (RemoteException ex) { 3871 Log.e(TAG, "unable to notify ranker (enqueued): " + ranker, ex); 3872 } 3873 } 3874 3875 public boolean isEnabled() { 3876 return !mServices.isEmpty(); 3877 } 3878 3879 @Override 3880 public void onUserSwitched(int user) { 3881 synchronized (mNotificationList) { 3882 for (ManagedServiceInfo info : mServices) { 3883 unregisterService(info.service, info.userid); 3884 } 3885 } 3886 registerRanker(); 3887 } 3888 3889 @Override 3890 public void onPackagesChanged(boolean queryReplace, String[] pkgList) { 3891 if (DEBUG) Slog.d(TAG, "onPackagesChanged queryReplace=" + queryReplace 3892 + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList))); 3893 if (mRankerServicePackageName == null) { 3894 return; 3895 } 3896 3897 if (pkgList != null && (pkgList.length > 0)) { 3898 for (String pkgName : pkgList) { 3899 if (mRankerServicePackageName.equals(pkgName)) { 3900 registerRanker(); 3901 } 3902 } 3903 } 3904 } 3905 3906 protected void registerRanker() { 3907 // Find the updatable ranker and register it. 3908 if (mRankerServicePackageName == null) { 3909 Slog.w(TAG, "could not start ranker service: no package specified!"); 3910 return; 3911 } 3912 Set<ComponentName> rankerComponents = queryPackageForServices( 3913 mRankerServicePackageName, UserHandle.USER_SYSTEM); 3914 Iterator<ComponentName> iterator = rankerComponents.iterator(); 3915 if (iterator.hasNext()) { 3916 ComponentName rankerComponent = iterator.next(); 3917 if (iterator.hasNext()) { 3918 Slog.e(TAG, "found multiple ranker services:" + rankerComponents); 3919 } else { 3920 registerSystemService(rankerComponent, UserHandle.USER_SYSTEM); 3921 } 3922 } else { 3923 Slog.w(TAG, "could not start ranker service: none found"); 3924 } 3925 } 3926 } 3927 3928 public class NotificationListeners extends ManagedServices { 3929 3930 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>(); 3931 3932 public NotificationListeners() { 3933 super(getContext(), mHandler, mNotificationList, mUserProfiles); 3934 } 3935 3936 @Override 3937 protected Config getConfig() { 3938 Config c = new Config(); 3939 c.caption = "notification listener"; 3940 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE; 3941 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS; 3942 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE; 3943 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS; 3944 c.clientLabel = R.string.notification_listener_binding_label; 3945 return c; 3946 } 3947 3948 @Override 3949 protected IInterface asInterface(IBinder binder) { 3950 return INotificationListener.Stub.asInterface(binder); 3951 } 3952 3953 @Override 3954 protected boolean checkType(IInterface service) { 3955 return service instanceof INotificationListener; 3956 } 3957 3958 @Override 3959 public void onServiceAdded(ManagedServiceInfo info) { 3960 final INotificationListener listener = (INotificationListener) info.service; 3961 final NotificationRankingUpdate update; 3962 synchronized (mNotificationList) { 3963 update = makeRankingUpdateLocked(info); 3964 } 3965 try { 3966 listener.onListenerConnected(update); 3967 } catch (RemoteException e) { 3968 // we tried 3969 } 3970 } 3971 3972 @Override 3973 protected void onServiceRemovedLocked(ManagedServiceInfo removed) { 3974 if (removeDisabledHints(removed)) { 3975 updateListenerHintsLocked(); 3976 updateEffectsSuppressorLocked(); 3977 } 3978 mLightTrimListeners.remove(removed); 3979 } 3980 3981 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) { 3982 if (trim == TRIM_LIGHT) { 3983 mLightTrimListeners.add(info); 3984 } else { 3985 mLightTrimListeners.remove(info); 3986 } 3987 } 3988 3989 public int getOnNotificationPostedTrim(ManagedServiceInfo info) { 3990 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL; 3991 } 3992 3993 /** 3994 * asynchronously notify all listeners about a new notification 3995 * 3996 * <p> 3997 * Also takes care of removing a notification that has been visible to a listener before, 3998 * but isn't anymore. 3999 */ 4000 public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) { 4001 // Lazily initialized snapshots of the notification. 4002 TrimCache trimCache = new TrimCache(sbn); 4003 4004 for (final ManagedServiceInfo info : mServices) { 4005 boolean sbnVisible = isVisibleToListener(sbn, info); 4006 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false; 4007 // This notification hasn't been and still isn't visible -> ignore. 4008 if (!oldSbnVisible && !sbnVisible) { 4009 continue; 4010 } 4011 final NotificationRankingUpdate update = makeRankingUpdateLocked(info); 4012 4013 // This notification became invisible -> remove the old one. 4014 if (oldSbnVisible && !sbnVisible) { 4015 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight(); 4016 mHandler.post(new Runnable() { 4017 @Override 4018 public void run() { 4019 notifyRemoved(info, oldSbnLightClone, update); 4020 } 4021 }); 4022 continue; 4023 } 4024 4025 final StatusBarNotification sbnToPost = trimCache.ForListener(info); 4026 mHandler.post(new Runnable() { 4027 @Override 4028 public void run() { 4029 notifyPosted(info, sbnToPost, update); 4030 } 4031 }); 4032 } 4033 } 4034 4035 /** 4036 * asynchronously notify all listeners about a removed notification 4037 */ 4038 public void notifyRemovedLocked(StatusBarNotification sbn) { 4039 // make a copy in case changes are made to the underlying Notification object 4040 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the 4041 // notification 4042 final StatusBarNotification sbnLight = sbn.cloneLight(); 4043 for (final ManagedServiceInfo info : mServices) { 4044 if (!isVisibleToListener(sbn, info)) { 4045 continue; 4046 } 4047 final NotificationRankingUpdate update = makeRankingUpdateLocked(info); 4048 mHandler.post(new Runnable() { 4049 @Override 4050 public void run() { 4051 notifyRemoved(info, sbnLight, update); 4052 } 4053 }); 4054 } 4055 } 4056 4057 /** 4058 * asynchronously notify all listeners about a reordering of notifications 4059 */ 4060 public void notifyRankingUpdateLocked() { 4061 for (final ManagedServiceInfo serviceInfo : mServices) { 4062 if (!serviceInfo.isEnabledForCurrentProfiles()) { 4063 continue; 4064 } 4065 final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo); 4066 mHandler.post(new Runnable() { 4067 @Override 4068 public void run() { 4069 notifyRankingUpdate(serviceInfo, update); 4070 } 4071 }); 4072 } 4073 } 4074 4075 public void notifyListenerHintsChangedLocked(final int hints) { 4076 for (final ManagedServiceInfo serviceInfo : mServices) { 4077 if (!serviceInfo.isEnabledForCurrentProfiles()) { 4078 continue; 4079 } 4080 mHandler.post(new Runnable() { 4081 @Override 4082 public void run() { 4083 notifyListenerHintsChanged(serviceInfo, hints); 4084 } 4085 }); 4086 } 4087 } 4088 4089 public void notifyInterruptionFilterChanged(final int interruptionFilter) { 4090 for (final ManagedServiceInfo serviceInfo : mServices) { 4091 if (!serviceInfo.isEnabledForCurrentProfiles()) { 4092 continue; 4093 } 4094 mHandler.post(new Runnable() { 4095 @Override 4096 public void run() { 4097 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter); 4098 } 4099 }); 4100 } 4101 } 4102 4103 private void notifyPosted(final ManagedServiceInfo info, 4104 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) { 4105 final INotificationListener listener = (INotificationListener)info.service; 4106 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); 4107 try { 4108 listener.onNotificationPosted(sbnHolder, rankingUpdate); 4109 } catch (RemoteException ex) { 4110 Log.e(TAG, "unable to notify listener (posted): " + listener, ex); 4111 } 4112 } 4113 4114 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn, 4115 NotificationRankingUpdate rankingUpdate) { 4116 if (!info.enabledAndUserMatches(sbn.getUserId())) { 4117 return; 4118 } 4119 final INotificationListener listener = (INotificationListener) info.service; 4120 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); 4121 try { 4122 listener.onNotificationRemoved(sbnHolder, rankingUpdate); 4123 } catch (RemoteException ex) { 4124 Log.e(TAG, "unable to notify listener (removed): " + listener, ex); 4125 } 4126 } 4127 4128 private void notifyRankingUpdate(ManagedServiceInfo info, 4129 NotificationRankingUpdate rankingUpdate) { 4130 final INotificationListener listener = (INotificationListener) info.service; 4131 try { 4132 listener.onNotificationRankingUpdate(rankingUpdate); 4133 } catch (RemoteException ex) { 4134 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex); 4135 } 4136 } 4137 4138 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) { 4139 final INotificationListener listener = (INotificationListener) info.service; 4140 try { 4141 listener.onListenerHintsChanged(hints); 4142 } catch (RemoteException ex) { 4143 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex); 4144 } 4145 } 4146 4147 private void notifyInterruptionFilterChanged(ManagedServiceInfo info, 4148 int interruptionFilter) { 4149 final INotificationListener listener = (INotificationListener) info.service; 4150 try { 4151 listener.onInterruptionFilterChanged(interruptionFilter); 4152 } catch (RemoteException ex) { 4153 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex); 4154 } 4155 } 4156 4157 private boolean isListenerPackage(String packageName) { 4158 if (packageName == null) { 4159 return false; 4160 } 4161 // TODO: clean up locking object later 4162 synchronized (mNotificationList) { 4163 for (final ManagedServiceInfo serviceInfo : mServices) { 4164 if (packageName.equals(serviceInfo.component.getPackageName())) { 4165 return true; 4166 } 4167 } 4168 } 4169 return false; 4170 } 4171 } 4172 4173 public static final class DumpFilter { 4174 public boolean filtered = false; 4175 public String pkgFilter; 4176 public boolean zen; 4177 public long since; 4178 public boolean stats; 4179 public boolean redact = true; 4180 4181 public static DumpFilter parseFromArguments(String[] args) { 4182 final DumpFilter filter = new DumpFilter(); 4183 for (int ai = 0; ai < args.length; ai++) { 4184 final String a = args[ai]; 4185 if ("--noredact".equals(a) || "--reveal".equals(a)) { 4186 filter.redact = false; 4187 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) { 4188 if (ai < args.length-1) { 4189 ai++; 4190 filter.pkgFilter = args[ai].trim().toLowerCase(); 4191 if (filter.pkgFilter.isEmpty()) { 4192 filter.pkgFilter = null; 4193 } else { 4194 filter.filtered = true; 4195 } 4196 } 4197 } else if ("--zen".equals(a) || "zen".equals(a)) { 4198 filter.filtered = true; 4199 filter.zen = true; 4200 } else if ("--stats".equals(a)) { 4201 filter.stats = true; 4202 if (ai < args.length-1) { 4203 ai++; 4204 filter.since = Long.valueOf(args[ai]); 4205 } else { 4206 filter.since = 0; 4207 } 4208 } 4209 } 4210 return filter; 4211 } 4212 4213 public boolean matches(StatusBarNotification sbn) { 4214 if (!filtered) return true; 4215 return zen ? true : sbn != null 4216 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg())); 4217 } 4218 4219 public boolean matches(ComponentName component) { 4220 if (!filtered) return true; 4221 return zen ? true : component != null && matches(component.getPackageName()); 4222 } 4223 4224 public boolean matches(String pkg) { 4225 if (!filtered) return true; 4226 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter); 4227 } 4228 4229 @Override 4230 public String toString() { 4231 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\''); 4232 } 4233 } 4234 4235 /** 4236 * Wrapper for a StatusBarNotification object that allows transfer across a oneway 4237 * binder without sending large amounts of data over a oneway transaction. 4238 */ 4239 private static final class StatusBarNotificationHolder 4240 extends IStatusBarNotificationHolder.Stub { 4241 private StatusBarNotification mValue; 4242 4243 public StatusBarNotificationHolder(StatusBarNotification value) { 4244 mValue = value; 4245 } 4246 4247 /** Get the held value and clear it. This function should only be called once per holder */ 4248 @Override 4249 public StatusBarNotification get() { 4250 StatusBarNotification value = mValue; 4251 mValue = null; 4252 return value; 4253 } 4254 } 4255 4256 private final class PolicyAccess { 4257 private static final String SEPARATOR = ":"; 4258 private final String[] PERM = { 4259 android.Manifest.permission.ACCESS_NOTIFICATION_POLICY 4260 }; 4261 4262 public boolean isPackageGranted(String pkg) { 4263 return pkg != null && getGrantedPackages().contains(pkg); 4264 } 4265 4266 public void put(String pkg, boolean granted) { 4267 if (pkg == null) return; 4268 final ArraySet<String> pkgs = getGrantedPackages(); 4269 boolean changed; 4270 if (granted) { 4271 changed = pkgs.add(pkg); 4272 } else { 4273 changed = pkgs.remove(pkg); 4274 } 4275 if (!changed) return; 4276 final String setting = TextUtils.join(SEPARATOR, pkgs); 4277 final int currentUser = ActivityManager.getCurrentUser(); 4278 Settings.Secure.putStringForUser(getContext().getContentResolver(), 4279 Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES, 4280 setting, 4281 currentUser); 4282 getContext().sendBroadcastAsUser(new Intent(NotificationManager 4283 .ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED) 4284 .setPackage(pkg) 4285 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), new UserHandle(currentUser), null); 4286 } 4287 4288 public ArraySet<String> getGrantedPackages() { 4289 final ArraySet<String> pkgs = new ArraySet<>(); 4290 4291 long identity = Binder.clearCallingIdentity(); 4292 try { 4293 final String setting = Settings.Secure.getStringForUser( 4294 getContext().getContentResolver(), 4295 Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES, 4296 ActivityManager.getCurrentUser()); 4297 if (setting != null) { 4298 final String[] tokens = setting.split(SEPARATOR); 4299 for (int i = 0; i < tokens.length; i++) { 4300 String token = tokens[i]; 4301 if (token != null) { 4302 token = token.trim(); 4303 } 4304 if (TextUtils.isEmpty(token)) { 4305 continue; 4306 } 4307 pkgs.add(token); 4308 } 4309 } 4310 } finally { 4311 Binder.restoreCallingIdentity(identity); 4312 } 4313 return pkgs; 4314 } 4315 4316 public String[] getRequestingPackages() throws RemoteException { 4317 final ParceledListSlice list = AppGlobals.getPackageManager() 4318 .getPackagesHoldingPermissions(PERM, 0 /*flags*/, 4319 ActivityManager.getCurrentUser()); 4320 final List<PackageInfo> pkgs = list.getList(); 4321 if (pkgs == null || pkgs.isEmpty()) return new String[0]; 4322 final int N = pkgs.size(); 4323 final String[] rt = new String[N]; 4324 for (int i = 0; i < N; i++) { 4325 rt[i] = pkgs.get(i).packageName; 4326 } 4327 return rt; 4328 } 4329 } 4330} 4331