NotificationChannel.java revision 0f17000fb3b417fbc6129b47385c5f3c3dfd2de5
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 */
16package android.app;
17
18import android.annotation.SystemApi;
19import android.app.NotificationManager.Importance;
20import android.content.Intent;
21import android.media.AudioAttributes;
22import android.net.Uri;
23import android.os.Parcel;
24import android.os.Parcelable;
25import android.provider.Settings;
26import android.service.notification.NotificationListenerService;
27import android.text.TextUtils;
28
29import org.json.JSONException;
30import org.json.JSONObject;
31import org.xmlpull.v1.XmlPullParser;
32import org.xmlpull.v1.XmlSerializer;
33
34import java.io.IOException;
35import java.util.Arrays;
36
37/**
38 * A representation of settings that apply to a collection of similarly themed notifications.
39 */
40public final class NotificationChannel implements Parcelable {
41
42    /**
43     * The id of the default channel for an app. This id is reserved by the system. All
44     * notifications posted from apps targeting {@link android.os.Build.VERSION_CODES#N_MR1} or
45     * earlier without a notification channel specified are posted to this channel.
46     */
47    public static final String DEFAULT_CHANNEL_ID = "miscellaneous";
48
49    /**
50     * The maximum length for text fields in a NotificationChannel. Fields will be truncated at this
51     * limit.
52     */
53    private static final int MAX_TEXT_LENGTH = 1000;
54
55    private static final String TAG_CHANNEL = "channel";
56    private static final String ATT_NAME = "name";
57    private static final String ATT_DESC = "desc";
58    private static final String ATT_ID = "id";
59    private static final String ATT_DELETED = "deleted";
60    private static final String ATT_PRIORITY = "priority";
61    private static final String ATT_VISIBILITY = "visibility";
62    private static final String ATT_IMPORTANCE = "importance";
63    private static final String ATT_LIGHTS = "lights";
64    private static final String ATT_LIGHT_COLOR = "light_color";
65    private static final String ATT_VIBRATION = "vibration";
66    private static final String ATT_VIBRATION_ENABLED = "vibration_enabled";
67    private static final String ATT_SOUND = "sound";
68    private static final String ATT_USAGE = "usage";
69    private static final String ATT_FLAGS = "flags";
70    private static final String ATT_CONTENT_TYPE = "content_type";
71    private static final String ATT_SHOW_BADGE = "show_badge";
72    private static final String ATT_USER_LOCKED = "locked";
73    private static final String ATT_GROUP = "group";
74    private static final String ATT_BLOCKABLE_SYSTEM = "blockable_system";
75    private static final String DELIMITER = ",";
76
77    /**
78     * @hide
79     */
80    public static final int USER_LOCKED_PRIORITY = 0x00000001;
81    /**
82     * @hide
83     */
84    public static final int USER_LOCKED_VISIBILITY = 0x00000002;
85    /**
86     * @hide
87     */
88    public static final int USER_LOCKED_IMPORTANCE = 0x00000004;
89    /**
90     * @hide
91     */
92    public static final int USER_LOCKED_LIGHTS = 0x00000008;
93    /**
94     * @hide
95     */
96    public static final int USER_LOCKED_VIBRATION = 0x00000010;
97    /**
98     * @hide
99     */
100    public static final int USER_LOCKED_SOUND = 0x00000020;
101
102    /**
103     * @hide
104     */
105    public static final int USER_LOCKED_SHOW_BADGE = 0x00000080;
106
107    /**
108     * @hide
109     */
110    public static final int[] LOCKABLE_FIELDS = new int[] {
111            USER_LOCKED_PRIORITY,
112            USER_LOCKED_VISIBILITY,
113            USER_LOCKED_IMPORTANCE,
114            USER_LOCKED_LIGHTS,
115            USER_LOCKED_VIBRATION,
116            USER_LOCKED_SOUND,
117            USER_LOCKED_SHOW_BADGE,
118    };
119
120    private static final int DEFAULT_LIGHT_COLOR = 0;
121    private static final int DEFAULT_VISIBILITY =
122            NotificationManager.VISIBILITY_NO_OVERRIDE;
123    private static final int DEFAULT_IMPORTANCE =
124            NotificationManager.IMPORTANCE_UNSPECIFIED;
125    private static final boolean DEFAULT_DELETED = false;
126    private static final boolean DEFAULT_SHOW_BADGE = true;
127
128    private final String mId;
129    private String mName;
130    private String mDesc;
131    private int mImportance = DEFAULT_IMPORTANCE;
132    private boolean mBypassDnd;
133    private int mLockscreenVisibility = DEFAULT_VISIBILITY;
134    private Uri mSound = Settings.System.DEFAULT_NOTIFICATION_URI;
135    private boolean mLights;
136    private int mLightColor = DEFAULT_LIGHT_COLOR;
137    private long[] mVibration;
138    private int mUserLockedFields;
139    private boolean mVibrationEnabled;
140    private boolean mShowBadge = DEFAULT_SHOW_BADGE;
141    private boolean mDeleted = DEFAULT_DELETED;
142    private String mGroup;
143    private AudioAttributes mAudioAttributes = Notification.AUDIO_ATTRIBUTES_DEFAULT;
144    private boolean mBlockableSystem = false;
145
146    /**
147     * Creates a notification channel.
148     *
149     * @param id The id of the channel. Must be unique per package. The value may be truncated if
150     *           it is too long.
151     * @param name The user visible name of the channel. You can rename this channel when the system
152     *             locale changes by listening for the {@link Intent#ACTION_LOCALE_CHANGED}
153     *             broadcast. The recommended maximum length is 40 characters; the value may be
154     *             truncated if it is too long.
155     * @param importance The importance of the channel. This controls how interruptive notifications
156     *                   posted to this channel are.
157     */
158    public NotificationChannel(String id, CharSequence name, @Importance int importance) {
159        this.mId = getTrimmedString(id);
160        this.mName = name != null ? getTrimmedString(name.toString()) : null;
161        this.mImportance = importance;
162    }
163
164    /**
165     * @hide
166     */
167    protected NotificationChannel(Parcel in) {
168        if (in.readByte() != 0) {
169            mId = in.readString();
170        } else {
171            mId = null;
172        }
173        if (in.readByte() != 0) {
174            mName = in.readString();
175        } else {
176            mName = null;
177        }
178        if (in.readByte() != 0) {
179            mDesc = in.readString();
180        } else {
181            mDesc = null;
182        }
183        mImportance = in.readInt();
184        mBypassDnd = in.readByte() != 0;
185        mLockscreenVisibility = in.readInt();
186        if (in.readByte() != 0) {
187            mSound = Uri.CREATOR.createFromParcel(in);
188        } else {
189            mSound = null;
190        }
191        mLights = in.readByte() != 0;
192        mVibration = in.createLongArray();
193        mUserLockedFields = in.readInt();
194        mVibrationEnabled = in.readByte() != 0;
195        mShowBadge = in.readByte() != 0;
196        mDeleted = in.readByte() != 0;
197        if (in.readByte() != 0) {
198            mGroup = in.readString();
199        } else {
200            mGroup = null;
201        }
202        mAudioAttributes = in.readInt() > 0 ? AudioAttributes.CREATOR.createFromParcel(in) : null;
203        mLightColor = in.readInt();
204        mBlockableSystem = in.readBoolean();
205    }
206
207    @Override
208    public void writeToParcel(Parcel dest, int flags) {
209        if (mId != null) {
210            dest.writeByte((byte) 1);
211            dest.writeString(mId);
212        } else {
213            dest.writeByte((byte) 0);
214        }
215        if (mName != null) {
216            dest.writeByte((byte) 1);
217            dest.writeString(mName);
218        } else {
219            dest.writeByte((byte) 0);
220        }
221        if (mDesc != null) {
222            dest.writeByte((byte) 1);
223            dest.writeString(mDesc);
224        } else {
225            dest.writeByte((byte) 0);
226        }
227        dest.writeInt(mImportance);
228        dest.writeByte(mBypassDnd ? (byte) 1 : (byte) 0);
229        dest.writeInt(mLockscreenVisibility);
230        if (mSound != null) {
231            dest.writeByte((byte) 1);
232            mSound.writeToParcel(dest, 0);
233        } else {
234            dest.writeByte((byte) 0);
235        }
236        dest.writeByte(mLights ? (byte) 1 : (byte) 0);
237        dest.writeLongArray(mVibration);
238        dest.writeInt(mUserLockedFields);
239        dest.writeByte(mVibrationEnabled ? (byte) 1 : (byte) 0);
240        dest.writeByte(mShowBadge ? (byte) 1 : (byte) 0);
241        dest.writeByte(mDeleted ? (byte) 1 : (byte) 0);
242        if (mGroup != null) {
243            dest.writeByte((byte) 1);
244            dest.writeString(mGroup);
245        } else {
246            dest.writeByte((byte) 0);
247        }
248        if (mAudioAttributes != null) {
249            dest.writeInt(1);
250            mAudioAttributes.writeToParcel(dest, 0);
251        } else {
252            dest.writeInt(0);
253        }
254        dest.writeInt(mLightColor);
255        dest.writeBoolean(mBlockableSystem);
256    }
257
258    /**
259     * @hide
260     */
261    public void lockFields(int field) {
262        mUserLockedFields |= field;
263    }
264
265    /**
266     * @hide
267     */
268    public void unlockFields(int field) {
269        mUserLockedFields &= ~field;
270    }
271
272    /**
273     * @hide
274     */
275    public void setDeleted(boolean deleted) {
276        mDeleted = deleted;
277    }
278
279    /**
280     * @hide
281     */
282    public void setBlockableSystem(boolean blockableSystem) {
283        mBlockableSystem = blockableSystem;
284    }
285    // Modifiable by apps post channel creation
286
287    /**
288     * Sets the user visible name of this channel.
289     *
290     * <p>The recommended maximum length is 40 characters; the value may be truncated if it is too
291     * long.
292     */
293    public void setName(CharSequence name) {
294        mName = name != null ? getTrimmedString(name.toString()) : null;
295    }
296
297    /**
298     * Sets the user visible description of this channel.
299     *
300     * <p>The recommended maximum length is 300 characters; the value may be truncated if it is too
301     * long.
302     */
303    public void setDescription(String description) {
304        mDesc = getTrimmedString(description);
305    }
306
307    private String getTrimmedString(String input) {
308        if (input != null && input.length() > MAX_TEXT_LENGTH) {
309            return input.substring(0, MAX_TEXT_LENGTH);
310        }
311        return input;
312    }
313
314    // Modifiable by apps on channel creation.
315
316    /**
317     * Sets what group this channel belongs to.
318     *
319     * Group information is only used for presentation, not for behavior.
320     *
321     * Only modifiable before the channel is submitted to
322     * {@link NotificationManager#notify(String, int, Notification)}.
323     *
324     * @param groupId the id of a group created by
325     * {@link NotificationManager#createNotificationChannelGroup(NotificationChannelGroup)}.
326     */
327    public void setGroup(String groupId) {
328        this.mGroup = groupId;
329    }
330
331    /**
332     * Sets whether notifications posted to this channel can appear as application icon badges
333     * in a Launcher.
334     *
335     * @param showBadge true if badges should be allowed to be shown.
336     */
337    public void setShowBadge(boolean showBadge) {
338        this.mShowBadge = showBadge;
339    }
340
341    /**
342     * Sets the sound that should be played for notifications posted to this channel and its
343     * audio attributes. Notification channels with an {@link #getImportance() importance} of at
344     * least {@link NotificationManager#IMPORTANCE_DEFAULT} should have a sound.
345     *
346     * Only modifiable before the channel is submitted to
347     * {@link NotificationManager#notify(String, int, Notification)}.
348     */
349    public void setSound(Uri sound, AudioAttributes audioAttributes) {
350        this.mSound = sound;
351        this.mAudioAttributes = audioAttributes;
352    }
353
354    /**
355     * Sets whether notifications posted to this channel should display notification lights,
356     * on devices that support that feature.
357     *
358     * Only modifiable before the channel is submitted to
359     * {@link NotificationManager#notify(String, int, Notification)}.
360     */
361    public void enableLights(boolean lights) {
362        this.mLights = lights;
363    }
364
365    /**
366     * Sets the notification light color for notifications posted to this channel, if lights are
367     * {@link #enableLights(boolean) enabled} on this channel and the device supports that feature.
368     *
369     * Only modifiable before the channel is submitted to
370     * {@link NotificationManager#notify(String, int, Notification)}.
371     */
372    public void setLightColor(int argb) {
373        this.mLightColor = argb;
374    }
375
376    /**
377     * Sets whether notification posted to this channel should vibrate. The vibration pattern can
378     * be set with {@link #setVibrationPattern(long[])}.
379     *
380     * Only modifiable before the channel is submitted to
381     * {@link NotificationManager#notify(String, int, Notification)}.
382     */
383    public void enableVibration(boolean vibration) {
384        this.mVibrationEnabled = vibration;
385    }
386
387    /**
388     * Sets the vibration pattern for notifications posted to this channel. If the provided
389     * pattern is valid (non-null, non-empty), will {@link #enableVibration(boolean)} enable
390     * vibration} as well. Otherwise, vibration will be disabled.
391     *
392     * Only modifiable before the channel is submitted to
393     * {@link NotificationManager#notify(String, int, Notification)}.
394     */
395    public void setVibrationPattern(long[] vibrationPattern) {
396        this.mVibrationEnabled = vibrationPattern != null && vibrationPattern.length > 0;
397        this.mVibration = vibrationPattern;
398    }
399
400    /**
401     * Sets the level of interruption of this notification channel. Only
402     * modifiable before the channel is submitted to
403     * {@link NotificationManager#notify(String, int, Notification)}.
404     *
405     * @param importance the amount the user should be interrupted by
406     *            notifications from this channel.
407     */
408    public void setImportance(@Importance int importance) {
409        this.mImportance = importance;
410    }
411
412    // Modifiable by a notification ranker.
413
414    /**
415     * Sets whether or not notifications posted to this channel can interrupt the user in
416     * {@link android.app.NotificationManager.Policy#INTERRUPTION_FILTER_PRIORITY} mode.
417     *
418     * Only modifiable by the system and notification ranker.
419     */
420    public void setBypassDnd(boolean bypassDnd) {
421        this.mBypassDnd = bypassDnd;
422    }
423
424    /**
425     * Sets whether notifications posted to this channel appear on the lockscreen or not, and if so,
426     * whether they appear in a redacted form. See e.g. {@link Notification#VISIBILITY_SECRET}.
427     *
428     * Only modifiable by the system and notification ranker.
429     */
430    public void setLockscreenVisibility(int lockscreenVisibility) {
431        this.mLockscreenVisibility = lockscreenVisibility;
432    }
433
434    /**
435     * Returns the id of this channel.
436     */
437    public String getId() {
438        return mId;
439    }
440
441    /**
442     * Returns the user visible name of this channel.
443     */
444    public CharSequence getName() {
445        return mName;
446    }
447
448    /**
449     * Returns the user visible description of this channel.
450     */
451    public String getDescription() {
452        return mDesc;
453    }
454
455    /**
456     * Returns the user specified importance e.g. {@link NotificationManager#IMPORTANCE_LOW} for
457     * notifications posted to this channel.
458     */
459    public int getImportance() {
460        return mImportance;
461    }
462
463    /**
464     * Whether or not notifications posted to this channel can bypass the Do Not Disturb
465     * {@link NotificationManager#INTERRUPTION_FILTER_PRIORITY} mode.
466     */
467    public boolean canBypassDnd() {
468        return mBypassDnd;
469    }
470
471    /**
472     * Returns the notification sound for this channel.
473     */
474    public Uri getSound() {
475        return mSound;
476    }
477
478    /**
479     * Returns the audio attributes for sound played by notifications posted to this channel.
480     */
481    public AudioAttributes getAudioAttributes() {
482        return mAudioAttributes;
483    }
484
485    /**
486     * Returns whether notifications posted to this channel trigger notification lights.
487     */
488    public boolean shouldShowLights() {
489        return mLights;
490    }
491
492    /**
493     * Returns the notification light color for notifications posted to this channel. Irrelevant
494     * unless {@link #shouldShowLights()}.
495     */
496    public int getLightColor() {
497        return mLightColor;
498    }
499
500    /**
501     * Returns whether notifications posted to this channel always vibrate.
502     */
503    public boolean shouldVibrate() {
504        return mVibrationEnabled;
505    }
506
507    /**
508     * Returns the vibration pattern for notifications posted to this channel. Will be ignored if
509     * vibration is not enabled ({@link #shouldVibrate()}.
510     */
511    public long[] getVibrationPattern() {
512        return mVibration;
513    }
514
515    /**
516     * Returns whether or not notifications posted to this channel are shown on the lockscreen in
517     * full or redacted form.
518     */
519    public int getLockscreenVisibility() {
520        return mLockscreenVisibility;
521    }
522
523    /**
524     * Returns whether notifications posted to this channel can appear as badges in a Launcher
525     * application.
526     *
527     * Note that badging may be disabled for other reasons.
528     */
529    public boolean canShowBadge() {
530        return mShowBadge;
531    }
532
533    /**
534     * Returns what group this channel belongs to.
535     *
536     * This is used only for visually grouping channels in the UI.
537     */
538    public String getGroup() {
539        return mGroup;
540    }
541
542    /**
543     * @hide
544     */
545    @SystemApi
546    public boolean isDeleted() {
547        return mDeleted;
548    }
549
550    /**
551     * @hide
552     */
553    @SystemApi
554    public int getUserLockedFields() {
555        return mUserLockedFields;
556    }
557
558    /**
559     * @hide
560     */
561    public boolean isBlockableSystem() {
562        return mBlockableSystem;
563    }
564
565    /**
566     * @hide
567     */
568    @SystemApi
569    public void populateFromXml(XmlPullParser parser) {
570        // Name, id, and importance are set in the constructor.
571        setDescription(parser.getAttributeValue(null, ATT_DESC));
572        setBypassDnd(Notification.PRIORITY_DEFAULT
573                != safeInt(parser, ATT_PRIORITY, Notification.PRIORITY_DEFAULT));
574        setLockscreenVisibility(safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY));
575        setSound(safeUri(parser, ATT_SOUND), safeAudioAttributes(parser));
576        enableLights(safeBool(parser, ATT_LIGHTS, false));
577        setLightColor(safeInt(parser, ATT_LIGHT_COLOR, DEFAULT_LIGHT_COLOR));
578        setVibrationPattern(safeLongArray(parser, ATT_VIBRATION, null));
579        enableVibration(safeBool(parser, ATT_VIBRATION_ENABLED, false));
580        setShowBadge(safeBool(parser, ATT_SHOW_BADGE, false));
581        setDeleted(safeBool(parser, ATT_DELETED, false));
582        setGroup(parser.getAttributeValue(null, ATT_GROUP));
583        lockFields(safeInt(parser, ATT_USER_LOCKED, 0));
584        setBlockableSystem(safeBool(parser, ATT_BLOCKABLE_SYSTEM, false));
585    }
586
587    /**
588     * @hide
589     */
590    @SystemApi
591    public void writeXml(XmlSerializer out) throws IOException {
592        out.startTag(null, TAG_CHANNEL);
593        out.attribute(null, ATT_ID, getId());
594        if (getName() != null) {
595            out.attribute(null, ATT_NAME, getName().toString());
596        }
597        if (getDescription() != null) {
598            out.attribute(null, ATT_DESC, getDescription());
599        }
600        if (getImportance() != DEFAULT_IMPORTANCE) {
601            out.attribute(
602                    null, ATT_IMPORTANCE, Integer.toString(getImportance()));
603        }
604        if (canBypassDnd()) {
605            out.attribute(
606                    null, ATT_PRIORITY, Integer.toString(Notification.PRIORITY_MAX));
607        }
608        if (getLockscreenVisibility() != DEFAULT_VISIBILITY) {
609            out.attribute(null, ATT_VISIBILITY,
610                    Integer.toString(getLockscreenVisibility()));
611        }
612        if (getSound() != null) {
613            out.attribute(null, ATT_SOUND, getSound().toString());
614        }
615        if (getAudioAttributes() != null) {
616            out.attribute(null, ATT_USAGE, Integer.toString(getAudioAttributes().getUsage()));
617            out.attribute(null, ATT_CONTENT_TYPE,
618                    Integer.toString(getAudioAttributes().getContentType()));
619            out.attribute(null, ATT_FLAGS, Integer.toString(getAudioAttributes().getFlags()));
620        }
621        if (shouldShowLights()) {
622            out.attribute(null, ATT_LIGHTS, Boolean.toString(shouldShowLights()));
623        }
624        if (getLightColor() != DEFAULT_LIGHT_COLOR) {
625            out.attribute(null, ATT_LIGHT_COLOR, Integer.toString(getLightColor()));
626        }
627        if (shouldVibrate()) {
628            out.attribute(null, ATT_VIBRATION_ENABLED, Boolean.toString(shouldVibrate()));
629        }
630        if (getVibrationPattern() != null) {
631            out.attribute(null, ATT_VIBRATION, longArrayToString(getVibrationPattern()));
632        }
633        if (getUserLockedFields() != 0) {
634            out.attribute(null, ATT_USER_LOCKED, Integer.toString(getUserLockedFields()));
635        }
636        if (canShowBadge()) {
637            out.attribute(null, ATT_SHOW_BADGE, Boolean.toString(canShowBadge()));
638        }
639        if (isDeleted()) {
640            out.attribute(null, ATT_DELETED, Boolean.toString(isDeleted()));
641        }
642        if (getGroup() != null) {
643            out.attribute(null, ATT_GROUP, getGroup());
644        }
645        if (isBlockableSystem()) {
646            out.attribute(null, ATT_BLOCKABLE_SYSTEM, Boolean.toString(isBlockableSystem()));
647        }
648
649        out.endTag(null, TAG_CHANNEL);
650    }
651
652    /**
653     * @hide
654     */
655    @SystemApi
656    public JSONObject toJson() throws JSONException {
657        JSONObject record = new JSONObject();
658        record.put(ATT_ID, getId());
659        record.put(ATT_NAME, getName());
660        record.put(ATT_DESC, getDescription());
661        if (getImportance() != DEFAULT_IMPORTANCE) {
662            record.put(ATT_IMPORTANCE,
663                    NotificationListenerService.Ranking.importanceToString(getImportance()));
664        }
665        if (canBypassDnd()) {
666            record.put(ATT_PRIORITY, Notification.PRIORITY_MAX);
667        }
668        if (getLockscreenVisibility() != DEFAULT_VISIBILITY) {
669            record.put(ATT_VISIBILITY, Notification.visibilityToString(getLockscreenVisibility()));
670        }
671        if (getSound() != null) {
672            record.put(ATT_SOUND, getSound().toString());
673        }
674        if (getAudioAttributes() != null) {
675            record.put(ATT_USAGE, Integer.toString(getAudioAttributes().getUsage()));
676            record.put(ATT_CONTENT_TYPE,
677                    Integer.toString(getAudioAttributes().getContentType()));
678            record.put(ATT_FLAGS, Integer.toString(getAudioAttributes().getFlags()));
679        }
680        record.put(ATT_LIGHTS, Boolean.toString(shouldShowLights()));
681        record.put(ATT_LIGHT_COLOR, Integer.toString(getLightColor()));
682        record.put(ATT_VIBRATION_ENABLED, Boolean.toString(shouldVibrate()));
683        record.put(ATT_USER_LOCKED, Integer.toString(getUserLockedFields()));
684        record.put(ATT_VIBRATION, longArrayToString(getVibrationPattern()));
685        record.put(ATT_SHOW_BADGE, Boolean.toString(canShowBadge()));
686        record.put(ATT_DELETED, Boolean.toString(isDeleted()));
687        record.put(ATT_GROUP, getGroup());
688        record.put(ATT_BLOCKABLE_SYSTEM, isBlockableSystem());
689        return record;
690    }
691
692    private static AudioAttributes safeAudioAttributes(XmlPullParser parser) {
693        int usage = safeInt(parser, ATT_USAGE, AudioAttributes.USAGE_NOTIFICATION);
694        int contentType = safeInt(parser, ATT_CONTENT_TYPE,
695                AudioAttributes.CONTENT_TYPE_SONIFICATION);
696        int flags = safeInt(parser, ATT_FLAGS, 0);
697        return new AudioAttributes.Builder()
698                .setUsage(usage)
699                .setContentType(contentType)
700                .setFlags(flags)
701                .build();
702    }
703
704    private static Uri safeUri(XmlPullParser parser, String att) {
705        final String val = parser.getAttributeValue(null, att);
706        return val == null ? null : Uri.parse(val);
707    }
708
709    private static int safeInt(XmlPullParser parser, String att, int defValue) {
710        final String val = parser.getAttributeValue(null, att);
711        return tryParseInt(val, defValue);
712    }
713
714    private static int tryParseInt(String value, int defValue) {
715        if (TextUtils.isEmpty(value)) return defValue;
716        try {
717            return Integer.parseInt(value);
718        } catch (NumberFormatException e) {
719            return defValue;
720        }
721    }
722
723    private static boolean safeBool(XmlPullParser parser, String att, boolean defValue) {
724        final String value = parser.getAttributeValue(null, att);
725        if (TextUtils.isEmpty(value)) return defValue;
726        return Boolean.parseBoolean(value);
727    }
728
729    private static long[] safeLongArray(XmlPullParser parser, String att, long[] defValue) {
730        final String attributeValue = parser.getAttributeValue(null, att);
731        if (TextUtils.isEmpty(attributeValue)) return defValue;
732        String[] values = attributeValue.split(DELIMITER);
733        long[] longValues = new long[values.length];
734        for (int i = 0; i < values.length; i++) {
735            try {
736                longValues[i] = Long.parseLong(values[i]);
737            } catch (NumberFormatException e) {
738                longValues[i] = 0;
739            }
740        }
741        return longValues;
742    }
743
744    private static String longArrayToString(long[] values) {
745        StringBuffer sb = new StringBuffer();
746        if (values != null && values.length > 0) {
747            for (int i = 0; i < values.length - 1; i++) {
748                sb.append(values[i]).append(DELIMITER);
749            }
750            sb.append(values[values.length - 1]);
751        }
752        return sb.toString();
753    }
754
755    public static final Creator<NotificationChannel> CREATOR = new Creator<NotificationChannel>() {
756        @Override
757        public NotificationChannel createFromParcel(Parcel in) {
758            return new NotificationChannel(in);
759        }
760
761        @Override
762        public NotificationChannel[] newArray(int size) {
763            return new NotificationChannel[size];
764        }
765    };
766
767    @Override
768    public int describeContents() {
769        return 0;
770    }
771
772    @Override
773    public boolean equals(Object o) {
774        if (this == o) return true;
775        if (o == null || getClass() != o.getClass()) return false;
776
777        NotificationChannel that = (NotificationChannel) o;
778
779        if (getImportance() != that.getImportance()) return false;
780        if (mBypassDnd != that.mBypassDnd) return false;
781        if (getLockscreenVisibility() != that.getLockscreenVisibility()) return false;
782        if (mLights != that.mLights) return false;
783        if (getLightColor() != that.getLightColor()) return false;
784        if (getUserLockedFields() != that.getUserLockedFields()) return false;
785        if (mVibrationEnabled != that.mVibrationEnabled) return false;
786        if (mShowBadge != that.mShowBadge) return false;
787        if (isDeleted() != that.isDeleted()) return false;
788        if (isBlockableSystem() != that.isBlockableSystem()) return false;
789        if (getId() != null ? !getId().equals(that.getId()) : that.getId() != null) return false;
790        if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) {
791            return false;
792        }
793        if (getDescription() != null ? !getDescription().equals(that.getDescription())
794                : that.getDescription() != null) {
795            return false;
796        }
797        if (getSound() != null ? !getSound().equals(that.getSound()) : that.getSound() != null) {
798            return false;
799        }
800        if (!Arrays.equals(mVibration, that.mVibration)) return false;
801        if (getGroup() != null ? !getGroup().equals(that.getGroup()) : that.getGroup() != null) {
802            return false;
803        }
804        return getAudioAttributes() != null ? getAudioAttributes().equals(that.getAudioAttributes())
805                : that.getAudioAttributes() == null;
806
807    }
808
809    @Override
810    public int hashCode() {
811        int result = getId() != null ? getId().hashCode() : 0;
812        result = 31 * result + (getName() != null ? getName().hashCode() : 0);
813        result = 31 * result + (getDescription() != null ? getDescription().hashCode() : 0);
814        result = 31 * result + getImportance();
815        result = 31 * result + (mBypassDnd ? 1 : 0);
816        result = 31 * result + getLockscreenVisibility();
817        result = 31 * result + (getSound() != null ? getSound().hashCode() : 0);
818        result = 31 * result + (mLights ? 1 : 0);
819        result = 31 * result + getLightColor();
820        result = 31 * result + Arrays.hashCode(mVibration);
821        result = 31 * result + getUserLockedFields();
822        result = 31 * result + (mVibrationEnabled ? 1 : 0);
823        result = 31 * result + (mShowBadge ? 1 : 0);
824        result = 31 * result + (isDeleted() ? 1 : 0);
825        result = 31 * result + (getGroup() != null ? getGroup().hashCode() : 0);
826        result = 31 * result + (getAudioAttributes() != null ? getAudioAttributes().hashCode() : 0);
827        result = 31 * result + (isBlockableSystem() ? 1 : 0);
828        return result;
829    }
830
831    @Override
832    public String toString() {
833        return "NotificationChannel{" +
834                "mId='" + mId + '\'' +
835                ", mName=" + mName +
836                ", mDescription=" + (!TextUtils.isEmpty(mDesc) ? "hasDescription " : "") +
837                ", mImportance=" + mImportance +
838                ", mBypassDnd=" + mBypassDnd +
839                ", mLockscreenVisibility=" + mLockscreenVisibility +
840                ", mSound=" + mSound +
841                ", mLights=" + mLights +
842                ", mLightColor=" + mLightColor +
843                ", mVibration=" + Arrays.toString(mVibration) +
844                ", mUserLockedFields=" + mUserLockedFields +
845                ", mVibrationEnabled=" + mVibrationEnabled +
846                ", mShowBadge=" + mShowBadge +
847                ", mDeleted=" + mDeleted +
848                ", mGroup='" + mGroup + '\'' +
849                ", mAudioAttributes=" + mAudioAttributes +
850                ", mBlockableSystem=" + mBlockableSystem +
851                '}';
852    }
853}
854