blob: 530b8bb7f3eb37e60ed901538ad14768976b95ab [file] [log] [blame]
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001package android.app;
2
3import org.json.JSONException;
4import org.json.JSONObject;
5import org.xmlpull.v1.XmlPullParser;
6import org.xmlpull.v1.XmlSerializer;
7
8import android.annotation.SystemApi;
9import android.net.Uri;
10import android.os.Parcel;
11import android.os.Parcelable;
12import android.service.notification.NotificationListenerService;
13import android.text.TextUtils;
14
15import java.io.IOException;
16
17/**
18 * A representation of settings that apply to a collection of similarly themed notifications.
19 */
20public final class NotificationChannel implements Parcelable {
21
22 /**
23 * The id of the default channel for an app. All notifications posted without a notification
24 * channel specified are posted to this channel.
25 */
26 public static final String DEFAULT_CHANNEL_ID = "miscellaneous";
27
28 private static final String TAG_CHANNEL = "channel";
29 private static final String ATT_NAME = "name";
30 private static final String ATT_ID = "id";
31 private static final String ATT_PRIORITY = "priority";
32 private static final String ATT_VISIBILITY = "visibility";
33 private static final String ATT_IMPORTANCE = "importance";
34 private static final String ATT_LIGHTS = "lights";
35 private static final String ATT_VIBRATION = "vibration";
36 private static final String ATT_DEFAULT_RINGTONE = "ringtone";
37
38 private static final int DEFAULT_VISIBILITY =
39 NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE;
40 private static final int DEFAULT_IMPORTANCE =
41 NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
42
43 private final String mId;
44 private CharSequence mName;
45 private int mImportance = DEFAULT_IMPORTANCE;
46 private boolean mBypassDnd;
47 private int mLockscreenVisibility = DEFAULT_VISIBILITY;
48 private Uri mRingtone;
49 private boolean mLights;
50 private boolean mVibration;
51
52 /**
53 * Creates a notification channel.
54 *
55 * @param id The id of the channel. Must be unique per package.
56 * @param name The user visible name of the channel.
57 */
58 public NotificationChannel(String id, CharSequence name) {
59 this.mId = id;
60 this.mName = name;
61 }
62
63 protected NotificationChannel(Parcel in) {
64 if (in.readByte() != 0) {
65 mId = in.readString();
66 } else {
67 mId = null;
68 }
69 mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
70 mImportance = in.readInt();
71 mBypassDnd = in.readByte() != 0;
72 mLockscreenVisibility = in.readInt();
73 if (in.readByte() != 0) {
74 mRingtone = Uri.CREATOR.createFromParcel(in);
75 } else {
76 mRingtone = null;
77 }
78 mLights = in.readByte() != 0;
79 mVibration = in.readByte() != 0;
80 }
81
82 @Override
83 public void writeToParcel(Parcel dest, int flags) {
84 if (mId != null) {
85 dest.writeByte((byte) 1);
86 dest.writeString(mId);
87 } else {
88 dest.writeByte((byte) 0);
89 }
90 TextUtils.writeToParcel(mName, dest, flags);
91 dest.writeInt(mImportance);
92 dest.writeByte(mBypassDnd ? (byte) 1 : (byte) 0);
93 dest.writeInt(mLockscreenVisibility);
94 if (mRingtone != null) {
95 dest.writeByte((byte) 1);
96 mRingtone.writeToParcel(dest, 0);
97 } else {
98 dest.writeByte((byte) 0);
99 }
100 dest.writeByte(mLights ? (byte) 1 : (byte) 0);
101 dest.writeByte(mVibration ? (byte) 1 : (byte) 0);
102 }
103
104 // Only modifiable by users.
105 /**
106 * @hide
107 */
108 @SystemApi
109 public void setName(CharSequence name) {
110 this.mName = name;
111 }
112
113 /**
114 * @hide
115 */
116 @SystemApi
117 public void setImportance(int importance) {
118 this.mImportance = importance;
119 }
120
121 /**
122 * @hide
123 */
124 @SystemApi
125 public void setBypassDnd(boolean bypassDnd) {
126 this.mBypassDnd = bypassDnd;
127 }
128
129 /**
130 * @hide
131 */
132 @SystemApi
133 public void setLockscreenVisibility(int lockscreenVisibility) {
134 this.mLockscreenVisibility = lockscreenVisibility;
135 }
136
137 // Modifiable by apps.
138
139 /**
140 * Sets the ringtone that should be played for notifications posted to this channel if
141 * the notifications don't supply a ringtone.
142 */
143 public void setDefaultRingtone(Uri defaultRingtone) {
144 this.mRingtone = defaultRingtone;
145 }
146
147 /**
148 * Sets whether notifications posted to this channel should display notification lights,
149 * on devices that support that feature.
150 */
151 public void setLights(boolean lights) {
152 this.mLights = lights;
153 }
154
155 /**
156 * Sets whether notification posted to this channel should vibrate, even if individual
157 * notifications are marked as having vibration.
158 */
159 public void setVibration(boolean vibration) {
160 this.mVibration = vibration;
161 }
162
163 /**
164 * Returns the id of this channel.
165 */
166 public String getId() {
167 return mId;
168 }
169
170 /**
171 * Returns the user visible name of this channel.
172 */
173 public CharSequence getName() {
174 return mName;
175 }
176
177 /**
178 * Returns the user specified importance {e.g. @link NotificationManager#IMPORTANCE_LOW} for
179 * notifications posted to this channel.
180 */
181 public int getImportance() {
182 return mImportance;
183 }
184
185 /**
186 * Whether or not notifications posted to this channel can bypass the Do Not Disturb
187 * {@link NotificationManager#INTERRUPTION_FILTER_PRIORITY} mode.
188 */
189 public boolean canBypassDnd() {
190 return mBypassDnd;
191 }
192
193 /**
194 * Returns the notification sound for this channel.
195 */
196 public Uri getDefaultRingtone() {
197 return mRingtone;
198 }
199
200 /**
201 * Returns whether notifications posted to this channel trigger notification lights.
202 */
203 public boolean shouldShowLights() {
204 return mLights;
205 }
206
207 /**
208 * Returns whether notifications posted to this channel always vibrate.
209 */
210 public boolean shouldVibrate() {
211 return mVibration;
212 }
213
214 /**
215 * @hide
216 */
217 @SystemApi
218 public int getLockscreenVisibility() {
219 return mLockscreenVisibility;
220 }
221
222 /**
223 * @hide
224 */
225 @SystemApi
226 public void populateFromXml(XmlPullParser parser) {
227 // Name and id are set in the constructor.
228 setImportance(safeInt(parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE));
229 setBypassDnd(Notification.PRIORITY_DEFAULT
230 != safeInt(parser, ATT_PRIORITY, Notification.PRIORITY_DEFAULT));
231 setLockscreenVisibility(safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY));
232 setDefaultRingtone(safeUri(parser, ATT_DEFAULT_RINGTONE));
233 setLights(safeBool(parser, ATT_LIGHTS, false));
234 setVibration(safeBool(parser, ATT_VIBRATION, false));
235 }
236
237 /**
238 * @hide
239 */
240 @SystemApi
241 public void writeXml(XmlSerializer out) throws IOException {
242 out.startTag(null, TAG_CHANNEL);
243 out.attribute(null, ATT_ID, getId());
244 out.attribute(null, ATT_NAME, getName().toString());
245 if (getImportance() != DEFAULT_IMPORTANCE) {
246 out.attribute(
247 null, ATT_IMPORTANCE, Integer.toString(getImportance()));
248 }
249 if (canBypassDnd()) {
250 out.attribute(
251 null, ATT_PRIORITY, Integer.toString(Notification.PRIORITY_MAX));
252 }
253 if (getLockscreenVisibility() != DEFAULT_VISIBILITY) {
254 out.attribute(null, ATT_VISIBILITY,
255 Integer.toString(getLockscreenVisibility()));
256 }
257 if (getDefaultRingtone() != null) {
258 out.attribute(null, ATT_DEFAULT_RINGTONE, getDefaultRingtone().toString());
259 }
260 if (shouldShowLights()) {
261 out.attribute(null, ATT_LIGHTS, Boolean.toString(shouldShowLights()));
262 }
263 if (shouldVibrate()) {
264 out.attribute(null, ATT_VIBRATION, Boolean.toString(shouldVibrate()));
265 }
266 out.endTag(null, TAG_CHANNEL);
267 }
268
269 /**
270 * @hide
271 */
272 @SystemApi
273 public JSONObject toJson() throws JSONException {
274 JSONObject record = new JSONObject();
275 record.put(ATT_ID, getId());
276 record.put(ATT_NAME, getName());
277 if (getImportance() != DEFAULT_IMPORTANCE) {
278 record.put(ATT_IMPORTANCE,
279 NotificationListenerService.Ranking.importanceToString(getImportance()));
280 }
281 if (canBypassDnd()) {
282 record.put(ATT_PRIORITY, Notification.PRIORITY_MAX);
283 }
284 if (getLockscreenVisibility() != DEFAULT_VISIBILITY) {
285 record.put(ATT_VISIBILITY, Notification.visibilityToString(getLockscreenVisibility()));
286 }
287 if (getDefaultRingtone() != null) {
288 record.put(ATT_DEFAULT_RINGTONE, getDefaultRingtone().toString());
289 }
290 record.put(ATT_LIGHTS, Boolean.toString(shouldShowLights()));
291 record.put(ATT_VIBRATION, Boolean.toString(shouldVibrate()));
292
293 return record;
294 }
295
296 private static Uri safeUri(XmlPullParser parser, String att) {
297 final String val = parser.getAttributeValue(null, att);
298 return val == null ? null : Uri.parse(val);
299 }
300
301 private static int safeInt(XmlPullParser parser, String att, int defValue) {
302 final String val = parser.getAttributeValue(null, att);
303 return tryParseInt(val, defValue);
304 }
305
306 private static int tryParseInt(String value, int defValue) {
307 if (TextUtils.isEmpty(value)) return defValue;
308 try {
309 return Integer.parseInt(value);
310 } catch (NumberFormatException e) {
311 return defValue;
312 }
313 }
314
315 private static boolean safeBool(XmlPullParser parser, String att, boolean defValue) {
316 final String value = parser.getAttributeValue(null, att);
317 if (TextUtils.isEmpty(value)) return defValue;
318 return Boolean.parseBoolean(value);
319 }
320
321 public static final Creator<NotificationChannel> CREATOR = new Creator<NotificationChannel>() {
322 @Override
323 public NotificationChannel createFromParcel(Parcel in) {
324 return new NotificationChannel(in);
325 }
326
327 @Override
328 public NotificationChannel[] newArray(int size) {
329 return new NotificationChannel[size];
330 }
331 };
332
333 @Override
334 public int describeContents() {
335 return 0;
336 }
337
338 @Override
339 public boolean equals(Object o) {
340 if (this == o) return true;
341 if (o == null || getClass() != o.getClass()) return false;
342
343 NotificationChannel that = (NotificationChannel) o;
344
345 if (mImportance != that.mImportance) return false;
346 if (mBypassDnd != that.mBypassDnd) return false;
347 if (mLockscreenVisibility != that.mLockscreenVisibility) return false;
348 if (mLights != that.mLights) return false;
349 if (mVibration != that.mVibration) return false;
350 if (!mId.equals(that.mId)) return false;
351 if (mName != null ? !mName.equals(that.mName) : that.mName != null) return false;
352 return mRingtone != null ? mRingtone.equals(
353 that.mRingtone) : that.mRingtone == null;
354 }
355
356 @Override
357 public String toString() {
358 return "NotificationChannel{" +
359 "mId='" + mId + '\'' +
360 ", mName=" + mName +
361 ", mImportance=" + mImportance +
362 ", mBypassDnd=" + mBypassDnd +
363 ", mLockscreenVisibility=" + mLockscreenVisibility +
364 ", mRingtone='" + mRingtone + '\'' +
365 ", mLights=" + mLights +
366 ", mVibration=" + mVibration +
367 '}';
368 }
369
370 @Override
371 public int hashCode() {
372 int result = mId.hashCode();
373 result = 31 * result + (mName != null ? mName.hashCode() : 0);
374 result = 31 * result + mImportance;
375 result = 31 * result + (mBypassDnd ? 1 : 0);
376 result = 31 * result + mLockscreenVisibility;
377 result = 31 * result + (mRingtone != null ? mRingtone.hashCode() : 0);
378 result = 31 * result + (mLights ? 1 : 0);
379 result = 31 * result + (mVibration ? 1 : 0);
380 return result;
381 }
382}