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