blob: 5cdf85a6ca13271d059f7e1aaab59f6a78e6a8ad [file] [log] [blame]
Julia Reynolds85769912016-10-25 09:08:57 -04001/*
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 */
Julia Reynoldsb5e44b72016-08-16 15:00:25 -040016package android.app;
17
Julia Reynoldsb6bd93d2018-10-24 09:22:38 -040018import static android.app.NotificationManager.IMPORTANCE_HIGH;
19
Bernardo Rufinoc27bb6a2017-10-03 13:55:10 +010020import android.annotation.Nullable;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -040021import android.annotation.SystemApi;
Julia Reynolds413ba842019-01-11 10:38:08 -050022import android.annotation.TestApi;
Mathew Inwood61e8ae62018-08-14 14:17:44 +010023import android.annotation.UnsupportedAppUsage;
Jeff Sharkey6503bd82017-04-19 23:24:18 -060024import android.app.NotificationManager.Importance;
Bernardo Rufinoc27bb6a2017-10-03 13:55:10 +010025import android.content.ContentResolver;
26import android.content.Context;
Julia Reynolds1d97e6a2017-03-13 15:05:40 -040027import android.content.Intent;
Julia Reynolds619a69f2017-01-27 15:11:38 -050028import android.media.AudioAttributes;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -040029import android.net.Uri;
30import android.os.Parcel;
31import android.os.Parcelable;
Julia Reynolds184b86d2017-04-12 13:27:58 -040032import android.provider.Settings;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -040033import android.service.notification.NotificationListenerService;
34import android.text.TextUtils;
Kweku Adams62b42242017-09-25 12:54:02 -070035import android.util.proto.ProtoOutputStream;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -040036
Bernardo Rufinoc27bb6a2017-10-03 13:55:10 +010037import com.android.internal.util.Preconditions;
38
Julia Reynolds0f170002017-07-10 10:51:01 -040039import org.json.JSONException;
40import org.json.JSONObject;
41import org.xmlpull.v1.XmlPullParser;
42import org.xmlpull.v1.XmlSerializer;
43
Julia Reynoldsb5e44b72016-08-16 15:00:25 -040044import java.io.IOException;
Aaron Heuckroth51d32882018-07-03 15:14:04 -040045import java.io.PrintWriter;
Julia Reynoldsf57de462016-11-23 11:31:46 -050046import java.util.Arrays;
Julia Reynoldsb6bd93d2018-10-24 09:22:38 -040047import java.util.Objects;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -040048
49/**
50 * A representation of settings that apply to a collection of similarly themed notifications.
51 */
52public final class NotificationChannel implements Parcelable {
53
54 /**
Julia Reynoldsbad42972017-04-25 13:52:49 -040055 * The id of the default channel for an app. This id is reserved by the system. All
56 * notifications posted from apps targeting {@link android.os.Build.VERSION_CODES#N_MR1} or
57 * earlier without a notification channel specified are posted to this channel.
Julia Reynoldsb5e44b72016-08-16 15:00:25 -040058 */
59 public static final String DEFAULT_CHANNEL_ID = "miscellaneous";
60
Julia Reynolds2c891c92017-03-17 14:23:47 -040061 /**
62 * The maximum length for text fields in a NotificationChannel. Fields will be truncated at this
63 * limit.
64 */
65 private static final int MAX_TEXT_LENGTH = 1000;
66
Julia Reynoldsb5e44b72016-08-16 15:00:25 -040067 private static final String TAG_CHANNEL = "channel";
68 private static final String ATT_NAME = "name";
Julia Reynolds2c891c92017-03-17 14:23:47 -040069 private static final String ATT_DESC = "desc";
Julia Reynoldsb5e44b72016-08-16 15:00:25 -040070 private static final String ATT_ID = "id";
Julia Reynolds4036e8d2017-01-13 09:50:05 -050071 private static final String ATT_DELETED = "deleted";
Julia Reynoldsb5e44b72016-08-16 15:00:25 -040072 private static final String ATT_PRIORITY = "priority";
73 private static final String ATT_VISIBILITY = "visibility";
74 private static final String ATT_IMPORTANCE = "importance";
75 private static final String ATT_LIGHTS = "lights";
Julia Reynolds59e152e2017-01-25 17:42:53 -050076 private static final String ATT_LIGHT_COLOR = "light_color";
Julia Reynoldsb5e44b72016-08-16 15:00:25 -040077 private static final String ATT_VIBRATION = "vibration";
Julia Reynoldsf57de462016-11-23 11:31:46 -050078 private static final String ATT_VIBRATION_ENABLED = "vibration_enabled";
Julia Reynolds0c299d42016-11-15 14:37:04 -050079 private static final String ATT_SOUND = "sound";
Julia Reynolds619a69f2017-01-27 15:11:38 -050080 private static final String ATT_USAGE = "usage";
81 private static final String ATT_FLAGS = "flags";
82 private static final String ATT_CONTENT_TYPE = "content_type";
Julia Reynoldsbaff4002016-12-15 11:34:26 -050083 private static final String ATT_SHOW_BADGE = "show_badge";
Julia Reynolds85769912016-10-25 09:08:57 -040084 private static final String ATT_USER_LOCKED = "locked";
Dianne Hackborn025d4a52018-04-30 16:23:26 -070085 private static final String ATT_FG_SERVICE_SHOWN = "fgservice";
Julia Reynolds59e152e2017-01-25 17:42:53 -050086 private static final String ATT_GROUP = "group";
Julia Reynoldsf7321592017-05-24 16:09:19 -040087 private static final String ATT_BLOCKABLE_SYSTEM = "blockable_system";
Julia Reynolds4509ce72019-01-31 13:12:43 -050088 private static final String ATT_ALLOW_BUBBLE = "can_bubble";
Julia Reynoldsf57de462016-11-23 11:31:46 -050089 private static final String DELIMITER = ",";
Julia Reynolds85769912016-10-25 09:08:57 -040090
91 /**
92 * @hide
93 */
Julia Reynolds85769912016-10-25 09:08:57 -040094 public static final int USER_LOCKED_PRIORITY = 0x00000001;
95 /**
96 * @hide
97 */
Julia Reynolds85769912016-10-25 09:08:57 -040098 public static final int USER_LOCKED_VISIBILITY = 0x00000002;
99 /**
100 * @hide
101 */
Julia Reynolds85769912016-10-25 09:08:57 -0400102 public static final int USER_LOCKED_IMPORTANCE = 0x00000004;
103 /**
104 * @hide
105 */
Julia Reynolds85769912016-10-25 09:08:57 -0400106 public static final int USER_LOCKED_LIGHTS = 0x00000008;
107 /**
108 * @hide
109 */
Julia Reynolds85769912016-10-25 09:08:57 -0400110 public static final int USER_LOCKED_VIBRATION = 0x00000010;
111 /**
112 * @hide
113 */
Julia Reynolds0c299d42016-11-15 14:37:04 -0500114 public static final int USER_LOCKED_SOUND = 0x00000020;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400115
Julia Reynoldsbaff4002016-12-15 11:34:26 -0500116 /**
117 * @hide
118 */
Julia Reynoldsbaff4002016-12-15 11:34:26 -0500119 public static final int USER_LOCKED_SHOW_BADGE = 0x00000080;
120
121 /**
122 * @hide
123 */
Mady Mellorc39b4ae2019-01-09 17:11:37 -0800124 public static final int USER_LOCKED_ALLOW_BUBBLE = 0x00000100;
Julia Reynoldsb6bd93d2018-10-24 09:22:38 -0400125
126 /**
127 * @hide
128 */
Julia Reynoldsbaff4002016-12-15 11:34:26 -0500129 public static final int[] LOCKABLE_FIELDS = new int[] {
130 USER_LOCKED_PRIORITY,
131 USER_LOCKED_VISIBILITY,
132 USER_LOCKED_IMPORTANCE,
133 USER_LOCKED_LIGHTS,
134 USER_LOCKED_VIBRATION,
135 USER_LOCKED_SOUND,
Julia Reynolds619a69f2017-01-27 15:11:38 -0500136 USER_LOCKED_SHOW_BADGE,
Mady Mellorc39b4ae2019-01-09 17:11:37 -0800137 USER_LOCKED_ALLOW_BUBBLE
Julia Reynoldsbaff4002016-12-15 11:34:26 -0500138 };
139
Julia Reynolds529e3322017-02-06 08:33:01 -0500140 private static final int DEFAULT_LIGHT_COLOR = 0;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400141 private static final int DEFAULT_VISIBILITY =
Julia Reynolds85769912016-10-25 09:08:57 -0400142 NotificationManager.VISIBILITY_NO_OVERRIDE;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400143 private static final int DEFAULT_IMPORTANCE =
Julia Reynolds85769912016-10-25 09:08:57 -0400144 NotificationManager.IMPORTANCE_UNSPECIFIED;
Julia Reynolds4036e8d2017-01-13 09:50:05 -0500145 private static final boolean DEFAULT_DELETED = false;
Julia Reynolds924eed12017-01-19 09:52:07 -0500146 private static final boolean DEFAULT_SHOW_BADGE = true;
Mady Mellorc39b4ae2019-01-09 17:11:37 -0800147 private static final boolean DEFAULT_ALLOW_BUBBLE = true;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400148
Mathew Inwood61e8ae62018-08-14 14:17:44 +0100149 @UnsupportedAppUsage
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400150 private final String mId;
Julia Reynolds2c891c92017-03-17 14:23:47 -0400151 private String mName;
152 private String mDesc;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400153 private int mImportance = DEFAULT_IMPORTANCE;
154 private boolean mBypassDnd;
155 private int mLockscreenVisibility = DEFAULT_VISIBILITY;
Julia Reynolds184b86d2017-04-12 13:27:58 -0400156 private Uri mSound = Settings.System.DEFAULT_NOTIFICATION_URI;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400157 private boolean mLights;
Julia Reynolds529e3322017-02-06 08:33:01 -0500158 private int mLightColor = DEFAULT_LIGHT_COLOR;
Julia Reynoldsf57de462016-11-23 11:31:46 -0500159 private long[] mVibration;
Kweku Adams62b42242017-09-25 12:54:02 -0700160 // Bitwise representation of fields that have been changed by the user, preventing the app from
161 // making changes to these fields.
Julia Reynolds85769912016-10-25 09:08:57 -0400162 private int mUserLockedFields;
Dianne Hackborn025d4a52018-04-30 16:23:26 -0700163 private boolean mFgServiceShown;
Julia Reynoldsf57de462016-11-23 11:31:46 -0500164 private boolean mVibrationEnabled;
Julia Reynolds924eed12017-01-19 09:52:07 -0500165 private boolean mShowBadge = DEFAULT_SHOW_BADGE;
Julia Reynolds4036e8d2017-01-13 09:50:05 -0500166 private boolean mDeleted = DEFAULT_DELETED;
Julia Reynolds59e152e2017-01-25 17:42:53 -0500167 private String mGroup;
Julia Reynolds619a69f2017-01-27 15:11:38 -0500168 private AudioAttributes mAudioAttributes = Notification.AUDIO_ATTRIBUTES_DEFAULT;
Kweku Adams62b42242017-09-25 12:54:02 -0700169 // If this is a blockable system notification channel.
Julia Reynoldsf7321592017-05-24 16:09:19 -0400170 private boolean mBlockableSystem = false;
Mady Mellorc39b4ae2019-01-09 17:11:37 -0800171 private boolean mAllowBubbles = DEFAULT_ALLOW_BUBBLE;
Julia Reynolds413ba842019-01-11 10:38:08 -0500172 private boolean mImportanceLockedByOEM;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400173
174 /**
175 * Creates a notification channel.
176 *
Julia Reynolds2c891c92017-03-17 14:23:47 -0400177 * @param id The id of the channel. Must be unique per package. The value may be truncated if
178 * it is too long.
179 * @param name The user visible name of the channel. You can rename this channel when the system
Julia Reynolds1d97e6a2017-03-13 15:05:40 -0400180 * locale changes by listening for the {@link Intent#ACTION_LOCALE_CHANGED}
Julia Reynolds2c891c92017-03-17 14:23:47 -0400181 * broadcast. The recommended maximum length is 40 characters; the value may be
182 * truncated if it is too long.
Julia Reynolds85769912016-10-25 09:08:57 -0400183 * @param importance The importance of the channel. This controls how interruptive notifications
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600184 * posted to this channel are.
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400185 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600186 public NotificationChannel(String id, CharSequence name, @Importance int importance) {
Julia Reynolds2c891c92017-03-17 14:23:47 -0400187 this.mId = getTrimmedString(id);
188 this.mName = name != null ? getTrimmedString(name.toString()) : null;
Julia Reynolds85769912016-10-25 09:08:57 -0400189 this.mImportance = importance;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400190 }
191
Julia Reynoldsbad42972017-04-25 13:52:49 -0400192 /**
193 * @hide
194 */
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400195 protected NotificationChannel(Parcel in) {
196 if (in.readByte() != 0) {
197 mId = in.readString();
198 } else {
199 mId = null;
200 }
Julia Reynolds2c891c92017-03-17 14:23:47 -0400201 if (in.readByte() != 0) {
202 mName = in.readString();
203 } else {
204 mName = null;
205 }
206 if (in.readByte() != 0) {
207 mDesc = in.readString();
208 } else {
209 mDesc = null;
210 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400211 mImportance = in.readInt();
212 mBypassDnd = in.readByte() != 0;
213 mLockscreenVisibility = in.readInt();
214 if (in.readByte() != 0) {
Julia Reynolds0c299d42016-11-15 14:37:04 -0500215 mSound = Uri.CREATOR.createFromParcel(in);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400216 } else {
Julia Reynolds0c299d42016-11-15 14:37:04 -0500217 mSound = null;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400218 }
219 mLights = in.readByte() != 0;
Julia Reynoldsf57de462016-11-23 11:31:46 -0500220 mVibration = in.createLongArray();
Julia Reynolds85769912016-10-25 09:08:57 -0400221 mUserLockedFields = in.readInt();
Dianne Hackborn025d4a52018-04-30 16:23:26 -0700222 mFgServiceShown = in.readByte() != 0;
Julia Reynoldsf57de462016-11-23 11:31:46 -0500223 mVibrationEnabled = in.readByte() != 0;
Julia Reynoldsbaff4002016-12-15 11:34:26 -0500224 mShowBadge = in.readByte() != 0;
Julia Reynolds4036e8d2017-01-13 09:50:05 -0500225 mDeleted = in.readByte() != 0;
Julia Reynolds59e152e2017-01-25 17:42:53 -0500226 if (in.readByte() != 0) {
227 mGroup = in.readString();
228 } else {
229 mGroup = null;
230 }
Julia Reynolds619a69f2017-01-27 15:11:38 -0500231 mAudioAttributes = in.readInt() > 0 ? AudioAttributes.CREATOR.createFromParcel(in) : null;
Julia Reynolds529e3322017-02-06 08:33:01 -0500232 mLightColor = in.readInt();
Julia Reynoldsf7321592017-05-24 16:09:19 -0400233 mBlockableSystem = in.readBoolean();
Mady Mellorc39b4ae2019-01-09 17:11:37 -0800234 mAllowBubbles = in.readBoolean();
Julia Reynolds413ba842019-01-11 10:38:08 -0500235 mImportanceLockedByOEM = in.readBoolean();
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400236 }
237
238 @Override
239 public void writeToParcel(Parcel dest, int flags) {
240 if (mId != null) {
241 dest.writeByte((byte) 1);
242 dest.writeString(mId);
243 } else {
244 dest.writeByte((byte) 0);
245 }
Julia Reynolds2c891c92017-03-17 14:23:47 -0400246 if (mName != null) {
247 dest.writeByte((byte) 1);
248 dest.writeString(mName);
249 } else {
250 dest.writeByte((byte) 0);
251 }
252 if (mDesc != null) {
253 dest.writeByte((byte) 1);
254 dest.writeString(mDesc);
255 } else {
256 dest.writeByte((byte) 0);
257 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400258 dest.writeInt(mImportance);
259 dest.writeByte(mBypassDnd ? (byte) 1 : (byte) 0);
260 dest.writeInt(mLockscreenVisibility);
Julia Reynolds0c299d42016-11-15 14:37:04 -0500261 if (mSound != null) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400262 dest.writeByte((byte) 1);
Julia Reynolds0c299d42016-11-15 14:37:04 -0500263 mSound.writeToParcel(dest, 0);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400264 } else {
265 dest.writeByte((byte) 0);
266 }
267 dest.writeByte(mLights ? (byte) 1 : (byte) 0);
Julia Reynoldsf57de462016-11-23 11:31:46 -0500268 dest.writeLongArray(mVibration);
Julia Reynolds85769912016-10-25 09:08:57 -0400269 dest.writeInt(mUserLockedFields);
Dianne Hackborn025d4a52018-04-30 16:23:26 -0700270 dest.writeByte(mFgServiceShown ? (byte) 1 : (byte) 0);
Julia Reynoldsf57de462016-11-23 11:31:46 -0500271 dest.writeByte(mVibrationEnabled ? (byte) 1 : (byte) 0);
Julia Reynoldsbaff4002016-12-15 11:34:26 -0500272 dest.writeByte(mShowBadge ? (byte) 1 : (byte) 0);
Julia Reynolds4036e8d2017-01-13 09:50:05 -0500273 dest.writeByte(mDeleted ? (byte) 1 : (byte) 0);
Julia Reynolds59e152e2017-01-25 17:42:53 -0500274 if (mGroup != null) {
275 dest.writeByte((byte) 1);
276 dest.writeString(mGroup);
277 } else {
278 dest.writeByte((byte) 0);
279 }
Julia Reynolds619a69f2017-01-27 15:11:38 -0500280 if (mAudioAttributes != null) {
281 dest.writeInt(1);
282 mAudioAttributes.writeToParcel(dest, 0);
283 } else {
284 dest.writeInt(0);
285 }
Julia Reynolds529e3322017-02-06 08:33:01 -0500286 dest.writeInt(mLightColor);
Julia Reynoldsf7321592017-05-24 16:09:19 -0400287 dest.writeBoolean(mBlockableSystem);
Mady Mellorc39b4ae2019-01-09 17:11:37 -0800288 dest.writeBoolean(mAllowBubbles);
Julia Reynolds413ba842019-01-11 10:38:08 -0500289 dest.writeBoolean(mImportanceLockedByOEM);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400290 }
291
292 /**
293 * @hide
294 */
Julia Reynolds85769912016-10-25 09:08:57 -0400295 public void lockFields(int field) {
296 mUserLockedFields |= field;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400297 }
298
Julia Reynolds4036e8d2017-01-13 09:50:05 -0500299 /**
300 * @hide
301 */
Julia Reynoldse0b25742017-05-08 12:55:24 -0400302 public void unlockFields(int field) {
303 mUserLockedFields &= ~field;
304 }
305
306 /**
307 * @hide
308 */
Dianne Hackborn025d4a52018-04-30 16:23:26 -0700309 public void setFgServiceShown(boolean shown) {
310 mFgServiceShown = shown;
311 }
312
313 /**
314 * @hide
315 */
Julia Reynolds4036e8d2017-01-13 09:50:05 -0500316 public void setDeleted(boolean deleted) {
317 mDeleted = deleted;
318 }
319
Julia Reynoldsf7321592017-05-24 16:09:19 -0400320 /**
321 * @hide
322 */
Mathew Inwood61e8ae62018-08-14 14:17:44 +0100323 @UnsupportedAppUsage
Julia Reynoldsf7321592017-05-24 16:09:19 -0400324 public void setBlockableSystem(boolean blockableSystem) {
325 mBlockableSystem = blockableSystem;
326 }
Julia Reynolds2c891c92017-03-17 14:23:47 -0400327 // Modifiable by apps post channel creation
328
Julia Reynolds3d91f112017-03-03 08:59:53 -0500329 /**
Julia Reynolds2c891c92017-03-17 14:23:47 -0400330 * Sets the user visible name of this channel.
331 *
332 * <p>The recommended maximum length is 40 characters; the value may be truncated if it is too
333 * long.
Julia Reynolds3d91f112017-03-03 08:59:53 -0500334 */
Julia Reynolds1d97e6a2017-03-13 15:05:40 -0400335 public void setName(CharSequence name) {
Julia Reynolds2c891c92017-03-17 14:23:47 -0400336 mName = name != null ? getTrimmedString(name.toString()) : null;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400337 }
338
339 /**
Julia Reynolds2c891c92017-03-17 14:23:47 -0400340 * Sets the user visible description of this channel.
Julia Reynolds85769912016-10-25 09:08:57 -0400341 *
Julia Reynolds2c891c92017-03-17 14:23:47 -0400342 * <p>The recommended maximum length is 300 characters; the value may be truncated if it is too
343 * long.
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400344 */
Julia Reynolds2c891c92017-03-17 14:23:47 -0400345 public void setDescription(String description) {
346 mDesc = getTrimmedString(description);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400347 }
348
Julia Reynolds2c891c92017-03-17 14:23:47 -0400349 private String getTrimmedString(String input) {
350 if (input != null && input.length() > MAX_TEXT_LENGTH) {
351 return input.substring(0, MAX_TEXT_LENGTH);
352 }
353 return input;
Julia Reynolds85769912016-10-25 09:08:57 -0400354 }
355
Julia Reynolds8f488d32016-10-14 10:59:01 -0400356 // Modifiable by apps on channel creation.
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400357
358 /**
Julia Reynolds59e152e2017-01-25 17:42:53 -0500359 * Sets what group this channel belongs to.
360 *
361 * Group information is only used for presentation, not for behavior.
362 *
Julia Reynolds619a69f2017-01-27 15:11:38 -0500363 * Only modifiable before the channel is submitted to
Julia Reynolds82a9cf62018-04-10 14:59:19 -0400364 * {@link NotificationManager#createNotificationChannel(NotificationChannel)}, unless the
365 * channel is not currently part of a group.
Julia Reynolds619a69f2017-01-27 15:11:38 -0500366 *
Julia Reynolds59e152e2017-01-25 17:42:53 -0500367 * @param groupId the id of a group created by
368 * {@link NotificationManager#createNotificationChannelGroup(NotificationChannelGroup)}.
369 */
370 public void setGroup(String groupId) {
371 this.mGroup = groupId;
372 }
373
374 /**
Julia Reynoldsf35e3972017-01-05 15:41:04 -0500375 * Sets whether notifications posted to this channel can appear as application icon badges
376 * in a Launcher.
377 *
Julia Reynolds82a9cf62018-04-10 14:59:19 -0400378 * Only modifiable before the channel is submitted to
379 * {@link NotificationManager#createNotificationChannel(NotificationChannel)}.
380 *
Julia Reynoldsf35e3972017-01-05 15:41:04 -0500381 * @param showBadge true if badges should be allowed to be shown.
382 */
383 public void setShowBadge(boolean showBadge) {
384 this.mShowBadge = showBadge;
385 }
386
387 /**
Julia Reynolds619a69f2017-01-27 15:11:38 -0500388 * Sets the sound that should be played for notifications posted to this channel and its
Julia Reynolds184b86d2017-04-12 13:27:58 -0400389 * audio attributes. Notification channels with an {@link #getImportance() importance} of at
390 * least {@link NotificationManager#IMPORTANCE_DEFAULT} should have a sound.
Julia Reynolds619a69f2017-01-27 15:11:38 -0500391 *
392 * Only modifiable before the channel is submitted to
Julia Reynolds82a9cf62018-04-10 14:59:19 -0400393 * {@link NotificationManager#createNotificationChannel(NotificationChannel)}.
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400394 */
Julia Reynolds619a69f2017-01-27 15:11:38 -0500395 public void setSound(Uri sound, AudioAttributes audioAttributes) {
Julia Reynolds0c299d42016-11-15 14:37:04 -0500396 this.mSound = sound;
Julia Reynolds619a69f2017-01-27 15:11:38 -0500397 this.mAudioAttributes = audioAttributes;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400398 }
399
400 /**
401 * Sets whether notifications posted to this channel should display notification lights,
Julia Reynolds619a69f2017-01-27 15:11:38 -0500402 * on devices that support that feature.
403 *
404 * Only modifiable before the channel is submitted to
Julia Reynolds82a9cf62018-04-10 14:59:19 -0400405 * {@link NotificationManager#createNotificationChannel(NotificationChannel)}.
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400406 */
Julia Reynolds529e3322017-02-06 08:33:01 -0500407 public void enableLights(boolean lights) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400408 this.mLights = lights;
409 }
410
411 /**
Julia Reynolds529e3322017-02-06 08:33:01 -0500412 * Sets the notification light color for notifications posted to this channel, if lights are
413 * {@link #enableLights(boolean) enabled} on this channel and the device supports that feature.
414 *
415 * Only modifiable before the channel is submitted to
Julia Reynolds82a9cf62018-04-10 14:59:19 -0400416 * {@link NotificationManager#createNotificationChannel(NotificationChannel)}.
Julia Reynolds529e3322017-02-06 08:33:01 -0500417 */
418 public void setLightColor(int argb) {
419 this.mLightColor = argb;
420 }
421
422 /**
Julia Reynoldsf57de462016-11-23 11:31:46 -0500423 * Sets whether notification posted to this channel should vibrate. The vibration pattern can
Julia Reynolds619a69f2017-01-27 15:11:38 -0500424 * be set with {@link #setVibrationPattern(long[])}.
425 *
426 * Only modifiable before the channel is submitted to
Julia Reynolds82a9cf62018-04-10 14:59:19 -0400427 * {@link NotificationManager#createNotificationChannel(NotificationChannel)}.
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400428 */
Julia Reynoldsf57de462016-11-23 11:31:46 -0500429 public void enableVibration(boolean vibration) {
430 this.mVibrationEnabled = vibration;
431 }
432
433 /**
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500434 * Sets the vibration pattern for notifications posted to this channel. If the provided
435 * pattern is valid (non-null, non-empty), will {@link #enableVibration(boolean)} enable
436 * vibration} as well. Otherwise, vibration will be disabled.
Julia Reynolds619a69f2017-01-27 15:11:38 -0500437 *
438 * Only modifiable before the channel is submitted to
Julia Reynolds82a9cf62018-04-10 14:59:19 -0400439 * {@link NotificationManager#createNotificationChannel(NotificationChannel)}.
Julia Reynoldsf57de462016-11-23 11:31:46 -0500440 */
441 public void setVibrationPattern(long[] vibrationPattern) {
Julia Reynoldsa33f5c42017-01-31 16:53:35 -0500442 this.mVibrationEnabled = vibrationPattern != null && vibrationPattern.length > 0;
Julia Reynoldsf57de462016-11-23 11:31:46 -0500443 this.mVibration = vibrationPattern;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400444 }
445
446 /**
Julia Reynolds82a9cf62018-04-10 14:59:19 -0400447 * Sets the level of interruption of this notification channel.
448 *
449 * Only modifiable before the channel is submitted to
450 * {@link NotificationManager#createNotificationChannel(NotificationChannel)}.
Julia Reynolds2c891c92017-03-17 14:23:47 -0400451 *
Jeff Sharkey6503bd82017-04-19 23:24:18 -0600452 * @param importance the amount the user should be interrupted by
453 * notifications from this channel.
Julia Reynolds2c891c92017-03-17 14:23:47 -0400454 */
Jeff Sharkey6503bd82017-04-19 23:24:18 -0600455 public void setImportance(@Importance int importance) {
Julia Reynolds2c891c92017-03-17 14:23:47 -0400456 this.mImportance = importance;
457 }
458
459 // Modifiable by a notification ranker.
460
461 /**
462 * Sets whether or not notifications posted to this channel can interrupt the user in
463 * {@link android.app.NotificationManager.Policy#INTERRUPTION_FILTER_PRIORITY} mode.
464 *
465 * Only modifiable by the system and notification ranker.
466 */
467 public void setBypassDnd(boolean bypassDnd) {
468 this.mBypassDnd = bypassDnd;
469 }
470
471 /**
472 * Sets whether notifications posted to this channel appear on the lockscreen or not, and if so,
473 * whether they appear in a redacted form. See e.g. {@link Notification#VISIBILITY_SECRET}.
474 *
475 * Only modifiable by the system and notification ranker.
476 */
477 public void setLockscreenVisibility(int lockscreenVisibility) {
478 this.mLockscreenVisibility = lockscreenVisibility;
479 }
480
Julia Reynolds2c891c92017-03-17 14:23:47 -0400481 /**
Julia Reynoldsb6bd93d2018-10-24 09:22:38 -0400482 * Sets whether notifications posted to this channel can appear outside of the notification
Mady Mellorc39b4ae2019-01-09 17:11:37 -0800483 * shade, floating over other apps' content as a bubble.
Julia Reynoldsb6bd93d2018-10-24 09:22:38 -0400484 *
485 * <p>This value will be ignored for channels that aren't allowed to pop on screen (that is,
486 * channels whose {@link #getImportance() importance} is <
487 * {@link NotificationManager#IMPORTANCE_HIGH}.</p>
488 *
489 * <p>Only modifiable before the channel is submitted to
490 * * {@link NotificationManager#createNotificationChannel(NotificationChannel)}.</p>
Mady Mellorc39b4ae2019-01-09 17:11:37 -0800491 * @see Notification#getBubbleMetadata()
Julia Reynoldsb6bd93d2018-10-24 09:22:38 -0400492 */
Mady Mellorc39b4ae2019-01-09 17:11:37 -0800493 public void setAllowBubbles(boolean allowBubbles) {
494 mAllowBubbles = allowBubbles;
Julia Reynoldsb6bd93d2018-10-24 09:22:38 -0400495 }
496
497 /**
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400498 * Returns the id of this channel.
499 */
500 public String getId() {
501 return mId;
502 }
503
504 /**
505 * Returns the user visible name of this channel.
506 */
Julia Reynolds2c891c92017-03-17 14:23:47 -0400507 public CharSequence getName() {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400508 return mName;
509 }
510
511 /**
Julia Reynolds2c891c92017-03-17 14:23:47 -0400512 * Returns the user visible description of this channel.
513 */
514 public String getDescription() {
515 return mDesc;
516 }
517
518 /**
Julia Reynolds184b86d2017-04-12 13:27:58 -0400519 * Returns the user specified importance e.g. {@link NotificationManager#IMPORTANCE_LOW} for
Julia Reynolds8d2b0532018-03-29 15:44:13 -0400520 * notifications posted to this channel. Note: This value might be >
521 * {@link NotificationManager#IMPORTANCE_NONE}, but notifications posted to this channel will
522 * not be shown to the user if the parent {@link NotificationChannelGroup} or app is blocked.
523 * See {@link NotificationChannelGroup#isBlocked()} and
524 * {@link NotificationManager#areNotificationsEnabled()}.
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400525 */
526 public int getImportance() {
527 return mImportance;
528 }
529
530 /**
531 * Whether or not notifications posted to this channel can bypass the Do Not Disturb
532 * {@link NotificationManager#INTERRUPTION_FILTER_PRIORITY} mode.
533 */
534 public boolean canBypassDnd() {
535 return mBypassDnd;
536 }
537
538 /**
539 * Returns the notification sound for this channel.
540 */
Julia Reynolds0c299d42016-11-15 14:37:04 -0500541 public Uri getSound() {
542 return mSound;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400543 }
544
545 /**
Julia Reynolds619a69f2017-01-27 15:11:38 -0500546 * Returns the audio attributes for sound played by notifications posted to this channel.
547 */
548 public AudioAttributes getAudioAttributes() {
549 return mAudioAttributes;
550 }
551
552 /**
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400553 * Returns whether notifications posted to this channel trigger notification lights.
554 */
555 public boolean shouldShowLights() {
556 return mLights;
557 }
558
559 /**
Julia Reynolds529e3322017-02-06 08:33:01 -0500560 * Returns the notification light color for notifications posted to this channel. Irrelevant
561 * unless {@link #shouldShowLights()}.
562 */
563 public int getLightColor() {
564 return mLightColor;
565 }
566
567 /**
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400568 * Returns whether notifications posted to this channel always vibrate.
569 */
570 public boolean shouldVibrate() {
Julia Reynoldsf57de462016-11-23 11:31:46 -0500571 return mVibrationEnabled;
572 }
573
574 /**
575 * Returns the vibration pattern for notifications posted to this channel. Will be ignored if
576 * vibration is not enabled ({@link #shouldVibrate()}.
577 */
578 public long[] getVibrationPattern() {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400579 return mVibration;
580 }
581
582 /**
Julia Reynolds85769912016-10-25 09:08:57 -0400583 * Returns whether or not notifications posted to this channel are shown on the lockscreen in
584 * full or redacted form.
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400585 */
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400586 public int getLockscreenVisibility() {
587 return mLockscreenVisibility;
588 }
589
590 /**
Julia Reynoldsbaff4002016-12-15 11:34:26 -0500591 * Returns whether notifications posted to this channel can appear as badges in a Launcher
592 * application.
Julia Reynolds924eed12017-01-19 09:52:07 -0500593 *
594 * Note that badging may be disabled for other reasons.
Julia Reynoldsbaff4002016-12-15 11:34:26 -0500595 */
596 public boolean canShowBadge() {
597 return mShowBadge;
598 }
599
600 /**
Julia Reynolds59e152e2017-01-25 17:42:53 -0500601 * Returns what group this channel belongs to.
602 *
603 * This is used only for visually grouping channels in the UI.
604 */
605 public String getGroup() {
606 return mGroup;
607 }
608
609 /**
Julia Reynoldsb6bd93d2018-10-24 09:22:38 -0400610 * Returns whether notifications posted to this channel can display outside of the notification
611 * shade, in a floating window on top of other apps.
612 */
Mady Mellorc39b4ae2019-01-09 17:11:37 -0800613 public boolean canBubble() {
Mady Mellorc39b4ae2019-01-09 17:11:37 -0800614 return mAllowBubbles;
Julia Reynoldsb6bd93d2018-10-24 09:22:38 -0400615 }
616
617 /**
Julia Reynolds4036e8d2017-01-13 09:50:05 -0500618 * @hide
Julia Reynoldsbaff4002016-12-15 11:34:26 -0500619 */
Julia Reynolds4036e8d2017-01-13 09:50:05 -0500620 @SystemApi
621 public boolean isDeleted() {
622 return mDeleted;
Julia Reynoldsbaff4002016-12-15 11:34:26 -0500623 }
624
625 /**
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400626 * @hide
627 */
628 @SystemApi
Julia Reynolds85769912016-10-25 09:08:57 -0400629 public int getUserLockedFields() {
630 return mUserLockedFields;
631 }
632
633 /**
634 * @hide
635 */
Dianne Hackborn025d4a52018-04-30 16:23:26 -0700636 public boolean isFgServiceShown() {
637 return mFgServiceShown;
638 }
639
640 /**
641 * @hide
642 */
Julia Reynoldsf7321592017-05-24 16:09:19 -0400643 public boolean isBlockableSystem() {
644 return mBlockableSystem;
645 }
646
647 /**
Julia Reynolds413ba842019-01-11 10:38:08 -0500648 * @hide
649 */
650 @TestApi
651 public void setImportanceLockedByOEM(boolean locked) {
652 mImportanceLockedByOEM = locked;
653 }
654
655 /**
656 * @hide
657 */
658 @TestApi
659 public boolean isImportanceLockedByOEM() {
660 return mImportanceLockedByOEM;
661 }
662
663 /**
Julia Reynolds48a6ed92018-10-22 12:52:03 -0400664 * Returns whether the user has chosen the importance of this channel, either to affirm the
665 * initial selection from the app, or changed it to be higher or lower.
Julia Reynoldsb6bd93d2018-10-24 09:22:38 -0400666 * @see #getImportance()
Julia Reynoldsf7321592017-05-24 16:09:19 -0400667 */
Julia Reynolds48a6ed92018-10-22 12:52:03 -0400668 public boolean hasUserSetImportance() {
Julia Reynoldsefcdff42018-08-09 09:42:56 -0400669 return (mUserLockedFields & USER_LOCKED_IMPORTANCE) != 0;
670 }
671
672 /**
673 * @hide
674 */
Bernardo Rufinoc27bb6a2017-10-03 13:55:10 +0100675 public void populateFromXmlForRestore(XmlPullParser parser, Context context) {
676 populateFromXml(parser, true, context);
677 }
678
679 /**
680 * @hide
681 */
Julia Reynolds85769912016-10-25 09:08:57 -0400682 @SystemApi
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400683 public void populateFromXml(XmlPullParser parser) {
Bernardo Rufinoc27bb6a2017-10-03 13:55:10 +0100684 populateFromXml(parser, false, null);
685 }
686
687 /**
688 * If {@param forRestore} is true, {@param Context} MUST be non-null.
689 */
690 private void populateFromXml(XmlPullParser parser, boolean forRestore,
691 @Nullable Context context) {
692 Preconditions.checkArgument(!forRestore || context != null,
693 "forRestore is true but got null context");
694
Julia Reynolds85769912016-10-25 09:08:57 -0400695 // Name, id, and importance are set in the constructor.
Julia Reynolds2c891c92017-03-17 14:23:47 -0400696 setDescription(parser.getAttributeValue(null, ATT_DESC));
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400697 setBypassDnd(Notification.PRIORITY_DEFAULT
698 != safeInt(parser, ATT_PRIORITY, Notification.PRIORITY_DEFAULT));
699 setLockscreenVisibility(safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY));
Bernardo Rufinoc27bb6a2017-10-03 13:55:10 +0100700
701 Uri sound = safeUri(parser, ATT_SOUND);
702 setSound(forRestore ? restoreSoundUri(context, sound) : sound, safeAudioAttributes(parser));
703
Julia Reynolds529e3322017-02-06 08:33:01 -0500704 enableLights(safeBool(parser, ATT_LIGHTS, false));
705 setLightColor(safeInt(parser, ATT_LIGHT_COLOR, DEFAULT_LIGHT_COLOR));
Julia Reynoldsf57de462016-11-23 11:31:46 -0500706 setVibrationPattern(safeLongArray(parser, ATT_VIBRATION, null));
Julia Reynolds745c1542017-05-26 14:43:47 -0400707 enableVibration(safeBool(parser, ATT_VIBRATION_ENABLED, false));
Julia Reynoldsbaff4002016-12-15 11:34:26 -0500708 setShowBadge(safeBool(parser, ATT_SHOW_BADGE, false));
Julia Reynolds4036e8d2017-01-13 09:50:05 -0500709 setDeleted(safeBool(parser, ATT_DELETED, false));
Julia Reynolds59e152e2017-01-25 17:42:53 -0500710 setGroup(parser.getAttributeValue(null, ATT_GROUP));
Julia Reynolds85769912016-10-25 09:08:57 -0400711 lockFields(safeInt(parser, ATT_USER_LOCKED, 0));
Dianne Hackborn025d4a52018-04-30 16:23:26 -0700712 setFgServiceShown(safeBool(parser, ATT_FG_SERVICE_SHOWN, false));
Julia Reynoldsf7321592017-05-24 16:09:19 -0400713 setBlockableSystem(safeBool(parser, ATT_BLOCKABLE_SYSTEM, false));
Mady Mellorc39b4ae2019-01-09 17:11:37 -0800714 setAllowBubbles(safeBool(parser, ATT_ALLOW_BUBBLE, DEFAULT_ALLOW_BUBBLE));
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400715 }
716
Bernardo Rufinoc27bb6a2017-10-03 13:55:10 +0100717 @Nullable
718 private Uri restoreSoundUri(Context context, @Nullable Uri uri) {
Julia Reynoldsaca215a2018-06-20 10:20:31 -0400719 if (uri == null || Uri.EMPTY.equals(uri)) {
Bernardo Rufinoc27bb6a2017-10-03 13:55:10 +0100720 return null;
721 }
722 ContentResolver contentResolver = context.getContentResolver();
723 // There are backups out there with uncanonical uris (because we fixed this after
724 // shipping). If uncanonical uris are given to MediaProvider.uncanonicalize it won't
725 // verify the uri against device storage and we'll possibly end up with a broken uri.
726 // We then canonicalize the uri to uncanonicalize it back, which means we properly check
727 // the uri and in the case of not having the resource we end up with the default - better
728 // than broken. As a side effect we'll canonicalize already canonicalized uris, this is fine
729 // according to the docs because canonicalize method has to handle canonical uris as well.
730 Uri canonicalizedUri = contentResolver.canonicalize(uri);
731 if (canonicalizedUri == null) {
732 // We got a null because the uri in the backup does not exist here, so we return default
733 return Settings.System.DEFAULT_NOTIFICATION_URI;
734 }
735 return contentResolver.uncanonicalize(canonicalizedUri);
736 }
737
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400738 /**
739 * @hide
740 */
741 @SystemApi
742 public void writeXml(XmlSerializer out) throws IOException {
Bernardo Rufinoc27bb6a2017-10-03 13:55:10 +0100743 writeXml(out, false, null);
744 }
745
746 /**
747 * @hide
748 */
749 public void writeXmlForBackup(XmlSerializer out, Context context) throws IOException {
750 writeXml(out, true, context);
751 }
752
753 private Uri getSoundForBackup(Context context) {
754 Uri sound = getSound();
Julia Reynoldsaca215a2018-06-20 10:20:31 -0400755 if (sound == null || Uri.EMPTY.equals(sound)) {
Bernardo Rufinoc27bb6a2017-10-03 13:55:10 +0100756 return null;
757 }
758 Uri canonicalSound = context.getContentResolver().canonicalize(sound);
759 if (canonicalSound == null) {
760 // The content provider does not support canonical uris so we backup the default
761 return Settings.System.DEFAULT_NOTIFICATION_URI;
762 }
763 return canonicalSound;
764 }
765
766 /**
767 * If {@param forBackup} is true, {@param Context} MUST be non-null.
768 */
769 private void writeXml(XmlSerializer out, boolean forBackup, @Nullable Context context)
770 throws IOException {
771 Preconditions.checkArgument(!forBackup || context != null,
772 "forBackup is true but got null context");
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400773 out.startTag(null, TAG_CHANNEL);
774 out.attribute(null, ATT_ID, getId());
Julia Reynolds5a311932017-03-01 16:33:44 -0500775 if (getName() != null) {
776 out.attribute(null, ATT_NAME, getName().toString());
777 }
Julia Reynolds2c891c92017-03-17 14:23:47 -0400778 if (getDescription() != null) {
779 out.attribute(null, ATT_DESC, getDescription());
780 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400781 if (getImportance() != DEFAULT_IMPORTANCE) {
782 out.attribute(
783 null, ATT_IMPORTANCE, Integer.toString(getImportance()));
784 }
785 if (canBypassDnd()) {
786 out.attribute(
787 null, ATT_PRIORITY, Integer.toString(Notification.PRIORITY_MAX));
788 }
789 if (getLockscreenVisibility() != DEFAULT_VISIBILITY) {
790 out.attribute(null, ATT_VISIBILITY,
791 Integer.toString(getLockscreenVisibility()));
792 }
Bernardo Rufinoc27bb6a2017-10-03 13:55:10 +0100793 Uri sound = forBackup ? getSoundForBackup(context) : getSound();
794 if (sound != null) {
795 out.attribute(null, ATT_SOUND, sound.toString());
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400796 }
Julia Reynolds619a69f2017-01-27 15:11:38 -0500797 if (getAudioAttributes() != null) {
798 out.attribute(null, ATT_USAGE, Integer.toString(getAudioAttributes().getUsage()));
799 out.attribute(null, ATT_CONTENT_TYPE,
800 Integer.toString(getAudioAttributes().getContentType()));
801 out.attribute(null, ATT_FLAGS, Integer.toString(getAudioAttributes().getFlags()));
802 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400803 if (shouldShowLights()) {
804 out.attribute(null, ATT_LIGHTS, Boolean.toString(shouldShowLights()));
805 }
Julia Reynolds529e3322017-02-06 08:33:01 -0500806 if (getLightColor() != DEFAULT_LIGHT_COLOR) {
807 out.attribute(null, ATT_LIGHT_COLOR, Integer.toString(getLightColor()));
808 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400809 if (shouldVibrate()) {
Julia Reynoldsf57de462016-11-23 11:31:46 -0500810 out.attribute(null, ATT_VIBRATION_ENABLED, Boolean.toString(shouldVibrate()));
811 }
812 if (getVibrationPattern() != null) {
813 out.attribute(null, ATT_VIBRATION, longArrayToString(getVibrationPattern()));
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400814 }
Julia Reynolds85769912016-10-25 09:08:57 -0400815 if (getUserLockedFields() != 0) {
816 out.attribute(null, ATT_USER_LOCKED, Integer.toString(getUserLockedFields()));
817 }
Dianne Hackborn025d4a52018-04-30 16:23:26 -0700818 if (isFgServiceShown()) {
819 out.attribute(null, ATT_FG_SERVICE_SHOWN, Boolean.toString(isFgServiceShown()));
820 }
Julia Reynoldsbaff4002016-12-15 11:34:26 -0500821 if (canShowBadge()) {
822 out.attribute(null, ATT_SHOW_BADGE, Boolean.toString(canShowBadge()));
823 }
Julia Reynolds4036e8d2017-01-13 09:50:05 -0500824 if (isDeleted()) {
825 out.attribute(null, ATT_DELETED, Boolean.toString(isDeleted()));
826 }
Julia Reynolds59e152e2017-01-25 17:42:53 -0500827 if (getGroup() != null) {
828 out.attribute(null, ATT_GROUP, getGroup());
829 }
Julia Reynoldsf7321592017-05-24 16:09:19 -0400830 if (isBlockableSystem()) {
831 out.attribute(null, ATT_BLOCKABLE_SYSTEM, Boolean.toString(isBlockableSystem()));
832 }
Mady Mellorc39b4ae2019-01-09 17:11:37 -0800833 if (canBubble() != DEFAULT_ALLOW_BUBBLE) {
834 out.attribute(null, ATT_ALLOW_BUBBLE, Boolean.toString(canBubble()));
Julia Reynoldsb6bd93d2018-10-24 09:22:38 -0400835 }
Julia Reynolds85769912016-10-25 09:08:57 -0400836
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400837 out.endTag(null, TAG_CHANNEL);
838 }
839
840 /**
841 * @hide
842 */
843 @SystemApi
844 public JSONObject toJson() throws JSONException {
845 JSONObject record = new JSONObject();
846 record.put(ATT_ID, getId());
847 record.put(ATT_NAME, getName());
Julia Reynolds2c891c92017-03-17 14:23:47 -0400848 record.put(ATT_DESC, getDescription());
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400849 if (getImportance() != DEFAULT_IMPORTANCE) {
850 record.put(ATT_IMPORTANCE,
851 NotificationListenerService.Ranking.importanceToString(getImportance()));
852 }
853 if (canBypassDnd()) {
854 record.put(ATT_PRIORITY, Notification.PRIORITY_MAX);
855 }
856 if (getLockscreenVisibility() != DEFAULT_VISIBILITY) {
857 record.put(ATT_VISIBILITY, Notification.visibilityToString(getLockscreenVisibility()));
858 }
Julia Reynolds0c299d42016-11-15 14:37:04 -0500859 if (getSound() != null) {
860 record.put(ATT_SOUND, getSound().toString());
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400861 }
Julia Reynolds619a69f2017-01-27 15:11:38 -0500862 if (getAudioAttributes() != null) {
863 record.put(ATT_USAGE, Integer.toString(getAudioAttributes().getUsage()));
864 record.put(ATT_CONTENT_TYPE,
865 Integer.toString(getAudioAttributes().getContentType()));
866 record.put(ATT_FLAGS, Integer.toString(getAudioAttributes().getFlags()));
867 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400868 record.put(ATT_LIGHTS, Boolean.toString(shouldShowLights()));
Julia Reynolds529e3322017-02-06 08:33:01 -0500869 record.put(ATT_LIGHT_COLOR, Integer.toString(getLightColor()));
Julia Reynoldsf57de462016-11-23 11:31:46 -0500870 record.put(ATT_VIBRATION_ENABLED, Boolean.toString(shouldVibrate()));
Julia Reynolds85769912016-10-25 09:08:57 -0400871 record.put(ATT_USER_LOCKED, Integer.toString(getUserLockedFields()));
Dianne Hackborn025d4a52018-04-30 16:23:26 -0700872 record.put(ATT_FG_SERVICE_SHOWN, Boolean.toString(isFgServiceShown()));
Julia Reynoldsf57de462016-11-23 11:31:46 -0500873 record.put(ATT_VIBRATION, longArrayToString(getVibrationPattern()));
Julia Reynoldsbaff4002016-12-15 11:34:26 -0500874 record.put(ATT_SHOW_BADGE, Boolean.toString(canShowBadge()));
Julia Reynolds4036e8d2017-01-13 09:50:05 -0500875 record.put(ATT_DELETED, Boolean.toString(isDeleted()));
Julia Reynolds59e152e2017-01-25 17:42:53 -0500876 record.put(ATT_GROUP, getGroup());
Julia Reynoldsf7321592017-05-24 16:09:19 -0400877 record.put(ATT_BLOCKABLE_SYSTEM, isBlockableSystem());
Mady Mellorc39b4ae2019-01-09 17:11:37 -0800878 record.put(ATT_ALLOW_BUBBLE, canBubble());
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400879 return record;
880 }
881
Julia Reynolds619a69f2017-01-27 15:11:38 -0500882 private static AudioAttributes safeAudioAttributes(XmlPullParser parser) {
883 int usage = safeInt(parser, ATT_USAGE, AudioAttributes.USAGE_NOTIFICATION);
884 int contentType = safeInt(parser, ATT_CONTENT_TYPE,
885 AudioAttributes.CONTENT_TYPE_SONIFICATION);
886 int flags = safeInt(parser, ATT_FLAGS, 0);
887 return new AudioAttributes.Builder()
888 .setUsage(usage)
889 .setContentType(contentType)
890 .setFlags(flags)
891 .build();
892 }
893
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400894 private static Uri safeUri(XmlPullParser parser, String att) {
895 final String val = parser.getAttributeValue(null, att);
896 return val == null ? null : Uri.parse(val);
897 }
898
899 private static int safeInt(XmlPullParser parser, String att, int defValue) {
900 final String val = parser.getAttributeValue(null, att);
901 return tryParseInt(val, defValue);
902 }
903
904 private static int tryParseInt(String value, int defValue) {
905 if (TextUtils.isEmpty(value)) return defValue;
906 try {
907 return Integer.parseInt(value);
908 } catch (NumberFormatException e) {
909 return defValue;
910 }
911 }
912
913 private static boolean safeBool(XmlPullParser parser, String att, boolean defValue) {
914 final String value = parser.getAttributeValue(null, att);
915 if (TextUtils.isEmpty(value)) return defValue;
916 return Boolean.parseBoolean(value);
917 }
918
Julia Reynoldsf57de462016-11-23 11:31:46 -0500919 private static long[] safeLongArray(XmlPullParser parser, String att, long[] defValue) {
920 final String attributeValue = parser.getAttributeValue(null, att);
921 if (TextUtils.isEmpty(attributeValue)) return defValue;
922 String[] values = attributeValue.split(DELIMITER);
923 long[] longValues = new long[values.length];
924 for (int i = 0; i < values.length; i++) {
925 try {
926 longValues[i] = Long.parseLong(values[i]);
927 } catch (NumberFormatException e) {
928 longValues[i] = 0;
929 }
930 }
931 return longValues;
932 }
933
934 private static String longArrayToString(long[] values) {
935 StringBuffer sb = new StringBuffer();
Julia Reynolds0f170002017-07-10 10:51:01 -0400936 if (values != null && values.length > 0) {
Julia Reynolds59e152e2017-01-25 17:42:53 -0500937 for (int i = 0; i < values.length - 1; i++) {
938 sb.append(values[i]).append(DELIMITER);
939 }
940 sb.append(values[values.length - 1]);
Julia Reynoldsf57de462016-11-23 11:31:46 -0500941 }
Julia Reynoldsf57de462016-11-23 11:31:46 -0500942 return sb.toString();
943 }
944
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700945 public static final @android.annotation.NonNull Creator<NotificationChannel> CREATOR = new Creator<NotificationChannel>() {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400946 @Override
947 public NotificationChannel createFromParcel(Parcel in) {
948 return new NotificationChannel(in);
949 }
950
951 @Override
952 public NotificationChannel[] newArray(int size) {
953 return new NotificationChannel[size];
954 }
955 };
956
957 @Override
958 public int describeContents() {
959 return 0;
960 }
961
962 @Override
963 public boolean equals(Object o) {
964 if (this == o) return true;
965 if (o == null || getClass() != o.getClass()) return false;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400966 NotificationChannel that = (NotificationChannel) o;
Julia Reynolds413ba842019-01-11 10:38:08 -0500967 return getImportance() == that.getImportance()
968 && mBypassDnd == that.mBypassDnd
969 && getLockscreenVisibility() == that.getLockscreenVisibility()
970 && mLights == that.mLights
971 && getLightColor() == that.getLightColor()
972 && getUserLockedFields() == that.getUserLockedFields()
973 && isFgServiceShown() == that.isFgServiceShown()
974 && mVibrationEnabled == that.mVibrationEnabled
975 && mShowBadge == that.mShowBadge
976 && isDeleted() == that.isDeleted()
977 && isBlockableSystem() == that.isBlockableSystem()
Mady Mellorc39b4ae2019-01-09 17:11:37 -0800978 && mAllowBubbles == that.mAllowBubbles
Julia Reynolds413ba842019-01-11 10:38:08 -0500979 && Objects.equals(getId(), that.getId())
980 && Objects.equals(getName(), that.getName())
981 && Objects.equals(mDesc, that.mDesc)
982 && Objects.equals(getSound(), that.getSound())
983 && Arrays.equals(mVibration, that.mVibration)
984 && Objects.equals(getGroup(), that.getGroup())
985 && Objects.equals(getAudioAttributes(), that.getAudioAttributes())
986 && mImportanceLockedByOEM == that.mImportanceLockedByOEM;
Julia Reynolds85769912016-10-25 09:08:57 -0400987 }
988
989 @Override
990 public int hashCode() {
Julia Reynoldsb6bd93d2018-10-24 09:22:38 -0400991 int result = Objects.hash(getId(), getName(), mDesc, getImportance(), mBypassDnd,
992 getLockscreenVisibility(), getSound(), mLights, getLightColor(),
993 getUserLockedFields(),
994 isFgServiceShown(), mVibrationEnabled, mShowBadge, isDeleted(), getGroup(),
Mady Mellorc39b4ae2019-01-09 17:11:37 -0800995 getAudioAttributes(), isBlockableSystem(), mAllowBubbles,
Julia Reynolds413ba842019-01-11 10:38:08 -0500996 mImportanceLockedByOEM);
Julia Reynoldsf57de462016-11-23 11:31:46 -0500997 result = 31 * result + Arrays.hashCode(mVibration);
Julia Reynolds85769912016-10-25 09:08:57 -0400998 return result;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400999 }
1000
Aaron Heuckroth51d32882018-07-03 15:14:04 -04001001 /** @hide */
1002 public void dump(PrintWriter pw, String prefix, boolean redacted) {
1003 String redactedName = redacted ? TextUtils.trimToLengthWithEllipsis(mName, 3) : mName;
1004 String output = "NotificationChannel{"
1005 + "mId='" + mId + '\''
1006 + ", mName=" + redactedName
1007 + ", mDescription=" + (!TextUtils.isEmpty(mDesc) ? "hasDescription " : "")
1008 + ", mImportance=" + mImportance
1009 + ", mBypassDnd=" + mBypassDnd
1010 + ", mLockscreenVisibility=" + mLockscreenVisibility
1011 + ", mSound=" + mSound
1012 + ", mLights=" + mLights
1013 + ", mLightColor=" + mLightColor
1014 + ", mVibration=" + Arrays.toString(mVibration)
1015 + ", mUserLockedFields=" + Integer.toHexString(mUserLockedFields)
1016 + ", mFgServiceShown=" + mFgServiceShown
1017 + ", mVibrationEnabled=" + mVibrationEnabled
1018 + ", mShowBadge=" + mShowBadge
1019 + ", mDeleted=" + mDeleted
1020 + ", mGroup='" + mGroup + '\''
1021 + ", mAudioAttributes=" + mAudioAttributes
1022 + ", mBlockableSystem=" + mBlockableSystem
Mady Mellorc39b4ae2019-01-09 17:11:37 -08001023 + ", mAllowBubbles=" + mAllowBubbles
Julia Reynolds413ba842019-01-11 10:38:08 -05001024 + ", mImportanceLockedByOEM=" + mImportanceLockedByOEM
Aaron Heuckroth51d32882018-07-03 15:14:04 -04001025 + '}';
1026 pw.println(prefix + output);
1027 }
1028
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001029 @Override
1030 public String toString() {
Julia Reynolds005c8b92017-08-24 10:35:53 -04001031 return "NotificationChannel{"
1032 + "mId='" + mId + '\''
1033 + ", mName=" + mName
1034 + ", mDescription=" + (!TextUtils.isEmpty(mDesc) ? "hasDescription " : "")
1035 + ", mImportance=" + mImportance
1036 + ", mBypassDnd=" + mBypassDnd
1037 + ", mLockscreenVisibility=" + mLockscreenVisibility
1038 + ", mSound=" + mSound
1039 + ", mLights=" + mLights
1040 + ", mLightColor=" + mLightColor
1041 + ", mVibration=" + Arrays.toString(mVibration)
1042 + ", mUserLockedFields=" + Integer.toHexString(mUserLockedFields)
Dianne Hackborn025d4a52018-04-30 16:23:26 -07001043 + ", mFgServiceShown=" + mFgServiceShown
Julia Reynolds005c8b92017-08-24 10:35:53 -04001044 + ", mVibrationEnabled=" + mVibrationEnabled
1045 + ", mShowBadge=" + mShowBadge
1046 + ", mDeleted=" + mDeleted
1047 + ", mGroup='" + mGroup + '\''
1048 + ", mAudioAttributes=" + mAudioAttributes
1049 + ", mBlockableSystem=" + mBlockableSystem
Mady Mellorc39b4ae2019-01-09 17:11:37 -08001050 + ", mAllowBubbles=" + mAllowBubbles
Julia Reynolds413ba842019-01-11 10:38:08 -05001051 + ", mImportanceLockedByOEM=" + mImportanceLockedByOEM
Julia Reynolds005c8b92017-08-24 10:35:53 -04001052 + '}';
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001053 }
Kweku Adams62b42242017-09-25 12:54:02 -07001054
1055 /** @hide */
Kweku Adamsbc84aec2018-01-23 13:33:12 -08001056 public void writeToProto(ProtoOutputStream proto, long fieldId) {
1057 final long token = proto.start(fieldId);
1058
Kweku Adams62b42242017-09-25 12:54:02 -07001059 proto.write(NotificationChannelProto.ID, mId);
1060 proto.write(NotificationChannelProto.NAME, mName);
1061 proto.write(NotificationChannelProto.DESCRIPTION, mDesc);
1062 proto.write(NotificationChannelProto.IMPORTANCE, mImportance);
1063 proto.write(NotificationChannelProto.CAN_BYPASS_DND, mBypassDnd);
1064 proto.write(NotificationChannelProto.LOCKSCREEN_VISIBILITY, mLockscreenVisibility);
1065 if (mSound != null) {
1066 proto.write(NotificationChannelProto.SOUND, mSound.toString());
1067 }
1068 proto.write(NotificationChannelProto.USE_LIGHTS, mLights);
1069 proto.write(NotificationChannelProto.LIGHT_COLOR, mLightColor);
1070 if (mVibration != null) {
1071 for (long v : mVibration) {
1072 proto.write(NotificationChannelProto.VIBRATION, v);
1073 }
1074 }
1075 proto.write(NotificationChannelProto.USER_LOCKED_FIELDS, mUserLockedFields);
Dianne Hackborn025d4a52018-04-30 16:23:26 -07001076 proto.write(NotificationChannelProto.FG_SERVICE_SHOWN, mFgServiceShown);
Kweku Adams62b42242017-09-25 12:54:02 -07001077 proto.write(NotificationChannelProto.IS_VIBRATION_ENABLED, mVibrationEnabled);
1078 proto.write(NotificationChannelProto.SHOW_BADGE, mShowBadge);
1079 proto.write(NotificationChannelProto.IS_DELETED, mDeleted);
1080 proto.write(NotificationChannelProto.GROUP, mGroup);
1081 if (mAudioAttributes != null) {
Kweku Adamsbc84aec2018-01-23 13:33:12 -08001082 mAudioAttributes.writeToProto(proto, NotificationChannelProto.AUDIO_ATTRIBUTES);
Kweku Adams62b42242017-09-25 12:54:02 -07001083 }
1084 proto.write(NotificationChannelProto.IS_BLOCKABLE_SYSTEM, mBlockableSystem);
Mady Mellorc39b4ae2019-01-09 17:11:37 -08001085 proto.write(NotificationChannelProto.ALLOW_APP_OVERLAY, mAllowBubbles);
Kweku Adamsbc84aec2018-01-23 13:33:12 -08001086
1087 proto.end(token);
Kweku Adams62b42242017-09-25 12:54:02 -07001088 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001089}