NotificationManager.java revision 1fc476d51203c0b76ebd0f2062adf3059437b0dc
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 android.app; 18 19import android.annotation.NonNull; 20import android.annotation.Nullable; 21import android.annotation.SdkConstant; 22import android.app.Notification.Builder; 23import android.app.NotificationManager.Policy.Token; 24import android.content.ComponentName; 25import android.content.Context; 26import android.net.Uri; 27import android.os.Bundle; 28import android.os.Handler; 29import android.os.IBinder; 30import android.os.Parcel; 31import android.os.Parcelable; 32import android.os.RemoteException; 33import android.os.ServiceManager; 34import android.os.StrictMode; 35import android.os.UserHandle; 36import android.provider.Settings.Global; 37import android.service.notification.IConditionListener; 38import android.service.notification.ZenModeConfig; 39import android.util.Log; 40 41import java.util.Objects; 42 43/** 44 * Class to notify the user of events that happen. This is how you tell 45 * the user that something has happened in the background. {@more} 46 * 47 * Notifications can take different forms: 48 * <ul> 49 * <li>A persistent icon that goes in the status bar and is accessible 50 * through the launcher, (when the user selects it, a designated Intent 51 * can be launched),</li> 52 * <li>Turning on or flashing LEDs on the device, or</li> 53 * <li>Alerting the user by flashing the backlight, playing a sound, 54 * or vibrating.</li> 55 * </ul> 56 * 57 * <p> 58 * Each of the notify methods takes an int id parameter and optionally a 59 * {@link String} tag parameter, which may be {@code null}. These parameters 60 * are used to form a pair (tag, id), or ({@code null}, id) if tag is 61 * unspecified. This pair identifies this notification from your app to the 62 * system, so that pair should be unique within your app. If you call one 63 * of the notify methods with a (tag, id) pair that is currently active and 64 * a new set of notification parameters, it will be updated. For example, 65 * if you pass a new status bar icon, the old icon in the status bar will 66 * be replaced with the new one. This is also the same tag and id you pass 67 * to the {@link #cancel(int)} or {@link #cancel(String, int)} method to clear 68 * this notification. 69 * 70 * <p> 71 * You do not instantiate this class directly; instead, retrieve it through 72 * {@link android.content.Context#getSystemService}. 73 * 74 * <div class="special reference"> 75 * <h3>Developer Guides</h3> 76 * <p>For a guide to creating notifications, read the 77 * <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Status Bar Notifications</a> 78 * developer guide.</p> 79 * </div> 80 * 81 * @see android.app.Notification 82 * @see android.content.Context#getSystemService 83 */ 84public class NotificationManager 85{ 86 private static String TAG = "NotificationManager"; 87 private static boolean localLOGV = false; 88 89 /** 90 * Intent that is broadcast when the state of {@link #getEffectsSuppressor()} changes. 91 * This broadcast is only sent to registered receivers. 92 * 93 * @hide 94 */ 95 @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION) 96 public static final String ACTION_EFFECTS_SUPPRESSOR_CHANGED 97 = "android.os.action.ACTION_EFFECTS_SUPPRESSOR_CHANGED"; 98 99 /** 100 * Intent that is broadcast when the state of getNotificationPolicy() changes. 101 * This broadcast is only sent to registered receivers. 102 */ 103 @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION) 104 public static final String ACTION_NOTIFICATION_POLICY_CHANGED 105 = "android.app.action.NOTIFICATION_POLICY_CHANGED"; 106 107 private static INotificationManager sService; 108 109 /** @hide */ 110 static public INotificationManager getService() 111 { 112 if (sService != null) { 113 return sService; 114 } 115 IBinder b = ServiceManager.getService("notification"); 116 sService = INotificationManager.Stub.asInterface(b); 117 return sService; 118 } 119 120 /*package*/ NotificationManager(Context context, Handler handler) 121 { 122 mContext = context; 123 } 124 125 /** {@hide} */ 126 public static NotificationManager from(Context context) { 127 return (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 128 } 129 130 /** 131 * Post a notification to be shown in the status bar. If a notification with 132 * the same id has already been posted by your application and has not yet been canceled, it 133 * will be replaced by the updated information. 134 * 135 * @param id An identifier for this notification unique within your 136 * application. 137 * @param notification A {@link Notification} object describing what to show the user. Must not 138 * be null. 139 */ 140 public void notify(int id, Notification notification) 141 { 142 notify(null, id, notification); 143 } 144 145 /** 146 * Post a notification to be shown in the status bar. If a notification with 147 * the same tag and id has already been posted by your application and has not yet been 148 * canceled, it will be replaced by the updated information. 149 * 150 * @param tag A string identifier for this notification. May be {@code null}. 151 * @param id An identifier for this notification. The pair (tag, id) must be unique 152 * within your application. 153 * @param notification A {@link Notification} object describing what to 154 * show the user. Must not be null. 155 */ 156 public void notify(String tag, int id, Notification notification) 157 { 158 int[] idOut = new int[1]; 159 INotificationManager service = getService(); 160 String pkg = mContext.getPackageName(); 161 if (notification.sound != null) { 162 notification.sound = notification.sound.getCanonicalUri(); 163 if (StrictMode.vmFileUriExposureEnabled()) { 164 notification.sound.checkFileUriExposed("Notification.sound"); 165 } 166 } 167 if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")"); 168 Notification stripped = notification.clone(); 169 Builder.stripForDelivery(stripped); 170 try { 171 service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id, 172 stripped, idOut, UserHandle.myUserId()); 173 if (id != idOut[0]) { 174 Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]); 175 } 176 } catch (RemoteException e) { 177 } 178 } 179 180 /** 181 * @hide 182 */ 183 public void notifyAsUser(String tag, int id, Notification notification, UserHandle user) 184 { 185 int[] idOut = new int[1]; 186 INotificationManager service = getService(); 187 String pkg = mContext.getPackageName(); 188 if (notification.sound != null) { 189 notification.sound = notification.sound.getCanonicalUri(); 190 if (StrictMode.vmFileUriExposureEnabled()) { 191 notification.sound.checkFileUriExposed("Notification.sound"); 192 } 193 } 194 if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")"); 195 Notification stripped = notification.clone(); 196 Builder.stripForDelivery(stripped); 197 try { 198 service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id, 199 stripped, idOut, user.getIdentifier()); 200 if (id != idOut[0]) { 201 Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]); 202 } 203 } catch (RemoteException e) { 204 } 205 } 206 207 /** 208 * Cancel a previously shown notification. If it's transient, the view 209 * will be hidden. If it's persistent, it will be removed from the status 210 * bar. 211 */ 212 public void cancel(int id) 213 { 214 cancel(null, id); 215 } 216 217 /** 218 * Cancel a previously shown notification. If it's transient, the view 219 * will be hidden. If it's persistent, it will be removed from the status 220 * bar. 221 */ 222 public void cancel(String tag, int id) 223 { 224 INotificationManager service = getService(); 225 String pkg = mContext.getPackageName(); 226 if (localLOGV) Log.v(TAG, pkg + ": cancel(" + id + ")"); 227 try { 228 service.cancelNotificationWithTag(pkg, tag, id, UserHandle.myUserId()); 229 } catch (RemoteException e) { 230 } 231 } 232 233 /** 234 * @hide 235 */ 236 public void cancelAsUser(String tag, int id, UserHandle user) 237 { 238 INotificationManager service = getService(); 239 String pkg = mContext.getPackageName(); 240 if (localLOGV) Log.v(TAG, pkg + ": cancel(" + id + ")"); 241 try { 242 service.cancelNotificationWithTag(pkg, tag, id, user.getIdentifier()); 243 } catch (RemoteException e) { 244 } 245 } 246 247 /** 248 * Cancel all previously shown notifications. See {@link #cancel} for the 249 * detailed behavior. 250 */ 251 public void cancelAll() 252 { 253 INotificationManager service = getService(); 254 String pkg = mContext.getPackageName(); 255 if (localLOGV) Log.v(TAG, pkg + ": cancelAll()"); 256 try { 257 service.cancelAllNotifications(pkg, UserHandle.myUserId()); 258 } catch (RemoteException e) { 259 } 260 } 261 262 /** 263 * @hide 264 */ 265 public ComponentName getEffectsSuppressor() { 266 INotificationManager service = getService(); 267 try { 268 return service.getEffectsSuppressor(); 269 } catch (RemoteException e) { 270 return null; 271 } 272 } 273 274 /** 275 * @hide 276 */ 277 public boolean matchesCallFilter(Bundle extras) { 278 INotificationManager service = getService(); 279 try { 280 return service.matchesCallFilter(extras); 281 } catch (RemoteException e) { 282 return false; 283 } 284 } 285 286 /** 287 * @hide 288 */ 289 public boolean isSystemConditionProviderEnabled(String path) { 290 INotificationManager service = getService(); 291 try { 292 return service.isSystemConditionProviderEnabled(path); 293 } catch (RemoteException e) { 294 return false; 295 } 296 } 297 298 /** 299 * @hide 300 */ 301 public void setZenMode(int mode, Uri conditionId, String reason) { 302 INotificationManager service = getService(); 303 try { 304 service.setZenMode(mode, conditionId, reason); 305 } catch (RemoteException e) { 306 } 307 } 308 309 /** 310 * @hide 311 */ 312 public boolean setZenModeConfig(ZenModeConfig config, String reason) { 313 INotificationManager service = getService(); 314 try { 315 return service.setZenModeConfig(config, reason); 316 } catch (RemoteException e) { 317 return false; 318 } 319 } 320 321 /** 322 * @hide 323 */ 324 public void requestZenModeConditions(IConditionListener listener, int relevance) { 325 INotificationManager service = getService(); 326 try { 327 service.requestZenModeConditions(listener, relevance); 328 } catch (RemoteException e) { 329 } 330 } 331 332 /** 333 * @hide 334 */ 335 public int getZenMode() { 336 INotificationManager service = getService(); 337 try { 338 return service.getZenMode(); 339 } catch (RemoteException e) { 340 } 341 return Global.ZEN_MODE_OFF; 342 } 343 344 /** 345 * @hide 346 */ 347 public ZenModeConfig getZenModeConfig() { 348 INotificationManager service = getService(); 349 try { 350 return service.getZenModeConfig(); 351 } catch (RemoteException e) { 352 } 353 return null; 354 } 355 356 /** 357 * Requests a notification policy token for the calling package. 358 * 359 * @param callback required, used to receive the granted token or the deny signal. 360 * @param handler The handler used when receiving the result. 361 * If null, the current thread is used. 362 */ 363 public void requestNotificationPolicyToken(@NonNull final Policy.Token.RequestCallback callback, 364 @Nullable Handler handler) { 365 checkRequired("callback", callback); 366 final Handler h = handler != null ? handler : new Handler(); 367 INotificationManager service = getService(); 368 try { 369 service.requestNotificationPolicyToken(mContext.getOpPackageName(), 370 new INotificationManagerCallback.Stub() { 371 @Override 372 public void onPolicyToken(final Token token) throws RemoteException { 373 h.post(new Runnable() { 374 @Override 375 public void run() { 376 if (token != null) { 377 callback.onTokenGranted(token); 378 } else { 379 callback.onTokenDenied(); 380 } 381 } 382 }); 383 } 384 }); 385 } catch (RemoteException e) { 386 } 387 } 388 389 /** 390 * Checks a given notification policy token. 391 * 392 * Returns true if the token is still valid for managing policy. 393 */ 394 public boolean isNotificationPolicyTokenValid(@NonNull Policy.Token token) { 395 if (token == null) return false; 396 INotificationManager service = getService(); 397 try { 398 return service.isNotificationPolicyTokenValid(mContext.getOpPackageName(), token); 399 } catch (RemoteException e) { 400 } 401 return false; 402 } 403 404 /** 405 * Gets the current notification policy. 406 * 407 * @param token A valid notification policy token is required to access the current policy. 408 */ 409 public Policy getNotificationPolicy(@NonNull Policy.Token token) { 410 checkRequired("token", token); 411 INotificationManager service = getService(); 412 try { 413 return service.getNotificationPolicy(token); 414 } catch (RemoteException e) { 415 } 416 return null; 417 } 418 419 /** 420 * Sets the current notification policy. 421 * 422 * @param token A valid notification policy token is required to modify the current policy. 423 * @param policy The new desired policy. 424 */ 425 public void setNotificationPolicy(@NonNull Policy.Token token, @NonNull Policy policy) { 426 checkRequired("token", token); 427 checkRequired("policy", policy); 428 INotificationManager service = getService(); 429 try { 430 service.setNotificationPolicy(token, policy); 431 } catch (RemoteException e) { 432 } 433 } 434 435 private Context mContext; 436 437 private static void checkRequired(String name, Object value) { 438 if (value == null) { 439 throw new IllegalArgumentException(name + " is required"); 440 } 441 } 442 443 /** 444 * Notification policy configuration. Represents user-preferences for notification 445 * filtering and prioritization. 446 */ 447 public static class Policy implements android.os.Parcelable { 448 /** Reminder notifications are prioritized. */ 449 public static final int PRIORITY_CATEGORY_REMINDERS = 1 << 0; 450 /** Event notifications are prioritized. */ 451 public static final int PRIORITY_CATEGORY_EVENTS = 1 << 1; 452 /** Message notifications are prioritized. */ 453 public static final int PRIORITY_CATEGORY_MESSAGES = 1 << 2; 454 /** Calls are prioritized. */ 455 public static final int PRIORITY_CATEGORY_CALLS = 1 << 3; 456 /** Calls from repeat callers are prioritized. */ 457 public static final int PRIORITY_CATEGORY_REPEAT_CALLERS = 1 << 4; 458 459 private static final int[] ALL_PRIORITY_CATEGORIES = { 460 PRIORITY_CATEGORY_REMINDERS, 461 PRIORITY_CATEGORY_EVENTS, 462 PRIORITY_CATEGORY_MESSAGES, 463 PRIORITY_CATEGORY_CALLS, 464 PRIORITY_CATEGORY_REPEAT_CALLERS, 465 }; 466 467 /** Any sender is prioritized. */ 468 public static final int PRIORITY_SENDERS_ANY = 0; 469 /** Saved contacts are prioritized. */ 470 public static final int PRIORITY_SENDERS_CONTACTS = 1; 471 /** Only starred contacts are prioritized. */ 472 public static final int PRIORITY_SENDERS_STARRED = 2; 473 474 /** Notification categories to prioritize. Bitmask of PRIORITY_CATEGORY_* constants. */ 475 public final int priorityCategories; 476 477 /** Notification senders to prioritize. One of: 478 * PRIORITY_SENDERS_ANY, PRIORITY_SENDERS_CONTACTS, PRIORITY_SENDERS_STARRED */ 479 public final int prioritySenders; 480 481 public Policy(int priorityCategories, int prioritySenders) { 482 this.priorityCategories = priorityCategories; 483 this.prioritySenders = prioritySenders; 484 } 485 486 /** @hide */ 487 public Policy(Parcel source) { 488 this(source.readInt(), source.readInt()); 489 } 490 491 @Override 492 public void writeToParcel(Parcel dest, int flags) { 493 dest.writeInt(priorityCategories); 494 dest.writeInt(prioritySenders); 495 } 496 497 @Override 498 public int describeContents() { 499 return 0; 500 } 501 502 @Override 503 public int hashCode() { 504 return Objects.hash(priorityCategories, prioritySenders); 505 } 506 507 @Override 508 public boolean equals(Object o) { 509 if (!(o instanceof Policy)) return false; 510 if (o == this) return true; 511 final Policy other = (Policy) o; 512 return other.priorityCategories == priorityCategories 513 && other.prioritySenders == prioritySenders; 514 } 515 516 @Override 517 public String toString() { 518 return "NotificationManager.Policy[" 519 + "priorityCategories=" + priorityCategoriesToString(priorityCategories) 520 + ",prioritySenders=" + prioritySendersToString(prioritySenders) 521 + "]"; 522 } 523 524 public static String priorityCategoriesToString(int priorityCategories) { 525 if (priorityCategories == 0) return ""; 526 final StringBuilder sb = new StringBuilder(); 527 for (int i = 0; i < ALL_PRIORITY_CATEGORIES.length; i++) { 528 final int priorityCategory = ALL_PRIORITY_CATEGORIES[i]; 529 if ((priorityCategories & priorityCategory) != 0) { 530 if (sb.length() > 0) sb.append(','); 531 sb.append(priorityCategoryToString(priorityCategory)); 532 } 533 priorityCategories &= ~priorityCategory; 534 } 535 if (priorityCategories != 0) { 536 if (sb.length() > 0) sb.append(','); 537 sb.append("PRIORITY_CATEGORY_UNKNOWN_").append(priorityCategories); 538 } 539 return sb.toString(); 540 } 541 542 private static String priorityCategoryToString(int priorityCategory) { 543 switch (priorityCategory) { 544 case PRIORITY_CATEGORY_REMINDERS: return "PRIORITY_CATEGORY_REMINDERS"; 545 case PRIORITY_CATEGORY_EVENTS: return "PRIORITY_CATEGORY_EVENTS"; 546 case PRIORITY_CATEGORY_MESSAGES: return "PRIORITY_CATEGORY_MESSAGES"; 547 case PRIORITY_CATEGORY_CALLS: return "PRIORITY_CATEGORY_CALLS"; 548 case PRIORITY_CATEGORY_REPEAT_CALLERS: return "PRIORITY_CATEGORY_REPEAT_CALLERS"; 549 default: return "PRIORITY_CATEGORY_UNKNOWN_" + priorityCategory; 550 } 551 } 552 553 public static String prioritySendersToString(int prioritySenders) { 554 switch (prioritySenders) { 555 case PRIORITY_SENDERS_ANY: return "PRIORITY_SENDERS_ANY"; 556 case PRIORITY_SENDERS_CONTACTS: return "PRIORITY_SENDERS_CONTACTS"; 557 case PRIORITY_SENDERS_STARRED: return "PRIORITY_SENDERS_STARRED"; 558 default: return "PRIORITY_SENDERS_UNKNOWN_" + prioritySenders; 559 } 560 } 561 562 public static final Parcelable.Creator<Policy> CREATOR = new Parcelable.Creator<Policy>() { 563 @Override 564 public Policy createFromParcel(Parcel in) { 565 return new Policy(in); 566 } 567 568 @Override 569 public Policy[] newArray(int size) { 570 return new Policy[size]; 571 } 572 }; 573 574 /** 575 * Represents a client-specific token required to manage notification policy. 576 */ 577 public static class Token implements Parcelable { 578 private final IBinder mBinder; 579 580 /** @hide */ 581 public Token(IBinder binder) { 582 if (binder == null) throw new IllegalArgumentException("Binder required for token"); 583 mBinder = binder; 584 } 585 586 @Override 587 public int describeContents() { 588 return 0; 589 } 590 591 @Override 592 public int hashCode() { 593 return Objects.hash(mBinder); 594 } 595 596 @Override 597 public boolean equals(Object o) { 598 if (!(o instanceof Token)) return false; 599 if (o == this) return true; 600 final Token other = (Token) o; 601 return Objects.equals(other.mBinder, mBinder); 602 } 603 604 @Override 605 public String toString() { 606 return String.format("NotificationManager.Token[0x%08x]", 607 System.identityHashCode(mBinder)); 608 } 609 610 @Override 611 public void writeToParcel(Parcel dest, int flags) { 612 dest.writeStrongBinder(mBinder); 613 } 614 615 public static final Parcelable.Creator<Token> CREATOR 616 = new Parcelable.Creator<Token>() { 617 @Override 618 public Token createFromParcel(Parcel in) { 619 return new Token(in.readStrongBinder()); 620 } 621 622 @Override 623 public Token[] newArray(int size) { 624 return new Token[size]; 625 } 626 }; 627 628 /** Callback for receiving the result of a token request. */ 629 public static abstract class RequestCallback { 630 /** 631 * Received if the request was granted for this package. 632 * 633 * @param token can be used to manage notification policy. 634 */ 635 public abstract void onTokenGranted(Policy.Token token); 636 637 /** 638 * Received if the request was denied for this package. 639 */ 640 public abstract void onTokenDenied(); 641 } 642 } 643 } 644 645} 646