1 /* 2 * Copyright (C) 2016 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 package android.app; 17 18 import android.annotation.NonNull; 19 import android.annotation.Nullable; 20 import android.annotation.SystemApi; 21 import android.annotation.TestApi; 22 import android.app.NotificationManager.Importance; 23 import android.compat.annotation.UnsupportedAppUsage; 24 import android.content.ContentResolver; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.pm.ShortcutInfo; 28 import android.media.AudioAttributes; 29 import android.net.Uri; 30 import android.os.Parcel; 31 import android.os.Parcelable; 32 import android.provider.Settings; 33 import android.service.notification.NotificationListenerService; 34 import android.text.TextUtils; 35 import android.util.Slog; 36 import android.util.TypedXmlPullParser; 37 import android.util.TypedXmlSerializer; 38 import android.util.proto.ProtoOutputStream; 39 40 import com.android.internal.util.Preconditions; 41 import com.android.internal.util.XmlUtils; 42 43 import org.json.JSONException; 44 import org.json.JSONObject; 45 import org.xmlpull.v1.XmlPullParser; 46 import org.xmlpull.v1.XmlSerializer; 47 48 import java.io.IOException; 49 import java.io.PrintWriter; 50 import java.util.Arrays; 51 import java.util.Objects; 52 53 /** 54 * A representation of settings that apply to a collection of similarly themed notifications. 55 */ 56 public final class NotificationChannel implements Parcelable { 57 58 /** 59 * The id of the default channel for an app. This id is reserved by the system. All 60 * notifications posted from apps targeting {@link android.os.Build.VERSION_CODES#N_MR1} or 61 * earlier without a notification channel specified are posted to this channel. 62 */ 63 public static final String DEFAULT_CHANNEL_ID = "miscellaneous"; 64 65 /** 66 * The formatter used by the system to create an id for notification 67 * channels when it automatically creates conversation channels on behalf of an app. The format 68 * string takes two arguments, in this order: the 69 * {@link #getId()} of the original notification channel, and the 70 * {@link ShortcutInfo#getId() id} of the conversation. 71 * @hide 72 */ 73 public static final String CONVERSATION_CHANNEL_ID_FORMAT = "%1$s : %2$s"; 74 75 /** 76 * TODO: STOPSHIP remove 77 * Conversation id to use for apps that aren't providing them yet. 78 * @hide 79 */ 80 public static final String PLACEHOLDER_CONVERSATION_ID = ":placeholder_id"; 81 82 /** 83 * Extra value for {@link Settings#EXTRA_CHANNEL_FILTER_LIST}. Include to show fields 84 * that have to do with editing sound, like a tone picker 85 * ({@link #setSound(Uri, AudioAttributes)}). 86 */ 87 public static final String EDIT_SOUND = "sound"; 88 /** 89 * Extra value for {@link Settings#EXTRA_CHANNEL_FILTER_LIST}. Include to show fields 90 * that have to do with editing vibration ({@link #enableVibration(boolean)}, 91 * {@link #setVibrationPattern(long[])}). 92 */ 93 public static final String EDIT_VIBRATION = "vibration"; 94 /** 95 * Extra value for {@link Settings#EXTRA_CHANNEL_FILTER_LIST}. Include to show fields 96 * that have to do with editing importance ({@link #setImportance(int)}) and/or conversation 97 * priority. 98 */ 99 public static final String EDIT_IMPORTANCE = "importance"; 100 /** 101 * Extra value for {@link Settings#EXTRA_CHANNEL_FILTER_LIST}. Include to show fields 102 * that have to do with editing behavior on devices that are locked or have a turned off 103 * display ({@link #setLockscreenVisibility(int)}, {@link #enableLights(boolean)}, 104 * {@link #setLightColor(int)}). 105 */ 106 public static final String EDIT_LOCKED_DEVICE = "locked"; 107 /** 108 * Extra value for {@link Settings#EXTRA_CHANNEL_FILTER_LIST}. Include to show fields 109 * that have to do with editing do not disturb bypass {(@link #setBypassDnd(boolean)}) . 110 */ 111 public static final String EDIT_ZEN = "zen"; 112 /** 113 * Extra value for {@link Settings#EXTRA_CHANNEL_FILTER_LIST}. Include to show fields 114 * that have to do with editing conversation settings (demoting or restoring a channel to 115 * be a Conversation, changing bubble behavior, or setting the priority of a conversation). 116 */ 117 public static final String EDIT_CONVERSATION = "conversation"; 118 /** 119 * Extra value for {@link Settings#EXTRA_CHANNEL_FILTER_LIST}. Include to show fields 120 * that have to do with editing launcher behavior (showing badges)}. 121 */ 122 public static final String EDIT_LAUNCHER = "launcher"; 123 124 /** 125 * The maximum length for text fields in a NotificationChannel. Fields will be truncated at this 126 * limit. 127 */ 128 private static final int MAX_TEXT_LENGTH = 1000; 129 130 private static final String TAG_CHANNEL = "channel"; 131 private static final String ATT_NAME = "name"; 132 private static final String ATT_DESC = "desc"; 133 private static final String ATT_ID = "id"; 134 private static final String ATT_DELETED = "deleted"; 135 private static final String ATT_PRIORITY = "priority"; 136 private static final String ATT_VISIBILITY = "visibility"; 137 private static final String ATT_IMPORTANCE = "importance"; 138 private static final String ATT_LIGHTS = "lights"; 139 private static final String ATT_LIGHT_COLOR = "light_color"; 140 private static final String ATT_VIBRATION = "vibration"; 141 private static final String ATT_VIBRATION_ENABLED = "vibration_enabled"; 142 private static final String ATT_SOUND = "sound"; 143 private static final String ATT_USAGE = "usage"; 144 private static final String ATT_FLAGS = "flags"; 145 private static final String ATT_CONTENT_TYPE = "content_type"; 146 private static final String ATT_SHOW_BADGE = "show_badge"; 147 private static final String ATT_USER_LOCKED = "locked"; 148 private static final String ATT_FG_SERVICE_SHOWN = "fgservice"; 149 private static final String ATT_GROUP = "group"; 150 private static final String ATT_BLOCKABLE_SYSTEM = "blockable_system"; 151 private static final String ATT_ALLOW_BUBBLE = "allow_bubbles"; 152 private static final String ATT_ORIG_IMP = "orig_imp"; 153 private static final String ATT_PARENT_CHANNEL = "parent"; 154 private static final String ATT_CONVERSATION_ID = "conv_id"; 155 private static final String ATT_IMP_CONVERSATION = "imp_conv"; 156 private static final String ATT_DEMOTE = "dem"; 157 private static final String ATT_DELETED_TIME_MS = "del_time"; 158 private static final String DELIMITER = ","; 159 160 /** 161 * @hide 162 */ 163 public static final int USER_LOCKED_PRIORITY = 0x00000001; 164 /** 165 * @hide 166 */ 167 public static final int USER_LOCKED_VISIBILITY = 0x00000002; 168 /** 169 * @hide 170 */ 171 public static final int USER_LOCKED_IMPORTANCE = 0x00000004; 172 /** 173 * @hide 174 */ 175 public static final int USER_LOCKED_LIGHTS = 0x00000008; 176 /** 177 * @hide 178 */ 179 public static final int USER_LOCKED_VIBRATION = 0x00000010; 180 /** 181 * @hide 182 */ 183 @SystemApi 184 public static final int USER_LOCKED_SOUND = 0x00000020; 185 186 /** 187 * @hide 188 */ 189 public static final int USER_LOCKED_SHOW_BADGE = 0x00000080; 190 191 /** 192 * @hide 193 */ 194 public static final int USER_LOCKED_ALLOW_BUBBLE = 0x00000100; 195 196 /** 197 * @hide 198 */ 199 public static final int[] LOCKABLE_FIELDS = new int[] { 200 USER_LOCKED_PRIORITY, 201 USER_LOCKED_VISIBILITY, 202 USER_LOCKED_IMPORTANCE, 203 USER_LOCKED_LIGHTS, 204 USER_LOCKED_VIBRATION, 205 USER_LOCKED_SOUND, 206 USER_LOCKED_SHOW_BADGE, 207 USER_LOCKED_ALLOW_BUBBLE 208 }; 209 210 /** 211 * @hide 212 */ 213 public static final int DEFAULT_ALLOW_BUBBLE = -1; 214 /** 215 * @hide 216 */ 217 public static final int ALLOW_BUBBLE_ON = 1; 218 /** 219 * @hide 220 */ 221 public static final int ALLOW_BUBBLE_OFF = 0; 222 223 private static final int DEFAULT_LIGHT_COLOR = 0; 224 private static final int DEFAULT_VISIBILITY = 225 NotificationManager.VISIBILITY_NO_OVERRIDE; 226 private static final int DEFAULT_IMPORTANCE = 227 NotificationManager.IMPORTANCE_UNSPECIFIED; 228 private static final boolean DEFAULT_DELETED = false; 229 private static final boolean DEFAULT_SHOW_BADGE = true; 230 private static final long DEFAULT_DELETION_TIME_MS = -1; 231 232 @UnsupportedAppUsage 233 private String mId; 234 private String mName; 235 private String mDesc; 236 private int mImportance = DEFAULT_IMPORTANCE; 237 private int mOriginalImportance = DEFAULT_IMPORTANCE; 238 private boolean mBypassDnd; 239 private int mLockscreenVisibility = DEFAULT_VISIBILITY; 240 private Uri mSound = Settings.System.DEFAULT_NOTIFICATION_URI; 241 private boolean mLights; 242 private int mLightColor = DEFAULT_LIGHT_COLOR; 243 private long[] mVibration; 244 // Bitwise representation of fields that have been changed by the user, preventing the app from 245 // making changes to these fields. 246 private int mUserLockedFields; 247 private boolean mFgServiceShown; 248 private boolean mVibrationEnabled; 249 private boolean mShowBadge = DEFAULT_SHOW_BADGE; 250 private boolean mDeleted = DEFAULT_DELETED; 251 private String mGroup; 252 private AudioAttributes mAudioAttributes = Notification.AUDIO_ATTRIBUTES_DEFAULT; 253 // If this is a blockable system notification channel. 254 private boolean mBlockableSystem = false; 255 private int mAllowBubbles = DEFAULT_ALLOW_BUBBLE; 256 private boolean mImportanceLockedByOEM; 257 private boolean mImportanceLockedDefaultApp; 258 private String mParentId = null; 259 private String mConversationId = null; 260 private boolean mDemoted = false; 261 private boolean mImportantConvo = false; 262 private long mDeletedTime = DEFAULT_DELETION_TIME_MS; 263 // If the sound for this channel is missing, e.g. after restore. 264 private boolean mIsSoundMissing; 265 266 /** 267 * Creates a notification channel. 268 * 269 * @param id The id of the channel. Must be unique per package. The value may be truncated if 270 * it is too long. 271 * @param name The user visible name of the channel. You can rename this channel when the system 272 * locale changes by listening for the {@link Intent#ACTION_LOCALE_CHANGED} 273 * broadcast. The recommended maximum length is 40 characters; the value may be 274 * truncated if it is too long. 275 * @param importance The importance of the channel. This controls how interruptive notifications 276 * posted to this channel are. 277 */ NotificationChannel(String id, CharSequence name, @Importance int importance)278 public NotificationChannel(String id, CharSequence name, @Importance int importance) { 279 this.mId = getTrimmedString(id); 280 this.mName = name != null ? getTrimmedString(name.toString()) : null; 281 this.mImportance = importance; 282 } 283 284 /** 285 * @hide 286 */ NotificationChannel(Parcel in)287 protected NotificationChannel(Parcel in) { 288 if (in.readByte() != 0) { 289 mId = in.readString(); 290 } else { 291 mId = null; 292 } 293 if (in.readByte() != 0) { 294 mName = in.readString(); 295 } else { 296 mName = null; 297 } 298 if (in.readByte() != 0) { 299 mDesc = in.readString(); 300 } else { 301 mDesc = null; 302 } 303 mImportance = in.readInt(); 304 mBypassDnd = in.readByte() != 0; 305 mLockscreenVisibility = in.readInt(); 306 if (in.readByte() != 0) { 307 mSound = Uri.CREATOR.createFromParcel(in); 308 } else { 309 mSound = null; 310 } 311 mLights = in.readByte() != 0; 312 mVibration = in.createLongArray(); 313 mUserLockedFields = in.readInt(); 314 mFgServiceShown = in.readByte() != 0; 315 mVibrationEnabled = in.readByte() != 0; 316 mShowBadge = in.readByte() != 0; 317 mDeleted = in.readByte() != 0; 318 if (in.readByte() != 0) { 319 mGroup = in.readString(); 320 } else { 321 mGroup = null; 322 } 323 mAudioAttributes = in.readInt() > 0 ? AudioAttributes.CREATOR.createFromParcel(in) : null; 324 mLightColor = in.readInt(); 325 mBlockableSystem = in.readBoolean(); 326 mAllowBubbles = in.readInt(); 327 mImportanceLockedByOEM = in.readBoolean(); 328 mOriginalImportance = in.readInt(); 329 mParentId = in.readString(); 330 mConversationId = in.readString(); 331 mDemoted = in.readBoolean(); 332 mImportantConvo = in.readBoolean(); 333 mDeletedTime = in.readLong(); 334 } 335 336 @Override writeToParcel(Parcel dest, int flags)337 public void writeToParcel(Parcel dest, int flags) { 338 if (mId != null) { 339 dest.writeByte((byte) 1); 340 dest.writeString(mId); 341 } else { 342 dest.writeByte((byte) 0); 343 } 344 if (mName != null) { 345 dest.writeByte((byte) 1); 346 dest.writeString(mName); 347 } else { 348 dest.writeByte((byte) 0); 349 } 350 if (mDesc != null) { 351 dest.writeByte((byte) 1); 352 dest.writeString(mDesc); 353 } else { 354 dest.writeByte((byte) 0); 355 } 356 dest.writeInt(mImportance); 357 dest.writeByte(mBypassDnd ? (byte) 1 : (byte) 0); 358 dest.writeInt(mLockscreenVisibility); 359 if (mSound != null) { 360 dest.writeByte((byte) 1); 361 mSound.writeToParcel(dest, 0); 362 } else { 363 dest.writeByte((byte) 0); 364 } 365 dest.writeByte(mLights ? (byte) 1 : (byte) 0); 366 dest.writeLongArray(mVibration); 367 dest.writeInt(mUserLockedFields); 368 dest.writeByte(mFgServiceShown ? (byte) 1 : (byte) 0); 369 dest.writeByte(mVibrationEnabled ? (byte) 1 : (byte) 0); 370 dest.writeByte(mShowBadge ? (byte) 1 : (byte) 0); 371 dest.writeByte(mDeleted ? (byte) 1 : (byte) 0); 372 if (mGroup != null) { 373 dest.writeByte((byte) 1); 374 dest.writeString(mGroup); 375 } else { 376 dest.writeByte((byte) 0); 377 } 378 if (mAudioAttributes != null) { 379 dest.writeInt(1); 380 mAudioAttributes.writeToParcel(dest, 0); 381 } else { 382 dest.writeInt(0); 383 } 384 dest.writeInt(mLightColor); 385 dest.writeBoolean(mBlockableSystem); 386 dest.writeInt(mAllowBubbles); 387 dest.writeBoolean(mImportanceLockedByOEM); 388 dest.writeInt(mOriginalImportance); 389 dest.writeString(mParentId); 390 dest.writeString(mConversationId); 391 dest.writeBoolean(mDemoted); 392 dest.writeBoolean(mImportantConvo); 393 dest.writeLong(mDeletedTime); 394 } 395 396 /** 397 * @hide 398 */ 399 @TestApi lockFields(int field)400 public void lockFields(int field) { 401 mUserLockedFields |= field; 402 } 403 404 /** 405 * @hide 406 */ unlockFields(int field)407 public void unlockFields(int field) { 408 mUserLockedFields &= ~field; 409 } 410 411 /** 412 * @hide 413 */ 414 @TestApi setFgServiceShown(boolean shown)415 public void setFgServiceShown(boolean shown) { 416 mFgServiceShown = shown; 417 } 418 419 /** 420 * @hide 421 */ 422 @TestApi setDeleted(boolean deleted)423 public void setDeleted(boolean deleted) { 424 mDeleted = deleted; 425 } 426 427 /** 428 * @hide 429 */ 430 @TestApi setDeletedTimeMs(long time)431 public void setDeletedTimeMs(long time) { 432 mDeletedTime = time; 433 } 434 435 /** 436 * @hide 437 */ 438 @TestApi setImportantConversation(boolean importantConvo)439 public void setImportantConversation(boolean importantConvo) { 440 mImportantConvo = importantConvo; 441 } 442 443 /** 444 * Allows users to block notifications sent through this channel, if this channel belongs to 445 * a package that is signed with the system signature. 446 * 447 * If the channel does not belong to a package that is signed with the system signature, this 448 * method does nothing, since such channels are blockable by default and cannot be set to be 449 * unblockable. 450 * @param blockable if {@code true}, allows users to block notifications on this channel. 451 * @hide 452 */ 453 @SystemApi setBlockable(boolean blockable)454 public void setBlockable(boolean blockable) { 455 mBlockableSystem = blockable; 456 } 457 // Modifiable by apps post channel creation 458 459 /** 460 * Sets the user visible name of this channel. 461 * 462 * <p>The recommended maximum length is 40 characters; the value may be truncated if it is too 463 * long. 464 */ setName(CharSequence name)465 public void setName(CharSequence name) { 466 mName = name != null ? getTrimmedString(name.toString()) : null; 467 } 468 469 /** 470 * Sets the user visible description of this channel. 471 * 472 * <p>The recommended maximum length is 300 characters; the value may be truncated if it is too 473 * long. 474 */ setDescription(String description)475 public void setDescription(String description) { 476 mDesc = getTrimmedString(description); 477 } 478 getTrimmedString(String input)479 private String getTrimmedString(String input) { 480 if (input != null && input.length() > MAX_TEXT_LENGTH) { 481 return input.substring(0, MAX_TEXT_LENGTH); 482 } 483 return input; 484 } 485 486 /** 487 * @hide 488 */ setId(String id)489 public void setId(String id) { 490 mId = id; 491 } 492 493 // Modifiable by apps on channel creation. 494 495 /** 496 * Sets what group this channel belongs to. 497 * 498 * Group information is only used for presentation, not for behavior. 499 * 500 * Only modifiable before the channel is submitted to 501 * {@link NotificationManager#createNotificationChannel(NotificationChannel)}, unless the 502 * channel is not currently part of a group. 503 * 504 * @param groupId the id of a group created by 505 * {@link NotificationManager#createNotificationChannelGroup(NotificationChannelGroup)}. 506 */ setGroup(String groupId)507 public void setGroup(String groupId) { 508 this.mGroup = groupId; 509 } 510 511 /** 512 * Sets whether notifications posted to this channel can appear as application icon badges 513 * in a Launcher. 514 * 515 * Only modifiable before the channel is submitted to 516 * {@link NotificationManager#createNotificationChannel(NotificationChannel)}. 517 * 518 * @param showBadge true if badges should be allowed to be shown. 519 */ setShowBadge(boolean showBadge)520 public void setShowBadge(boolean showBadge) { 521 this.mShowBadge = showBadge; 522 } 523 524 /** 525 * Sets the sound that should be played for notifications posted to this channel and its 526 * audio attributes. Notification channels with an {@link #getImportance() importance} of at 527 * least {@link NotificationManager#IMPORTANCE_DEFAULT} should have a sound. 528 * 529 * Only modifiable before the channel is submitted to 530 * {@link NotificationManager#createNotificationChannel(NotificationChannel)}. 531 */ setSound(Uri sound, AudioAttributes audioAttributes)532 public void setSound(Uri sound, AudioAttributes audioAttributes) { 533 this.mSound = sound; 534 this.mAudioAttributes = audioAttributes; 535 } 536 537 /** 538 * Sets whether notifications posted to this channel should display notification lights, 539 * on devices that support that feature. 540 * 541 * Only modifiable before the channel is submitted to 542 * {@link NotificationManager#createNotificationChannel(NotificationChannel)}. 543 */ enableLights(boolean lights)544 public void enableLights(boolean lights) { 545 this.mLights = lights; 546 } 547 548 /** 549 * Sets the notification light color for notifications posted to this channel, if lights are 550 * {@link #enableLights(boolean) enabled} on this channel and the device supports that feature. 551 * 552 * Only modifiable before the channel is submitted to 553 * {@link NotificationManager#createNotificationChannel(NotificationChannel)}. 554 */ setLightColor(int argb)555 public void setLightColor(int argb) { 556 this.mLightColor = argb; 557 } 558 559 /** 560 * Sets whether notification posted to this channel should vibrate. The vibration pattern can 561 * be set with {@link #setVibrationPattern(long[])}. 562 * 563 * Only modifiable before the channel is submitted to 564 * {@link NotificationManager#createNotificationChannel(NotificationChannel)}. 565 */ enableVibration(boolean vibration)566 public void enableVibration(boolean vibration) { 567 this.mVibrationEnabled = vibration; 568 } 569 570 /** 571 * Sets the vibration pattern for notifications posted to this channel. If the provided 572 * pattern is valid (non-null, non-empty), will {@link #enableVibration(boolean)} enable 573 * vibration} as well. Otherwise, vibration will be disabled. 574 * 575 * Only modifiable before the channel is submitted to 576 * {@link NotificationManager#createNotificationChannel(NotificationChannel)}. 577 */ setVibrationPattern(long[] vibrationPattern)578 public void setVibrationPattern(long[] vibrationPattern) { 579 this.mVibrationEnabled = vibrationPattern != null && vibrationPattern.length > 0; 580 this.mVibration = vibrationPattern; 581 } 582 583 /** 584 * Sets the level of interruption of this notification channel. 585 * 586 * Only modifiable before the channel is submitted to 587 * {@link NotificationManager#createNotificationChannel(NotificationChannel)}. 588 * 589 * @param importance the amount the user should be interrupted by 590 * notifications from this channel. 591 */ setImportance(@mportance int importance)592 public void setImportance(@Importance int importance) { 593 this.mImportance = importance; 594 } 595 596 // Modifiable by a notification ranker. 597 598 /** 599 * Sets whether or not notifications posted to this channel can interrupt the user in 600 * {@link android.app.NotificationManager.Policy#INTERRUPTION_FILTER_PRIORITY} mode. 601 * 602 * Only modifiable by the system and notification ranker. 603 */ setBypassDnd(boolean bypassDnd)604 public void setBypassDnd(boolean bypassDnd) { 605 this.mBypassDnd = bypassDnd; 606 } 607 608 /** 609 * Sets whether notifications posted to this channel appear on the lockscreen or not, and if so, 610 * whether they appear in a redacted form. See e.g. {@link Notification#VISIBILITY_SECRET}. 611 * 612 * Only modifiable by the system and notification ranker. 613 */ setLockscreenVisibility(int lockscreenVisibility)614 public void setLockscreenVisibility(int lockscreenVisibility) { 615 this.mLockscreenVisibility = lockscreenVisibility; 616 } 617 618 /** 619 * As of Android 11 this value is no longer respected. 620 * @see #canBubble() 621 * @see Notification#getBubbleMetadata() 622 */ setAllowBubbles(boolean allowBubbles)623 public void setAllowBubbles(boolean allowBubbles) { 624 mAllowBubbles = allowBubbles ? ALLOW_BUBBLE_ON : ALLOW_BUBBLE_OFF; 625 } 626 627 /** 628 * @hide 629 */ setAllowBubbles(int allowed)630 public void setAllowBubbles(int allowed) { 631 mAllowBubbles = allowed; 632 } 633 634 /** 635 * Sets this channel as being converastion-centric. Different settings and functionality may be 636 * exposed for conversation-centric channels. 637 * 638 * @param parentChannelId The {@link #getId()} id} of the generic channel that notifications of 639 * this type would be posted to in absence of a specific conversation id. 640 * For example, if this channel represents 'Messages from Person A', the 641 * parent channel would be 'Messages.' 642 * @param conversationId The {@link ShortcutInfo#getId()} of the shortcut representing this 643 * channel's conversation. 644 */ setConversationId(@onNull String parentChannelId, @NonNull String conversationId)645 public void setConversationId(@NonNull String parentChannelId, 646 @NonNull String conversationId) { 647 mParentId = parentChannelId; 648 mConversationId = conversationId; 649 } 650 651 /** 652 * Returns the id of this channel. 653 */ getId()654 public String getId() { 655 return mId; 656 } 657 658 /** 659 * Returns the user visible name of this channel. 660 */ getName()661 public CharSequence getName() { 662 return mName; 663 } 664 665 /** 666 * Returns the user visible description of this channel. 667 */ getDescription()668 public String getDescription() { 669 return mDesc; 670 } 671 672 /** 673 * Returns the user specified importance e.g. {@link NotificationManager#IMPORTANCE_LOW} for 674 * notifications posted to this channel. Note: This value might be > 675 * {@link NotificationManager#IMPORTANCE_NONE}, but notifications posted to this channel will 676 * not be shown to the user if the parent {@link NotificationChannelGroup} or app is blocked. 677 * See {@link NotificationChannelGroup#isBlocked()} and 678 * {@link NotificationManager#areNotificationsEnabled()}. 679 */ getImportance()680 public int getImportance() { 681 return mImportance; 682 } 683 684 /** 685 * Whether or not notifications posted to this channel can bypass the Do Not Disturb 686 * {@link NotificationManager#INTERRUPTION_FILTER_PRIORITY} mode. 687 */ canBypassDnd()688 public boolean canBypassDnd() { 689 return mBypassDnd; 690 } 691 692 /** 693 * Whether or not this channel represents a conversation. 694 */ isConversation()695 public boolean isConversation() { 696 return !TextUtils.isEmpty(getConversationId()); 697 } 698 699 700 /** 701 * Whether or not notifications in this conversation are considered important. 702 * 703 * <p>Important conversations may get special visual treatment, and might be able to bypass DND. 704 * 705 * <p>This is only valid for channels that represent conversations, that is, 706 * where {@link #isConversation()} is true. 707 */ isImportantConversation()708 public boolean isImportantConversation() { 709 return mImportantConvo; 710 } 711 712 /** 713 * Returns the notification sound for this channel. 714 */ getSound()715 public Uri getSound() { 716 return mSound; 717 } 718 719 /** 720 * @hide 721 */ isSoundMissing()722 public boolean isSoundMissing() { 723 return mIsSoundMissing; 724 } 725 726 /** 727 * Returns the audio attributes for sound played by notifications posted to this channel. 728 */ getAudioAttributes()729 public AudioAttributes getAudioAttributes() { 730 return mAudioAttributes; 731 } 732 733 /** 734 * Returns whether notifications posted to this channel trigger notification lights. 735 */ shouldShowLights()736 public boolean shouldShowLights() { 737 return mLights; 738 } 739 740 /** 741 * Returns the notification light color for notifications posted to this channel. Irrelevant 742 * unless {@link #shouldShowLights()}. 743 */ getLightColor()744 public int getLightColor() { 745 return mLightColor; 746 } 747 748 /** 749 * Returns whether notifications posted to this channel always vibrate. 750 */ shouldVibrate()751 public boolean shouldVibrate() { 752 return mVibrationEnabled; 753 } 754 755 /** 756 * Returns the vibration pattern for notifications posted to this channel. Will be ignored if 757 * vibration is not enabled ({@link #shouldVibrate()}. 758 */ getVibrationPattern()759 public long[] getVibrationPattern() { 760 return mVibration; 761 } 762 763 /** 764 * Returns whether or not notifications posted to this channel are shown on the lockscreen in 765 * full or redacted form. 766 */ getLockscreenVisibility()767 public int getLockscreenVisibility() { 768 return mLockscreenVisibility; 769 } 770 771 /** 772 * Returns whether notifications posted to this channel can appear as badges in a Launcher 773 * application. 774 * 775 * Note that badging may be disabled for other reasons. 776 */ canShowBadge()777 public boolean canShowBadge() { 778 return mShowBadge; 779 } 780 781 /** 782 * Returns what group this channel belongs to. 783 * 784 * This is used only for visually grouping channels in the UI. 785 */ getGroup()786 public String getGroup() { 787 return mGroup; 788 } 789 790 /** 791 * Returns whether notifications posted to this channel are allowed to display outside of the 792 * notification shade, in a floating window on top of other apps. 793 * 794 * @see Notification#getBubbleMetadata() 795 */ canBubble()796 public boolean canBubble() { 797 return mAllowBubbles == ALLOW_BUBBLE_ON; 798 } 799 800 /** 801 * @hide 802 */ getAllowBubbles()803 public int getAllowBubbles() { 804 return mAllowBubbles; 805 } 806 807 /** 808 * Returns the {@link #getId() id} of the parent notification channel to this channel, if it's 809 * a conversation related channel. See {@link #setConversationId(String, String)}. 810 */ getParentChannelId()811 public @Nullable String getParentChannelId() { 812 return mParentId; 813 } 814 815 /** 816 * Returns the {@link ShortcutInfo#getId() id} of the conversation backing this channel, if it's 817 * associated with a conversation. See {@link #setConversationId(String, String)}. 818 */ getConversationId()819 public @Nullable String getConversationId() { 820 return mConversationId; 821 } 822 823 /** 824 * @hide 825 */ 826 @SystemApi isDeleted()827 public boolean isDeleted() { 828 return mDeleted; 829 } 830 831 /** 832 * @hide 833 */ getDeletedTimeMs()834 public long getDeletedTimeMs() { 835 return mDeletedTime; 836 } 837 838 /** 839 * @hide 840 */ 841 @SystemApi getUserLockedFields()842 public int getUserLockedFields() { 843 return mUserLockedFields; 844 } 845 846 /** 847 * @hide 848 */ isFgServiceShown()849 public boolean isFgServiceShown() { 850 return mFgServiceShown; 851 } 852 853 /** 854 * @hide 855 */ 856 @TestApi isBlockable()857 public boolean isBlockable() { 858 return mBlockableSystem; 859 } 860 861 /** 862 * @hide 863 */ 864 @TestApi setImportanceLockedByOEM(boolean locked)865 public void setImportanceLockedByOEM(boolean locked) { 866 mImportanceLockedByOEM = locked; 867 } 868 869 /** 870 * @hide 871 */ 872 @TestApi setImportanceLockedByCriticalDeviceFunction(boolean locked)873 public void setImportanceLockedByCriticalDeviceFunction(boolean locked) { 874 mImportanceLockedDefaultApp = locked; 875 } 876 877 /** 878 * @hide 879 */ 880 @TestApi isImportanceLockedByOEM()881 public boolean isImportanceLockedByOEM() { 882 return mImportanceLockedByOEM; 883 } 884 885 /** 886 * @hide 887 */ 888 @TestApi isImportanceLockedByCriticalDeviceFunction()889 public boolean isImportanceLockedByCriticalDeviceFunction() { 890 return mImportanceLockedDefaultApp; 891 } 892 893 /** 894 * @hide 895 */ 896 @TestApi getOriginalImportance()897 public int getOriginalImportance() { 898 return mOriginalImportance; 899 } 900 901 /** 902 * @hide 903 */ 904 @TestApi setOriginalImportance(int importance)905 public void setOriginalImportance(int importance) { 906 mOriginalImportance = importance; 907 } 908 909 /** 910 * @hide 911 */ 912 @TestApi setDemoted(boolean demoted)913 public void setDemoted(boolean demoted) { 914 mDemoted = demoted; 915 } 916 917 /** 918 * Returns whether the user has decided that this channel does not represent a conversation. The 919 * value will always be false for channels that never claimed to be conversations - that is, 920 * for channels where {@link #getConversationId()} and {@link #getParentChannelId()} are empty. 921 */ isDemoted()922 public boolean isDemoted() { 923 return mDemoted; 924 } 925 926 /** 927 * Returns whether the user has chosen the importance of this channel, either to affirm the 928 * initial selection from the app, or changed it to be higher or lower. 929 * @see #getImportance() 930 */ hasUserSetImportance()931 public boolean hasUserSetImportance() { 932 return (mUserLockedFields & USER_LOCKED_IMPORTANCE) != 0; 933 } 934 935 /** 936 * Returns whether the user has chosen the sound of this channel. 937 * @see #getSound() 938 */ hasUserSetSound()939 public boolean hasUserSetSound() { 940 return (mUserLockedFields & USER_LOCKED_SOUND) != 0; 941 } 942 943 /** 944 * @hide 945 */ populateFromXmlForRestore(XmlPullParser parser, Context context)946 public void populateFromXmlForRestore(XmlPullParser parser, Context context) { 947 populateFromXml(XmlUtils.makeTyped(parser), true, context); 948 } 949 950 /** 951 * @hide 952 */ 953 @SystemApi populateFromXml(XmlPullParser parser)954 public void populateFromXml(XmlPullParser parser) { 955 populateFromXml(XmlUtils.makeTyped(parser), false, null); 956 } 957 958 /** 959 * If {@param forRestore} is true, {@param Context} MUST be non-null. 960 */ populateFromXml(TypedXmlPullParser parser, boolean forRestore, @Nullable Context context)961 private void populateFromXml(TypedXmlPullParser parser, boolean forRestore, 962 @Nullable Context context) { 963 Preconditions.checkArgument(!forRestore || context != null, 964 "forRestore is true but got null context"); 965 966 // Name, id, and importance are set in the constructor. 967 setDescription(parser.getAttributeValue(null, ATT_DESC)); 968 setBypassDnd(Notification.PRIORITY_DEFAULT 969 != safeInt(parser, ATT_PRIORITY, Notification.PRIORITY_DEFAULT)); 970 setLockscreenVisibility(safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY)); 971 972 Uri sound = safeUri(parser, ATT_SOUND); 973 setSound(forRestore ? restoreSoundUri(context, sound) : sound, safeAudioAttributes(parser)); 974 975 enableLights(safeBool(parser, ATT_LIGHTS, false)); 976 setLightColor(safeInt(parser, ATT_LIGHT_COLOR, DEFAULT_LIGHT_COLOR)); 977 setVibrationPattern(safeLongArray(parser, ATT_VIBRATION, null)); 978 enableVibration(safeBool(parser, ATT_VIBRATION_ENABLED, false)); 979 setShowBadge(safeBool(parser, ATT_SHOW_BADGE, false)); 980 setDeleted(safeBool(parser, ATT_DELETED, false)); 981 setDeletedTimeMs(XmlUtils.readLongAttribute( 982 parser, ATT_DELETED_TIME_MS, DEFAULT_DELETION_TIME_MS)); 983 setGroup(parser.getAttributeValue(null, ATT_GROUP)); 984 lockFields(safeInt(parser, ATT_USER_LOCKED, 0)); 985 setFgServiceShown(safeBool(parser, ATT_FG_SERVICE_SHOWN, false)); 986 setBlockable(safeBool(parser, ATT_BLOCKABLE_SYSTEM, false)); 987 setAllowBubbles(safeInt(parser, ATT_ALLOW_BUBBLE, DEFAULT_ALLOW_BUBBLE)); 988 setOriginalImportance(safeInt(parser, ATT_ORIG_IMP, DEFAULT_IMPORTANCE)); 989 setConversationId(parser.getAttributeValue(null, ATT_PARENT_CHANNEL), 990 parser.getAttributeValue(null, ATT_CONVERSATION_ID)); 991 setDemoted(safeBool(parser, ATT_DEMOTE, false)); 992 setImportantConversation(safeBool(parser, ATT_IMP_CONVERSATION, false)); 993 } 994 995 @Nullable restoreSoundUri(Context context, @Nullable Uri uri)996 private Uri restoreSoundUri(Context context, @Nullable Uri uri) { 997 if (uri == null || Uri.EMPTY.equals(uri)) { 998 return null; 999 } 1000 ContentResolver contentResolver = context.getContentResolver(); 1001 // There are backups out there with uncanonical uris (because we fixed this after 1002 // shipping). If uncanonical uris are given to MediaProvider.uncanonicalize it won't 1003 // verify the uri against device storage and we'll possibly end up with a broken uri. 1004 // We then canonicalize the uri to uncanonicalize it back, which means we properly check 1005 // the uri and in the case of not having the resource we end up with the default - better 1006 // than broken. As a side effect we'll canonicalize already canonicalized uris, this is fine 1007 // according to the docs because canonicalize method has to handle canonical uris as well. 1008 Uri canonicalizedUri = contentResolver.canonicalize(uri); 1009 if (canonicalizedUri == null) { 1010 // We got a null because the uri in the backup does not exist here. 1011 mIsSoundMissing = true; 1012 return null; 1013 } 1014 return contentResolver.uncanonicalize(canonicalizedUri); 1015 } 1016 1017 /** 1018 * @hide 1019 */ 1020 @SystemApi writeXml(XmlSerializer out)1021 public void writeXml(XmlSerializer out) throws IOException { 1022 writeXml(XmlUtils.makeTyped(out), false, null); 1023 } 1024 1025 /** 1026 * @hide 1027 */ writeXmlForBackup(XmlSerializer out, Context context)1028 public void writeXmlForBackup(XmlSerializer out, Context context) throws IOException { 1029 writeXml(XmlUtils.makeTyped(out), true, context); 1030 } 1031 getSoundForBackup(Context context)1032 private Uri getSoundForBackup(Context context) { 1033 Uri sound = getSound(); 1034 if (sound == null || Uri.EMPTY.equals(sound)) { 1035 return null; 1036 } 1037 Uri canonicalSound = context.getContentResolver().canonicalize(sound); 1038 if (canonicalSound == null) { 1039 // The content provider does not support canonical uris so we backup the default 1040 return Settings.System.DEFAULT_NOTIFICATION_URI; 1041 } 1042 return canonicalSound; 1043 } 1044 1045 /** 1046 * If {@param forBackup} is true, {@param Context} MUST be non-null. 1047 */ writeXml(TypedXmlSerializer out, boolean forBackup, @Nullable Context context)1048 private void writeXml(TypedXmlSerializer out, boolean forBackup, @Nullable Context context) 1049 throws IOException { 1050 Preconditions.checkArgument(!forBackup || context != null, 1051 "forBackup is true but got null context"); 1052 out.startTag(null, TAG_CHANNEL); 1053 out.attribute(null, ATT_ID, getId()); 1054 if (getName() != null) { 1055 out.attribute(null, ATT_NAME, getName().toString()); 1056 } 1057 if (getDescription() != null) { 1058 out.attribute(null, ATT_DESC, getDescription()); 1059 } 1060 if (getImportance() != DEFAULT_IMPORTANCE) { 1061 out.attributeInt(null, ATT_IMPORTANCE, getImportance()); 1062 } 1063 if (canBypassDnd()) { 1064 out.attributeInt(null, ATT_PRIORITY, Notification.PRIORITY_MAX); 1065 } 1066 if (getLockscreenVisibility() != DEFAULT_VISIBILITY) { 1067 out.attributeInt(null, ATT_VISIBILITY, getLockscreenVisibility()); 1068 } 1069 Uri sound = forBackup ? getSoundForBackup(context) : getSound(); 1070 if (sound != null) { 1071 out.attribute(null, ATT_SOUND, sound.toString()); 1072 } 1073 if (getAudioAttributes() != null) { 1074 out.attributeInt(null, ATT_USAGE, getAudioAttributes().getUsage()); 1075 out.attributeInt(null, ATT_CONTENT_TYPE, getAudioAttributes().getContentType()); 1076 out.attributeInt(null, ATT_FLAGS, getAudioAttributes().getFlags()); 1077 } 1078 if (shouldShowLights()) { 1079 out.attributeBoolean(null, ATT_LIGHTS, shouldShowLights()); 1080 } 1081 if (getLightColor() != DEFAULT_LIGHT_COLOR) { 1082 out.attributeInt(null, ATT_LIGHT_COLOR, getLightColor()); 1083 } 1084 if (shouldVibrate()) { 1085 out.attributeBoolean(null, ATT_VIBRATION_ENABLED, shouldVibrate()); 1086 } 1087 if (getVibrationPattern() != null) { 1088 out.attribute(null, ATT_VIBRATION, longArrayToString(getVibrationPattern())); 1089 } 1090 if (getUserLockedFields() != 0) { 1091 out.attributeInt(null, ATT_USER_LOCKED, getUserLockedFields()); 1092 } 1093 if (isFgServiceShown()) { 1094 out.attributeBoolean(null, ATT_FG_SERVICE_SHOWN, isFgServiceShown()); 1095 } 1096 if (canShowBadge()) { 1097 out.attributeBoolean(null, ATT_SHOW_BADGE, canShowBadge()); 1098 } 1099 if (isDeleted()) { 1100 out.attributeBoolean(null, ATT_DELETED, isDeleted()); 1101 } 1102 if (getDeletedTimeMs() >= 0) { 1103 out.attributeLong(null, ATT_DELETED_TIME_MS, getDeletedTimeMs()); 1104 } 1105 if (getGroup() != null) { 1106 out.attribute(null, ATT_GROUP, getGroup()); 1107 } 1108 if (isBlockable()) { 1109 out.attributeBoolean(null, ATT_BLOCKABLE_SYSTEM, isBlockable()); 1110 } 1111 if (getAllowBubbles() != DEFAULT_ALLOW_BUBBLE) { 1112 out.attributeInt(null, ATT_ALLOW_BUBBLE, getAllowBubbles()); 1113 } 1114 if (getOriginalImportance() != DEFAULT_IMPORTANCE) { 1115 out.attributeInt(null, ATT_ORIG_IMP, getOriginalImportance()); 1116 } 1117 if (getParentChannelId() != null) { 1118 out.attribute(null, ATT_PARENT_CHANNEL, getParentChannelId()); 1119 } 1120 if (getConversationId() != null) { 1121 out.attribute(null, ATT_CONVERSATION_ID, getConversationId()); 1122 } 1123 if (isDemoted()) { 1124 out.attributeBoolean(null, ATT_DEMOTE, isDemoted()); 1125 } 1126 if (isImportantConversation()) { 1127 out.attributeBoolean(null, ATT_IMP_CONVERSATION, isImportantConversation()); 1128 } 1129 1130 // mImportanceLockedDefaultApp and mImportanceLockedByOEM have a different source of 1131 // truth and so aren't written to this xml file 1132 1133 out.endTag(null, TAG_CHANNEL); 1134 } 1135 1136 /** 1137 * @hide 1138 */ 1139 @SystemApi toJson()1140 public JSONObject toJson() throws JSONException { 1141 JSONObject record = new JSONObject(); 1142 record.put(ATT_ID, getId()); 1143 record.put(ATT_NAME, getName()); 1144 record.put(ATT_DESC, getDescription()); 1145 if (getImportance() != DEFAULT_IMPORTANCE) { 1146 record.put(ATT_IMPORTANCE, 1147 NotificationListenerService.Ranking.importanceToString(getImportance())); 1148 } 1149 if (canBypassDnd()) { 1150 record.put(ATT_PRIORITY, Notification.PRIORITY_MAX); 1151 } 1152 if (getLockscreenVisibility() != DEFAULT_VISIBILITY) { 1153 record.put(ATT_VISIBILITY, Notification.visibilityToString(getLockscreenVisibility())); 1154 } 1155 if (getSound() != null) { 1156 record.put(ATT_SOUND, getSound().toString()); 1157 } 1158 if (getAudioAttributes() != null) { 1159 record.put(ATT_USAGE, Integer.toString(getAudioAttributes().getUsage())); 1160 record.put(ATT_CONTENT_TYPE, 1161 Integer.toString(getAudioAttributes().getContentType())); 1162 record.put(ATT_FLAGS, Integer.toString(getAudioAttributes().getFlags())); 1163 } 1164 record.put(ATT_LIGHTS, Boolean.toString(shouldShowLights())); 1165 record.put(ATT_LIGHT_COLOR, Integer.toString(getLightColor())); 1166 record.put(ATT_VIBRATION_ENABLED, Boolean.toString(shouldVibrate())); 1167 record.put(ATT_USER_LOCKED, Integer.toString(getUserLockedFields())); 1168 record.put(ATT_FG_SERVICE_SHOWN, Boolean.toString(isFgServiceShown())); 1169 record.put(ATT_VIBRATION, longArrayToString(getVibrationPattern())); 1170 record.put(ATT_SHOW_BADGE, Boolean.toString(canShowBadge())); 1171 record.put(ATT_DELETED, Boolean.toString(isDeleted())); 1172 record.put(ATT_DELETED_TIME_MS, Long.toString(getDeletedTimeMs())); 1173 record.put(ATT_GROUP, getGroup()); 1174 record.put(ATT_BLOCKABLE_SYSTEM, isBlockable()); 1175 record.put(ATT_ALLOW_BUBBLE, getAllowBubbles()); 1176 // TODO: original importance 1177 return record; 1178 } 1179 safeAudioAttributes(TypedXmlPullParser parser)1180 private static AudioAttributes safeAudioAttributes(TypedXmlPullParser parser) { 1181 int usage = safeInt(parser, ATT_USAGE, AudioAttributes.USAGE_NOTIFICATION); 1182 int contentType = safeInt(parser, ATT_CONTENT_TYPE, 1183 AudioAttributes.CONTENT_TYPE_SONIFICATION); 1184 int flags = safeInt(parser, ATT_FLAGS, 0); 1185 return new AudioAttributes.Builder() 1186 .setUsage(usage) 1187 .setContentType(contentType) 1188 .setFlags(flags) 1189 .build(); 1190 } 1191 safeUri(TypedXmlPullParser parser, String att)1192 private static Uri safeUri(TypedXmlPullParser parser, String att) { 1193 final String val = parser.getAttributeValue(null, att); 1194 return val == null ? null : Uri.parse(val); 1195 } 1196 safeInt(TypedXmlPullParser parser, String att, int defValue)1197 private static int safeInt(TypedXmlPullParser parser, String att, int defValue) { 1198 return parser.getAttributeInt(null, att, defValue); 1199 } 1200 safeBool(TypedXmlPullParser parser, String att, boolean defValue)1201 private static boolean safeBool(TypedXmlPullParser parser, String att, boolean defValue) { 1202 return parser.getAttributeBoolean(null, att, defValue); 1203 } 1204 safeLongArray(TypedXmlPullParser parser, String att, long[] defValue)1205 private static long[] safeLongArray(TypedXmlPullParser parser, String att, long[] defValue) { 1206 final String attributeValue = parser.getAttributeValue(null, att); 1207 if (TextUtils.isEmpty(attributeValue)) return defValue; 1208 String[] values = attributeValue.split(DELIMITER); 1209 long[] longValues = new long[values.length]; 1210 for (int i = 0; i < values.length; i++) { 1211 try { 1212 longValues[i] = Long.parseLong(values[i]); 1213 } catch (NumberFormatException e) { 1214 longValues[i] = 0; 1215 } 1216 } 1217 return longValues; 1218 } 1219 longArrayToString(long[] values)1220 private static String longArrayToString(long[] values) { 1221 StringBuilder sb = new StringBuilder(); 1222 if (values != null && values.length > 0) { 1223 for (int i = 0; i < values.length - 1; i++) { 1224 sb.append(values[i]).append(DELIMITER); 1225 } 1226 sb.append(values[values.length - 1]); 1227 } 1228 return sb.toString(); 1229 } 1230 1231 public static final @android.annotation.NonNull Creator<NotificationChannel> CREATOR = 1232 new Creator<NotificationChannel>() { 1233 @Override 1234 public NotificationChannel createFromParcel(Parcel in) { 1235 return new NotificationChannel(in); 1236 } 1237 1238 @Override 1239 public NotificationChannel[] newArray(int size) { 1240 return new NotificationChannel[size]; 1241 } 1242 }; 1243 1244 @Override describeContents()1245 public int describeContents() { 1246 return 0; 1247 } 1248 1249 @Override equals(@ullable Object o)1250 public boolean equals(@Nullable Object o) { 1251 if (this == o) return true; 1252 if (o == null || getClass() != o.getClass()) return false; 1253 NotificationChannel that = (NotificationChannel) o; 1254 return getImportance() == that.getImportance() 1255 && mBypassDnd == that.mBypassDnd 1256 && getLockscreenVisibility() == that.getLockscreenVisibility() 1257 && mLights == that.mLights 1258 && getLightColor() == that.getLightColor() 1259 && getUserLockedFields() == that.getUserLockedFields() 1260 && isFgServiceShown() == that.isFgServiceShown() 1261 && mVibrationEnabled == that.mVibrationEnabled 1262 && mShowBadge == that.mShowBadge 1263 && isDeleted() == that.isDeleted() 1264 && getDeletedTimeMs() == that.getDeletedTimeMs() 1265 && isBlockable() == that.isBlockable() 1266 && mAllowBubbles == that.mAllowBubbles 1267 && Objects.equals(getId(), that.getId()) 1268 && Objects.equals(getName(), that.getName()) 1269 && Objects.equals(mDesc, that.mDesc) 1270 && Objects.equals(getSound(), that.getSound()) 1271 && Arrays.equals(mVibration, that.mVibration) 1272 && Objects.equals(getGroup(), that.getGroup()) 1273 && Objects.equals(getAudioAttributes(), that.getAudioAttributes()) 1274 && mImportanceLockedByOEM == that.mImportanceLockedByOEM 1275 && mImportanceLockedDefaultApp == that.mImportanceLockedDefaultApp 1276 && mOriginalImportance == that.mOriginalImportance 1277 && Objects.equals(getParentChannelId(), that.getParentChannelId()) 1278 && Objects.equals(getConversationId(), that.getConversationId()) 1279 && isDemoted() == that.isDemoted() 1280 && isImportantConversation() == that.isImportantConversation(); 1281 } 1282 1283 @Override hashCode()1284 public int hashCode() { 1285 int result = Objects.hash(getId(), getName(), mDesc, getImportance(), mBypassDnd, 1286 getLockscreenVisibility(), getSound(), mLights, getLightColor(), 1287 getUserLockedFields(), 1288 isFgServiceShown(), mVibrationEnabled, mShowBadge, isDeleted(), getDeletedTimeMs(), 1289 getGroup(), getAudioAttributes(), isBlockable(), mAllowBubbles, 1290 mImportanceLockedByOEM, mImportanceLockedDefaultApp, mOriginalImportance, 1291 mParentId, mConversationId, mDemoted, mImportantConvo); 1292 result = 31 * result + Arrays.hashCode(mVibration); 1293 return result; 1294 } 1295 1296 /** @hide */ dump(PrintWriter pw, String prefix, boolean redacted)1297 public void dump(PrintWriter pw, String prefix, boolean redacted) { 1298 String redactedName = redacted ? TextUtils.trimToLengthWithEllipsis(mName, 3) : mName; 1299 String output = "NotificationChannel{" 1300 + "mId='" + mId + '\'' 1301 + ", mName=" + redactedName 1302 + getFieldsString() 1303 + '}'; 1304 pw.println(prefix + output); 1305 } 1306 1307 @Override toString()1308 public String toString() { 1309 return "NotificationChannel{" 1310 + "mId='" + mId + '\'' 1311 + ", mName=" + mName 1312 + getFieldsString() 1313 + '}'; 1314 } 1315 getFieldsString()1316 private String getFieldsString() { 1317 return ", mDescription=" + (!TextUtils.isEmpty(mDesc) ? "hasDescription " : "") 1318 + ", mImportance=" + mImportance 1319 + ", mBypassDnd=" + mBypassDnd 1320 + ", mLockscreenVisibility=" + mLockscreenVisibility 1321 + ", mSound=" + mSound 1322 + ", mLights=" + mLights 1323 + ", mLightColor=" + mLightColor 1324 + ", mVibration=" + Arrays.toString(mVibration) 1325 + ", mUserLockedFields=" + Integer.toHexString(mUserLockedFields) 1326 + ", mFgServiceShown=" + mFgServiceShown 1327 + ", mVibrationEnabled=" + mVibrationEnabled 1328 + ", mShowBadge=" + mShowBadge 1329 + ", mDeleted=" + mDeleted 1330 + ", mDeletedTimeMs=" + mDeletedTime 1331 + ", mGroup='" + mGroup + '\'' 1332 + ", mAudioAttributes=" + mAudioAttributes 1333 + ", mBlockableSystem=" + mBlockableSystem 1334 + ", mAllowBubbles=" + mAllowBubbles 1335 + ", mImportanceLockedByOEM=" + mImportanceLockedByOEM 1336 + ", mImportanceLockedDefaultApp=" + mImportanceLockedDefaultApp 1337 + ", mOriginalImp=" + mOriginalImportance 1338 + ", mParent=" + mParentId 1339 + ", mConversationId=" + mConversationId 1340 + ", mDemoted=" + mDemoted 1341 + ", mImportantConvo=" + mImportantConvo; 1342 } 1343 1344 /** @hide */ dumpDebug(ProtoOutputStream proto, long fieldId)1345 public void dumpDebug(ProtoOutputStream proto, long fieldId) { 1346 final long token = proto.start(fieldId); 1347 1348 proto.write(NotificationChannelProto.ID, mId); 1349 proto.write(NotificationChannelProto.NAME, mName); 1350 proto.write(NotificationChannelProto.DESCRIPTION, mDesc); 1351 proto.write(NotificationChannelProto.IMPORTANCE, mImportance); 1352 proto.write(NotificationChannelProto.CAN_BYPASS_DND, mBypassDnd); 1353 proto.write(NotificationChannelProto.LOCKSCREEN_VISIBILITY, mLockscreenVisibility); 1354 if (mSound != null) { 1355 proto.write(NotificationChannelProto.SOUND, mSound.toString()); 1356 } 1357 proto.write(NotificationChannelProto.USE_LIGHTS, mLights); 1358 proto.write(NotificationChannelProto.LIGHT_COLOR, mLightColor); 1359 if (mVibration != null) { 1360 for (long v : mVibration) { 1361 proto.write(NotificationChannelProto.VIBRATION, v); 1362 } 1363 } 1364 proto.write(NotificationChannelProto.USER_LOCKED_FIELDS, mUserLockedFields); 1365 proto.write(NotificationChannelProto.FG_SERVICE_SHOWN, mFgServiceShown); 1366 proto.write(NotificationChannelProto.IS_VIBRATION_ENABLED, mVibrationEnabled); 1367 proto.write(NotificationChannelProto.SHOW_BADGE, mShowBadge); 1368 proto.write(NotificationChannelProto.IS_DELETED, mDeleted); 1369 proto.write(NotificationChannelProto.GROUP, mGroup); 1370 if (mAudioAttributes != null) { 1371 mAudioAttributes.dumpDebug(proto, NotificationChannelProto.AUDIO_ATTRIBUTES); 1372 } 1373 proto.write(NotificationChannelProto.IS_BLOCKABLE_SYSTEM, mBlockableSystem); 1374 proto.write(NotificationChannelProto.ALLOW_APP_OVERLAY, mAllowBubbles); 1375 1376 proto.end(token); 1377 } 1378 } 1379