1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.service.notification;
18 
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.app.Notification;
23 import android.app.NotificationChannel;
24 import android.os.Parcel;
25 import android.os.Parcelable;
26 import android.util.proto.ProtoOutputStream;
27 
28 import java.io.ByteArrayOutputStream;
29 import java.lang.annotation.Retention;
30 import java.lang.annotation.RetentionPolicy;
31 import java.util.ArrayList;
32 import java.util.Collections;
33 import java.util.Objects;
34 
35 /**
36  * ZenPolicy determines whether to allow certain notifications and their corresponding sounds to
37  * play when a device is in Do Not Disturb mode.
38  * ZenPolicy also dictates the visual effects of notifications that are intercepted when
39  * a device is in Do Not Disturb mode.
40  */
41 public final class ZenPolicy implements Parcelable {
42     private ArrayList<Integer> mPriorityCategories;
43     private ArrayList<Integer> mVisualEffects;
44     private @PeopleType int mPriorityMessages = PEOPLE_TYPE_UNSET;
45     private @PeopleType int mPriorityCalls = PEOPLE_TYPE_UNSET;
46     private @ConversationSenders int mConversationSenders = CONVERSATION_SENDERS_UNSET;
47 
48     /** @hide */
49     @IntDef(prefix = { "PRIORITY_CATEGORY_" }, value = {
50             PRIORITY_CATEGORY_REMINDERS,
51             PRIORITY_CATEGORY_EVENTS,
52             PRIORITY_CATEGORY_MESSAGES,
53             PRIORITY_CATEGORY_CALLS,
54             PRIORITY_CATEGORY_REPEAT_CALLERS,
55             PRIORITY_CATEGORY_ALARMS,
56             PRIORITY_CATEGORY_MEDIA,
57             PRIORITY_CATEGORY_SYSTEM,
58             PRIORITY_CATEGORY_CONVERSATIONS,
59     })
60     @Retention(RetentionPolicy.SOURCE)
61     public @interface PriorityCategory {}
62 
63     /** @hide */
64     public static final int PRIORITY_CATEGORY_REMINDERS = 0;
65     /** @hide */
66     public static final int PRIORITY_CATEGORY_EVENTS = 1;
67     /** @hide */
68     public static final int PRIORITY_CATEGORY_MESSAGES = 2;
69     /** @hide */
70     public static final int PRIORITY_CATEGORY_CALLS = 3;
71     /** @hide */
72     public static final int PRIORITY_CATEGORY_REPEAT_CALLERS = 4;
73     /** @hide */
74     public static final int PRIORITY_CATEGORY_ALARMS = 5;
75     /** @hide */
76     public static final int PRIORITY_CATEGORY_MEDIA = 6;
77     /** @hide */
78     public static final int PRIORITY_CATEGORY_SYSTEM = 7;
79     /** @hide */
80     public static final int PRIORITY_CATEGORY_CONVERSATIONS = 8;
81 
82     /**
83      * Total number of priority categories. Keep updated with any updates to PriorityCategory enum.
84      * @hide
85      */
86     public static final int NUM_PRIORITY_CATEGORIES = 9;
87 
88     /** @hide */
89     @IntDef(prefix = { "VISUAL_EFFECT_" }, value = {
90             VISUAL_EFFECT_FULL_SCREEN_INTENT,
91             VISUAL_EFFECT_LIGHTS,
92             VISUAL_EFFECT_PEEK,
93             VISUAL_EFFECT_STATUS_BAR,
94             VISUAL_EFFECT_BADGE,
95             VISUAL_EFFECT_AMBIENT,
96             VISUAL_EFFECT_NOTIFICATION_LIST,
97     })
98     @Retention(RetentionPolicy.SOURCE)
99     public @interface VisualEffect {}
100 
101     /** @hide */
102     public static final int VISUAL_EFFECT_FULL_SCREEN_INTENT = 0;
103     /** @hide */
104     public static final int VISUAL_EFFECT_LIGHTS = 1;
105     /** @hide */
106     public static final int VISUAL_EFFECT_PEEK = 2;
107     /** @hide */
108     public static final int VISUAL_EFFECT_STATUS_BAR = 3;
109     /** @hide */
110     public static final int VISUAL_EFFECT_BADGE = 4;
111     /** @hide */
112     public static final int VISUAL_EFFECT_AMBIENT = 5;
113     /** @hide */
114     public static final int VISUAL_EFFECT_NOTIFICATION_LIST = 6;
115 
116     /**
117      * Total number of visual effects. Keep updated with any updates to VisualEffect enum.
118      * @hide
119      */
120     public static final int NUM_VISUAL_EFFECTS = 7;
121 
122     /** @hide */
123     @IntDef(prefix = { "PEOPLE_TYPE_" }, value = {
124             PEOPLE_TYPE_UNSET,
125             PEOPLE_TYPE_ANYONE,
126             PEOPLE_TYPE_CONTACTS,
127             PEOPLE_TYPE_STARRED,
128             PEOPLE_TYPE_NONE,
129     })
130     @Retention(RetentionPolicy.SOURCE)
131     public @interface PeopleType {}
132 
133     /**
134      * Used to indicate no preference for the type of people that can bypass dnd for either
135      * calls or messages.
136      */
137     public static final int PEOPLE_TYPE_UNSET = 0;
138 
139     /**
140      * Used to indicate all calls or messages can bypass dnd.
141      */
142     public static final int PEOPLE_TYPE_ANYONE = 1;
143 
144     /**
145      * Used to indicate calls or messages from contacts can bypass dnd.
146      */
147     public static final int PEOPLE_TYPE_CONTACTS = 2;
148 
149     /**
150      * Used to indicate calls or messages from starred contacts can bypass dnd.
151      */
152     public static final int PEOPLE_TYPE_STARRED = 3;
153 
154     /**
155      * Used to indicate no calls or messages can bypass dnd.
156      */
157     public static final int PEOPLE_TYPE_NONE = 4;
158 
159 
160     /** @hide */
161     @IntDef(prefix = { "CONVERSATION_SENDERS_" }, value = {
162             CONVERSATION_SENDERS_UNSET,
163             CONVERSATION_SENDERS_ANYONE,
164             CONVERSATION_SENDERS_IMPORTANT,
165             CONVERSATION_SENDERS_NONE,
166     })
167     @Retention(RetentionPolicy.SOURCE)
168     public @interface ConversationSenders {}
169 
170     /**
171      * Used to indicate no preference for the type of conversations that can bypass dnd.
172      */
173     public static final int CONVERSATION_SENDERS_UNSET = 0;
174 
175     /**
176      * Used to indicate all conversations can bypass dnd.
177      */
178     public static final int CONVERSATION_SENDERS_ANYONE = 1;
179 
180     /**
181      * Used to indicate important conversations can bypass dnd.
182      */
183     public static final int CONVERSATION_SENDERS_IMPORTANT = 2;
184 
185     /**
186      * Used to indicate no conversations can bypass dnd.
187      */
188     public static final int CONVERSATION_SENDERS_NONE = 3;
189 
190     /** @hide */
191     @IntDef(prefix = { "STATE_" }, value = {
192             STATE_UNSET,
193             STATE_ALLOW,
194             STATE_DISALLOW,
195     })
196     @Retention(RetentionPolicy.SOURCE)
197     public @interface State {}
198 
199     /**
200      * Indicates no preference for whether a type of sound or visual effect is or isn't allowed
201      * to play/show when DND is active.  Will default to the current set policy.
202      */
203     public static final int STATE_UNSET = 0;
204 
205     /**
206      * Indicates a type of sound or visual effect is allowed to play/show when DND is active.
207      */
208     public static final int STATE_ALLOW = 1;
209 
210     /**
211      * Indicates a type of sound or visual effect is not allowed to play/show when DND is active.
212      */
213     public static final int STATE_DISALLOW = 2;
214 
215     /** @hide */
ZenPolicy()216     public ZenPolicy() {
217         mPriorityCategories = new ArrayList<>(Collections.nCopies(NUM_PRIORITY_CATEGORIES, 0));
218         mVisualEffects = new ArrayList<>(Collections.nCopies(NUM_VISUAL_EFFECTS, 0));
219     }
220 
221     /**
222      * Conversation type that can bypass DND.
223      * @return {@link #CONVERSATION_SENDERS_UNSET}, {@link #CONVERSATION_SENDERS_ANYONE},
224      * {@link #CONVERSATION_SENDERS_IMPORTANT}, {@link #CONVERSATION_SENDERS_NONE}.
225      */
getPriorityConversationSenders()226     public @PeopleType int getPriorityConversationSenders() {
227         return mConversationSenders;
228     }
229 
230     /**
231      * Message senders that can bypass DND.
232      * @return {@link #PEOPLE_TYPE_UNSET}, {@link #PEOPLE_TYPE_ANYONE},
233      * {@link #PEOPLE_TYPE_CONTACTS}, {@link #PEOPLE_TYPE_STARRED} or {@link #PEOPLE_TYPE_NONE}
234      */
getPriorityMessageSenders()235     public @PeopleType int getPriorityMessageSenders() {
236         return mPriorityMessages;
237     }
238 
239     /**
240      * Callers that can bypass DND.
241      * @return {@link #PEOPLE_TYPE_UNSET}, {@link #PEOPLE_TYPE_ANYONE},
242      * {@link #PEOPLE_TYPE_CONTACTS}, {@link #PEOPLE_TYPE_STARRED} or {@link #PEOPLE_TYPE_NONE}
243      */
getPriorityCallSenders()244     public @PeopleType int getPriorityCallSenders() {
245         return mPriorityCalls;
246     }
247 
248     /**
249      * Whether this policy wants to allow conversation notifications
250      * (see {@link NotificationChannel#getConversationId()}) to play sounds and visually appear
251      * or to intercept them when DND is active.
252      * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
253      */
getPriorityCategoryConversations()254     public @State int getPriorityCategoryConversations() {
255         return mPriorityCategories.get(PRIORITY_CATEGORY_CONVERSATIONS);
256     }
257 
258     /**
259      * Whether this policy wants to allow notifications with category
260      * {@link Notification#CATEGORY_REMINDER} to play sounds and visually appear
261      * or to intercept them when DND is active.
262      * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
263      */
getPriorityCategoryReminders()264     public @State int getPriorityCategoryReminders() {
265         return mPriorityCategories.get(PRIORITY_CATEGORY_REMINDERS);
266     }
267 
268     /**
269      * Whether this policy wants to allow notifications with category
270      * {@link Notification#CATEGORY_EVENT} to play sounds and visually appear
271      * or to intercept them when DND is active.
272      * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
273      */
getPriorityCategoryEvents()274     public @State int getPriorityCategoryEvents() {
275         return mPriorityCategories.get(PRIORITY_CATEGORY_EVENTS);
276     }
277 
278     /**
279      * Whether this policy wants to allow notifications with category
280      * {@link Notification#CATEGORY_MESSAGE} to play sounds and visually appear
281      * or to intercept them when DND is active.  Types of message senders that are allowed
282      * are specified by {@link #getPriorityMessageSenders}.
283      * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
284      */
getPriorityCategoryMessages()285     public @State int getPriorityCategoryMessages() {
286         return mPriorityCategories.get(PRIORITY_CATEGORY_MESSAGES);
287     }
288 
289     /**
290      * Whether this policy wants to allow notifications with category
291      * {@link Notification#CATEGORY_CALL} to play sounds and visually appear
292      * or to intercept them when DND is active.  Types of callers that are allowed
293      * are specified by {@link #getPriorityCallSenders()}.
294      * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
295      */
getPriorityCategoryCalls()296     public @State int getPriorityCategoryCalls() {
297         return mPriorityCategories.get(PRIORITY_CATEGORY_CALLS);
298     }
299 
300     /**
301      * Whether this policy wants to allow repeat callers (notifications with category
302      * {@link Notification#CATEGORY_CALL} that have recently called) to play sounds and
303      * visually appear or to intercept them when DND is active.
304      * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
305      */
getPriorityCategoryRepeatCallers()306     public @State int getPriorityCategoryRepeatCallers() {
307         return mPriorityCategories.get(PRIORITY_CATEGORY_REPEAT_CALLERS);
308     }
309 
310     /**
311      * Whether this policy wants to allow notifications with category
312      * {@link Notification#CATEGORY_ALARM} to play sounds and visually appear
313      * or to intercept them when DND is active.
314      * When alarms are {@link #STATE_DISALLOW disallowed}, the alarm stream will be muted when DND
315      * is active.
316      * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
317      */
getPriorityCategoryAlarms()318     public @State int getPriorityCategoryAlarms() {
319         return mPriorityCategories.get(PRIORITY_CATEGORY_ALARMS);
320     }
321 
322     /**
323      * Whether this policy wants to allow media notifications to play sounds and visually appear
324      * or to intercept them when DND is active.
325      * When media is {@link #STATE_DISALLOW disallowed}, the media stream will be muted when DND is
326      * active.
327      * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
328      */
getPriorityCategoryMedia()329     public @State int getPriorityCategoryMedia() {
330         return mPriorityCategories.get(PRIORITY_CATEGORY_MEDIA);
331     }
332 
333     /**
334      * Whether this policy wants to allow system sounds when DND is active.
335      * When system is {@link #STATE_DISALLOW}, the system stream will be muted when DND is active.
336      * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
337      */
getPriorityCategorySystem()338     public @State int getPriorityCategorySystem() {
339         return mPriorityCategories.get(PRIORITY_CATEGORY_SYSTEM);
340     }
341 
342     /**
343      * Whether this policy allows {@link Notification#fullScreenIntent full screen intents} from
344      * notifications intercepted by DND.
345      */
getVisualEffectFullScreenIntent()346     public @State int getVisualEffectFullScreenIntent() {
347         return mVisualEffects.get(VISUAL_EFFECT_FULL_SCREEN_INTENT);
348     }
349 
350     /**
351      * Whether this policy allows {@link NotificationChannel#shouldShowLights() notification
352      * lights} from notifications intercepted by DND.
353      */
getVisualEffectLights()354     public @State int getVisualEffectLights() {
355         return mVisualEffects.get(VISUAL_EFFECT_LIGHTS);
356     }
357 
358     /**
359      * Whether this policy allows peeking from notifications intercepted by DND.
360      */
getVisualEffectPeek()361     public @State int getVisualEffectPeek() {
362         return mVisualEffects.get(VISUAL_EFFECT_PEEK);
363     }
364 
365     /**
366      * Whether this policy allows notifications intercepted by DND from appearing in the status bar
367      * on devices that support status bars.
368      */
getVisualEffectStatusBar()369     public @State int getVisualEffectStatusBar() {
370         return mVisualEffects.get(VISUAL_EFFECT_STATUS_BAR);
371     }
372 
373     /**
374      * Whether this policy allows {@link NotificationChannel#canShowBadge() badges} from
375      * notifications intercepted by DND on devices that support badging.
376      */
getVisualEffectBadge()377     public @State int getVisualEffectBadge() {
378         return mVisualEffects.get(VISUAL_EFFECT_BADGE);
379     }
380 
381     /**
382      * Whether this policy allows notifications intercepted by DND from appearing on ambient
383      * displays on devices that support ambient display.
384      */
getVisualEffectAmbient()385     public @State int getVisualEffectAmbient() {
386         return mVisualEffects.get(VISUAL_EFFECT_AMBIENT);
387     }
388 
389     /**
390      * Whether this policy allows notifications intercepted by DND from appearing in notification
391      * list views like the notification shade or lockscreen on devices that support those
392      * views.
393      */
getVisualEffectNotificationList()394     public @State int getVisualEffectNotificationList() {
395         return mVisualEffects.get(VISUAL_EFFECT_NOTIFICATION_LIST);
396     }
397 
398     /**
399      * Whether this policy hides all visual effects
400      * @hide
401      */
shouldHideAllVisualEffects()402     public boolean shouldHideAllVisualEffects() {
403         for (int i = 0; i < mVisualEffects.size(); i++) {
404             if (mVisualEffects.get(i) != STATE_DISALLOW) {
405                 return false;
406             }
407         }
408         return true;
409     }
410 
411     /**
412      * Whether this policy shows all visual effects
413      * @hide
414      */
shouldShowAllVisualEffects()415     public boolean shouldShowAllVisualEffects() {
416         for (int i = 0; i < mVisualEffects.size(); i++) {
417             if (mVisualEffects.get(i) != STATE_ALLOW) {
418                 return false;
419             }
420         }
421         return true;
422     }
423 
424     /**
425      * Builder class for {@link ZenPolicy} objects.
426      * Provides a convenient way to set the various fields of a {@link ZenPolicy}.  If a field
427      * is not set, it is (@link STATE_UNSET} and will not change the current set policy.
428      */
429     public static final class Builder {
430         private ZenPolicy mZenPolicy;
431 
Builder()432         public Builder() {
433             mZenPolicy = new ZenPolicy();
434         }
435 
436         /**
437          * @hide
438          */
Builder(ZenPolicy policy)439         public Builder(ZenPolicy policy) {
440             if (policy != null) {
441                 mZenPolicy = policy.copy();
442             } else {
443                 mZenPolicy = new ZenPolicy();
444             }
445         }
446 
447         /**
448          * Builds the current ZenPolicy.
449          */
build()450         public @NonNull ZenPolicy build() {
451             return mZenPolicy.copy();
452         }
453 
454         /**
455          * Allows all notifications to bypass DND and unmutes all streams.
456          */
allowAllSounds()457         public @NonNull Builder allowAllSounds() {
458             for (int i = 0; i < mZenPolicy.mPriorityCategories.size(); i++) {
459                 mZenPolicy.mPriorityCategories.set(i, STATE_ALLOW);
460             }
461             mZenPolicy.mPriorityMessages = PEOPLE_TYPE_ANYONE;
462             mZenPolicy.mPriorityCalls = PEOPLE_TYPE_ANYONE;
463             mZenPolicy.mConversationSenders = CONVERSATION_SENDERS_ANYONE;
464             return this;
465         }
466 
467         /**
468          * Intercepts all notifications and prevents them from playing sounds
469          * when DND is active. Also mutes alarm, system and media streams.
470          * Notification channels can still play sounds only if they
471          * {@link NotificationChannel#canBypassDnd can bypass DND}. If no channels can bypass DND,
472          * the ringer stream is also muted.
473          */
disallowAllSounds()474         public @NonNull Builder disallowAllSounds() {
475             for (int i = 0; i < mZenPolicy.mPriorityCategories.size(); i++) {
476                 mZenPolicy.mPriorityCategories.set(i, STATE_DISALLOW);
477             }
478             mZenPolicy.mPriorityMessages = PEOPLE_TYPE_NONE;
479             mZenPolicy.mPriorityCalls = PEOPLE_TYPE_NONE;
480             mZenPolicy.mConversationSenders = CONVERSATION_SENDERS_NONE;
481             return this;
482         }
483 
484         /**
485          * Allows notifications intercepted by DND to show on all surfaces when DND is active.
486          */
showAllVisualEffects()487         public @NonNull Builder showAllVisualEffects() {
488             for (int i = 0; i < mZenPolicy.mVisualEffects.size(); i++) {
489                 mZenPolicy.mVisualEffects.set(i, STATE_ALLOW);
490             }
491             return this;
492         }
493 
494         /**
495          * Disallows notifications intercepted by DND from showing when DND is active.
496          */
hideAllVisualEffects()497         public @NonNull Builder hideAllVisualEffects() {
498             for (int i = 0; i < mZenPolicy.mVisualEffects.size(); i++) {
499                 mZenPolicy.mVisualEffects.set(i, STATE_DISALLOW);
500             }
501             return this;
502         }
503 
504         /**
505          * Unsets a priority category, neither allowing or disallowing. When applying this policy,
506          * unset categories will default to the current applied policy.
507          * @hide
508          */
unsetPriorityCategory(@riorityCategory int category)509         public @NonNull Builder unsetPriorityCategory(@PriorityCategory int category) {
510             mZenPolicy.mPriorityCategories.set(category, STATE_UNSET);
511 
512             if (category == PRIORITY_CATEGORY_MESSAGES) {
513                 mZenPolicy.mPriorityMessages = PEOPLE_TYPE_UNSET;
514             } else if (category == PRIORITY_CATEGORY_CALLS) {
515                 mZenPolicy.mPriorityCalls = PEOPLE_TYPE_UNSET;
516             } else if (category == PRIORITY_CATEGORY_CONVERSATIONS) {
517                 mZenPolicy.mConversationSenders = CONVERSATION_SENDERS_UNSET;
518             }
519 
520             return this;
521         }
522 
523         /**
524          * Unsets a visual effect, neither allowing or disallowing. When applying this policy,
525          * unset effects will default to the current applied policy.
526          * @hide
527          */
unsetVisualEffect(@isualEffect int effect)528         public @NonNull Builder unsetVisualEffect(@VisualEffect int effect) {
529             mZenPolicy.mVisualEffects.set(effect, STATE_UNSET);
530             return this;
531         }
532 
533         /**
534          * Whether to allow notifications with category {@link Notification#CATEGORY_REMINDER}
535          * to play sounds and visually appear or to intercept them when DND is active.
536          */
allowReminders(boolean allow)537         public @NonNull Builder allowReminders(boolean allow) {
538             mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_REMINDERS,
539                     allow ? STATE_ALLOW : STATE_DISALLOW);
540             return this;
541         }
542 
543         /**
544          * Whether to allow notifications with category {@link Notification#CATEGORY_EVENT}
545          * to play sounds and visually appear or to intercept them when DND is active.
546          */
allowEvents(boolean allow)547         public @NonNull Builder allowEvents(boolean allow) {
548             mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_EVENTS,
549                     allow ? STATE_ALLOW : STATE_DISALLOW);
550             return this;
551         }
552 
553         /**
554          * Whether to allow conversation notifications
555          * (see {@link NotificationChannel#setConversationId(String, String)})
556          * that match audienceType to play sounds and visually appear or to intercept
557          * them when DND is active.
558          * @param audienceType callers that are allowed to bypass DND
559          */
allowConversations(@onversationSenders int audienceType)560         public @NonNull  Builder allowConversations(@ConversationSenders int audienceType) {
561             if (audienceType == STATE_UNSET) {
562                 return unsetPriorityCategory(PRIORITY_CATEGORY_CONVERSATIONS);
563             }
564 
565             if (audienceType == CONVERSATION_SENDERS_NONE) {
566                 mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_CONVERSATIONS, STATE_DISALLOW);
567             } else if (audienceType == CONVERSATION_SENDERS_ANYONE
568                     || audienceType == CONVERSATION_SENDERS_IMPORTANT) {
569                 mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_CONVERSATIONS, STATE_ALLOW);
570             } else {
571                 return this;
572             }
573 
574             mZenPolicy.mConversationSenders = audienceType;
575             return this;
576         }
577 
578         /**
579          * Whether to allow notifications with category {@link Notification#CATEGORY_MESSAGE}
580          * that match audienceType to play sounds and visually appear or to intercept
581          * them when DND is active.
582          * @param audienceType message senders that are allowed to bypass DND
583          */
allowMessages(@eopleType int audienceType)584         public @NonNull Builder allowMessages(@PeopleType int audienceType) {
585             if (audienceType == STATE_UNSET) {
586                 return unsetPriorityCategory(PRIORITY_CATEGORY_MESSAGES);
587             }
588 
589             if (audienceType == PEOPLE_TYPE_NONE) {
590                 mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_MESSAGES, STATE_DISALLOW);
591             } else if (audienceType == PEOPLE_TYPE_ANYONE || audienceType == PEOPLE_TYPE_CONTACTS
592                     || audienceType == PEOPLE_TYPE_STARRED) {
593                 mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_MESSAGES, STATE_ALLOW);
594             } else {
595                 return this;
596             }
597 
598             mZenPolicy.mPriorityMessages = audienceType;
599             return this;
600         }
601 
602         /**
603          * Whether to allow notifications with category {@link Notification#CATEGORY_CALL}
604          * that match audienceType to play sounds and visually appear or to intercept
605          * them when DND is active.
606          * @param audienceType callers that are allowed to bypass DND
607          */
allowCalls(@eopleType int audienceType)608         public @NonNull  Builder allowCalls(@PeopleType int audienceType) {
609             if (audienceType == STATE_UNSET) {
610                 return unsetPriorityCategory(PRIORITY_CATEGORY_CALLS);
611             }
612 
613             if (audienceType == PEOPLE_TYPE_NONE) {
614                 mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_CALLS, STATE_DISALLOW);
615             } else if (audienceType == PEOPLE_TYPE_ANYONE || audienceType == PEOPLE_TYPE_CONTACTS
616                     || audienceType == PEOPLE_TYPE_STARRED) {
617                 mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_CALLS, STATE_ALLOW);
618             } else {
619                 return this;
620             }
621 
622             mZenPolicy.mPriorityCalls = audienceType;
623             return this;
624         }
625 
626         /**
627          * Whether to allow repeat callers (notifications with category
628          * {@link Notification#CATEGORY_CALL} that have recently called
629          * to play sounds and visually appear.
630          */
allowRepeatCallers(boolean allow)631         public @NonNull Builder allowRepeatCallers(boolean allow) {
632             mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_REPEAT_CALLERS,
633                     allow ? STATE_ALLOW : STATE_DISALLOW);
634             return this;
635         }
636 
637         /**
638          * Whether to allow notifications with category {@link Notification#CATEGORY_ALARM}
639          * to play sounds and visually appear or to intercept them when DND is active.
640          * Disallowing alarms will mute the alarm stream when DND is active.
641          */
allowAlarms(boolean allow)642         public @NonNull Builder allowAlarms(boolean allow) {
643             mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_ALARMS,
644                     allow ? STATE_ALLOW : STATE_DISALLOW);
645             return this;
646         }
647 
648         /**
649          * Whether to allow media notifications to play sounds and visually
650          * appear or to intercept them when DND is active.
651          * Disallowing media will mute the media stream when DND is active.
652          */
allowMedia(boolean allow)653         public @NonNull Builder allowMedia(boolean allow) {
654             mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_MEDIA,
655                     allow ? STATE_ALLOW : STATE_DISALLOW);
656             return this;
657         }
658 
659         /**
660          * Whether to allow system sounds to play when DND is active.
661          * Disallowing system sounds will mute the system stream when DND is active.
662          */
allowSystem(boolean allow)663         public @NonNull Builder allowSystem(boolean allow) {
664             mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_SYSTEM,
665                     allow ? STATE_ALLOW : STATE_DISALLOW);
666             return this;
667         }
668 
669         /**
670          * Whether to allow {@link PriorityCategory} sounds to play when DND is active.
671          * @hide
672          */
allowCategory(@riorityCategory int category, boolean allow)673         public @NonNull Builder allowCategory(@PriorityCategory int category, boolean allow) {
674             switch (category) {
675                 case PRIORITY_CATEGORY_ALARMS:
676                     allowAlarms(allow);
677                     break;
678                 case PRIORITY_CATEGORY_MEDIA:
679                     allowMedia(allow);
680                     break;
681                 case PRIORITY_CATEGORY_SYSTEM:
682                     allowSystem(allow);
683                     break;
684                 case PRIORITY_CATEGORY_REMINDERS:
685                     allowReminders(allow);
686                     break;
687                 case PRIORITY_CATEGORY_EVENTS:
688                     allowEvents(allow);
689                     break;
690                 case PRIORITY_CATEGORY_REPEAT_CALLERS:
691                     allowRepeatCallers(allow);
692                     break;
693             }
694             return this;
695         }
696 
697         /**
698          * Whether {@link Notification#fullScreenIntent full screen intents} that are intercepted
699          * by DND are shown.
700          */
showFullScreenIntent(boolean show)701         public @NonNull Builder showFullScreenIntent(boolean show) {
702             mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_FULL_SCREEN_INTENT,
703                     show ? STATE_ALLOW : STATE_DISALLOW);
704             return this;
705         }
706 
707         /**
708          * Whether {@link NotificationChannel#shouldShowLights() notification lights} from
709          * notifications intercepted by DND are blocked.
710          */
showLights(boolean show)711         public @NonNull Builder showLights(boolean show) {
712             mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_LIGHTS,
713                     show ? STATE_ALLOW : STATE_DISALLOW);
714             return this;
715         }
716 
717         /**
718          * Whether notifications intercepted by DND are prevented from peeking.
719          */
showPeeking(boolean show)720         public @NonNull Builder showPeeking(boolean show) {
721             mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_PEEK,
722                     show ? STATE_ALLOW : STATE_DISALLOW);
723             return this;
724         }
725 
726         /**
727          * Whether notifications intercepted by DND are prevented from appearing in the status bar
728          * on devices that support status bars.
729          */
showStatusBarIcons(boolean show)730         public @NonNull Builder showStatusBarIcons(boolean show) {
731             mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_STATUS_BAR,
732                     show ? STATE_ALLOW : STATE_DISALLOW);
733             return this;
734         }
735 
736         /**
737          * Whether {@link NotificationChannel#canShowBadge() badges} from
738          * notifications intercepted by DND are allowed on devices that support badging.
739          */
showBadges(boolean show)740         public @NonNull Builder showBadges(boolean show) {
741             mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_BADGE,
742                     show ? STATE_ALLOW : STATE_DISALLOW);
743             return this;
744         }
745 
746         /**
747          * Whether notification intercepted by DND are prevented from appearing on ambient displays
748          * on devices that support ambient display.
749          */
showInAmbientDisplay(boolean show)750         public @NonNull Builder showInAmbientDisplay(boolean show) {
751             mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_AMBIENT,
752                     show ? STATE_ALLOW : STATE_DISALLOW);
753             return this;
754         }
755 
756         /**
757          * Whether notification intercepted by DND are prevented from appearing in notification
758          * list views like the notification shade or lockscreen on devices that support those
759          * views.
760          */
showInNotificationList(boolean show)761         public @NonNull Builder showInNotificationList(boolean show) {
762             mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_NOTIFICATION_LIST,
763                     show ? STATE_ALLOW : STATE_DISALLOW);
764             return this;
765         }
766 
767         /**
768          * Whether notifications intercepted by DND are prevented from appearing for
769          * {@link VisualEffect}
770          * @hide
771          */
showVisualEffect(@isualEffect int effect, boolean show)772         public @NonNull Builder showVisualEffect(@VisualEffect int effect, boolean show) {
773             switch (effect) {
774                 case VISUAL_EFFECT_FULL_SCREEN_INTENT:
775                     showFullScreenIntent(show);
776                     break;
777                 case VISUAL_EFFECT_LIGHTS:
778                     showLights(show);
779                     break;
780                 case VISUAL_EFFECT_PEEK:
781                     showPeeking(show);
782                     break;
783                 case VISUAL_EFFECT_STATUS_BAR:
784                     showStatusBarIcons(show);
785                     break;
786                 case VISUAL_EFFECT_BADGE:
787                     showBadges(show);
788                     break;
789                 case VISUAL_EFFECT_AMBIENT:
790                     showInAmbientDisplay(show);
791                     break;
792                 case VISUAL_EFFECT_NOTIFICATION_LIST:
793                     showInNotificationList(show);
794                     break;
795             }
796             return this;
797         }
798     }
799 
800     @Override
describeContents()801     public int describeContents() {
802         return 0;
803     }
804 
805     @Override
writeToParcel(Parcel dest, int flags)806     public void writeToParcel(Parcel dest, int flags) {
807         dest.writeList(mPriorityCategories);
808         dest.writeList(mVisualEffects);
809         dest.writeInt(mPriorityCalls);
810         dest.writeInt(mPriorityMessages);
811         dest.writeInt(mConversationSenders);
812     }
813 
814     public static final @android.annotation.NonNull Parcelable.Creator<ZenPolicy> CREATOR =
815             new Parcelable.Creator<ZenPolicy>() {
816         @Override
817         public ZenPolicy createFromParcel(Parcel source) {
818             ZenPolicy policy = new ZenPolicy();
819             policy.mPriorityCategories = trimList(
820                     source.readArrayList(Integer.class.getClassLoader(), java.lang.Integer.class),
821                     NUM_PRIORITY_CATEGORIES);
822             policy.mVisualEffects = trimList(
823                     source.readArrayList(Integer.class.getClassLoader(), java.lang.Integer.class),
824                     NUM_VISUAL_EFFECTS);
825             policy.mPriorityCalls = source.readInt();
826             policy.mPriorityMessages = source.readInt();
827             policy.mConversationSenders = source.readInt();
828             return policy;
829         }
830 
831         @Override
832         public ZenPolicy[] newArray(int size) {
833             return new ZenPolicy[size];
834         }
835     };
836 
837     @Override
toString()838     public String toString() {
839         return new StringBuilder(ZenPolicy.class.getSimpleName())
840                 .append('{')
841                 .append("priorityCategories=[").append(priorityCategoriesToString())
842                 .append("], visualEffects=[").append(visualEffectsToString())
843                 .append("], priorityCallsSenders=").append(peopleTypeToString(mPriorityCalls))
844                 .append(", priorityMessagesSenders=").append(peopleTypeToString(mPriorityMessages))
845                 .append(", priorityConversationSenders=").append(
846                         conversationTypeToString(mConversationSenders))
847                 .append('}')
848                 .toString();
849     }
850 
851     // Returns a list containing the first maxLength elements of the input list if the list is
852     // longer than that size. For the lists in ZenPolicy, this should not happen unless the input
853     // is corrupt.
trimList(ArrayList<Integer> list, int maxLength)854     private static ArrayList<Integer> trimList(ArrayList<Integer> list, int maxLength) {
855         if (list == null || list.size() <= maxLength) {
856             return list;
857         }
858         return new ArrayList<>(list.subList(0, maxLength));
859     }
860 
priorityCategoriesToString()861     private String priorityCategoriesToString() {
862         StringBuilder builder = new StringBuilder();
863         for (int i = 0; i < mPriorityCategories.size(); i++) {
864             if (mPriorityCategories.get(i) != STATE_UNSET) {
865                 builder.append(indexToCategory(i))
866                         .append("=")
867                         .append(stateToString(mPriorityCategories.get(i)))
868                         .append(" ");
869             }
870 
871         }
872         return builder.toString();
873     }
874 
visualEffectsToString()875     private String visualEffectsToString() {
876         StringBuilder builder = new StringBuilder();
877         for (int i = 0; i < mVisualEffects.size(); i++) {
878             if (mVisualEffects.get(i) != STATE_UNSET) {
879                 builder.append(indexToVisualEffect(i))
880                         .append("=")
881                         .append(stateToString(mVisualEffects.get(i)))
882                         .append(" ");
883             }
884 
885         }
886         return builder.toString();
887     }
888 
indexToVisualEffect(@isualEffect int visualEffectIndex)889     private String indexToVisualEffect(@VisualEffect int visualEffectIndex) {
890         switch (visualEffectIndex) {
891             case VISUAL_EFFECT_FULL_SCREEN_INTENT:
892                 return "fullScreenIntent";
893             case VISUAL_EFFECT_LIGHTS:
894                 return "lights";
895             case VISUAL_EFFECT_PEEK:
896                 return "peek";
897             case VISUAL_EFFECT_STATUS_BAR:
898                 return "statusBar";
899             case VISUAL_EFFECT_BADGE:
900                 return "badge";
901             case VISUAL_EFFECT_AMBIENT:
902                 return "ambient";
903             case VISUAL_EFFECT_NOTIFICATION_LIST:
904                 return "notificationList";
905         }
906         return null;
907     }
908 
indexToCategory(@riorityCategory int categoryIndex)909     private String indexToCategory(@PriorityCategory int categoryIndex) {
910         switch (categoryIndex) {
911             case PRIORITY_CATEGORY_REMINDERS:
912                 return "reminders";
913             case PRIORITY_CATEGORY_EVENTS:
914                 return "events";
915             case PRIORITY_CATEGORY_MESSAGES:
916                 return "messages";
917             case PRIORITY_CATEGORY_CALLS:
918                 return "calls";
919             case PRIORITY_CATEGORY_REPEAT_CALLERS:
920                 return "repeatCallers";
921             case PRIORITY_CATEGORY_ALARMS:
922                 return "alarms";
923             case PRIORITY_CATEGORY_MEDIA:
924                 return "media";
925             case PRIORITY_CATEGORY_SYSTEM:
926                 return "system";
927             case PRIORITY_CATEGORY_CONVERSATIONS:
928                 return "convs";
929         }
930         return null;
931     }
932 
stateToString(@tate int state)933     private String stateToString(@State int state) {
934         switch (state) {
935             case STATE_UNSET:
936                 return "unset";
937             case STATE_DISALLOW:
938                 return "disallow";
939             case STATE_ALLOW:
940                 return "allow";
941         }
942         return "invalidState{" + state + "}";
943     }
944 
peopleTypeToString(@eopleType int peopleType)945     private String peopleTypeToString(@PeopleType int peopleType) {
946         switch (peopleType) {
947             case PEOPLE_TYPE_ANYONE:
948                 return "anyone";
949             case PEOPLE_TYPE_CONTACTS:
950                 return "contacts";
951             case PEOPLE_TYPE_NONE:
952                 return "none";
953             case PEOPLE_TYPE_STARRED:
954                 return "starred_contacts";
955             case STATE_UNSET:
956                 return "unset";
957         }
958         return "invalidPeopleType{" + peopleType + "}";
959     }
960 
961     /**
962      * @hide
963      */
conversationTypeToString(@onversationSenders int conversationType)964     public static String conversationTypeToString(@ConversationSenders int conversationType) {
965         switch (conversationType) {
966             case CONVERSATION_SENDERS_ANYONE:
967                 return "anyone";
968             case CONVERSATION_SENDERS_IMPORTANT:
969                 return "important";
970             case CONVERSATION_SENDERS_NONE:
971                 return "none";
972             case CONVERSATION_SENDERS_UNSET:
973                 return "unset";
974         }
975         return "invalidConversationType{" + conversationType + "}";
976     }
977 
978     @Override
equals(@ullable Object o)979     public boolean equals(@Nullable Object o) {
980         if (!(o instanceof ZenPolicy)) return false;
981         if (o == this) return true;
982         final ZenPolicy other = (ZenPolicy) o;
983 
984         return Objects.equals(other.mPriorityCategories, mPriorityCategories)
985                 && Objects.equals(other.mVisualEffects, mVisualEffects)
986                 && other.mPriorityCalls == mPriorityCalls
987                 && other.mPriorityMessages == mPriorityMessages
988                 && other.mConversationSenders == mConversationSenders;
989     }
990 
991     @Override
hashCode()992     public int hashCode() {
993         return Objects.hash(mPriorityCategories, mVisualEffects, mPriorityCalls, mPriorityMessages,
994                 mConversationSenders);
995     }
996 
getZenPolicyPriorityCategoryState(@riorityCategory int category)997     private @ZenPolicy.State int getZenPolicyPriorityCategoryState(@PriorityCategory int
998             category) {
999         switch (category) {
1000             case PRIORITY_CATEGORY_REMINDERS:
1001                 return getPriorityCategoryReminders();
1002             case PRIORITY_CATEGORY_EVENTS:
1003                 return getPriorityCategoryEvents();
1004             case PRIORITY_CATEGORY_MESSAGES:
1005                 return getPriorityCategoryMessages();
1006             case PRIORITY_CATEGORY_CALLS:
1007                 return getPriorityCategoryCalls();
1008             case PRIORITY_CATEGORY_REPEAT_CALLERS:
1009                 return getPriorityCategoryRepeatCallers();
1010             case PRIORITY_CATEGORY_ALARMS:
1011                 return getPriorityCategoryAlarms();
1012             case PRIORITY_CATEGORY_MEDIA:
1013                 return getPriorityCategoryMedia();
1014             case PRIORITY_CATEGORY_SYSTEM:
1015                 return getPriorityCategorySystem();
1016             case PRIORITY_CATEGORY_CONVERSATIONS:
1017                 return getPriorityCategoryConversations();
1018         }
1019         return -1;
1020     }
1021 
getZenPolicyVisualEffectState(@isualEffect int effect)1022     private @ZenPolicy.State int getZenPolicyVisualEffectState(@VisualEffect int effect) {
1023         switch (effect) {
1024             case VISUAL_EFFECT_FULL_SCREEN_INTENT:
1025                 return getVisualEffectFullScreenIntent();
1026             case VISUAL_EFFECT_LIGHTS:
1027                 return getVisualEffectLights();
1028             case VISUAL_EFFECT_PEEK:
1029                 return getVisualEffectPeek();
1030             case VISUAL_EFFECT_STATUS_BAR:
1031                 return getVisualEffectStatusBar();
1032             case VISUAL_EFFECT_BADGE:
1033                 return getVisualEffectBadge();
1034             case VISUAL_EFFECT_AMBIENT:
1035                 return getVisualEffectAmbient();
1036             case VISUAL_EFFECT_NOTIFICATION_LIST:
1037                 return getVisualEffectNotificationList();
1038         }
1039         return -1;
1040     }
1041 
1042     /** @hide */
isCategoryAllowed(@riorityCategory int category, boolean defaultVal)1043     public boolean isCategoryAllowed(@PriorityCategory int category, boolean defaultVal) {
1044         switch (getZenPolicyPriorityCategoryState(category)) {
1045             case ZenPolicy.STATE_ALLOW:
1046                 return true;
1047             case ZenPolicy.STATE_DISALLOW:
1048                 return false;
1049             default:
1050                 return defaultVal;
1051         }
1052     }
1053 
1054     /** @hide */
isVisualEffectAllowed(@isualEffect int effect, boolean defaultVal)1055     public boolean isVisualEffectAllowed(@VisualEffect int effect, boolean defaultVal) {
1056         switch (getZenPolicyVisualEffectState(effect)) {
1057             case ZenPolicy.STATE_ALLOW:
1058                 return true;
1059             case ZenPolicy.STATE_DISALLOW:
1060                 return false;
1061             default:
1062                 return defaultVal;
1063         }
1064     }
1065 
1066     /**
1067      * Applies another policy on top of this policy
1068      * @hide
1069      */
apply(ZenPolicy policyToApply)1070     public void apply(ZenPolicy policyToApply) {
1071         if (policyToApply == null) {
1072             return;
1073         }
1074 
1075         // apply priority categories
1076         for (int category = 0; category < mPriorityCategories.size(); category++) {
1077             if (mPriorityCategories.get(category) == STATE_DISALLOW) {
1078                 // if a priority category is already disallowed by the policy, cannot allow
1079                 continue;
1080             }
1081 
1082             @State int newState = policyToApply.mPriorityCategories.get(category);
1083             if (newState != STATE_UNSET) {
1084                 mPriorityCategories.set(category, newState);
1085 
1086                 if (category == PRIORITY_CATEGORY_MESSAGES
1087                         && mPriorityMessages < policyToApply.mPriorityMessages) {
1088                     mPriorityMessages = policyToApply.mPriorityMessages;
1089                 } else if (category == PRIORITY_CATEGORY_CALLS
1090                         && mPriorityCalls < policyToApply.mPriorityCalls) {
1091                     mPriorityCalls = policyToApply.mPriorityCalls;
1092                 } else if (category == PRIORITY_CATEGORY_CONVERSATIONS
1093                         && mConversationSenders < policyToApply.mConversationSenders) {
1094                     mConversationSenders = policyToApply.mConversationSenders;
1095                 }
1096             }
1097         }
1098 
1099         // apply visual effects
1100         for (int visualEffect = 0; visualEffect < mVisualEffects.size(); visualEffect++) {
1101             if (mVisualEffects.get(visualEffect) == STATE_DISALLOW) {
1102                 // if a visual effect is already disallowed by the policy, cannot allow
1103                 continue;
1104             }
1105 
1106             if (policyToApply.mVisualEffects.get(visualEffect) != STATE_UNSET) {
1107                 mVisualEffects.set(visualEffect, policyToApply.mVisualEffects.get(visualEffect));
1108             }
1109         }
1110     }
1111 
1112     /**
1113      * @hide
1114      */
dumpDebug(ProtoOutputStream proto, long fieldId)1115     public void dumpDebug(ProtoOutputStream proto, long fieldId) {
1116         final long token = proto.start(fieldId);
1117 
1118         proto.write(ZenPolicyProto.REMINDERS, getPriorityCategoryReminders());
1119         proto.write(ZenPolicyProto.EVENTS, getPriorityCategoryEvents());
1120         proto.write(ZenPolicyProto.MESSAGES, getPriorityCategoryMessages());
1121         proto.write(ZenPolicyProto.CALLS, getPriorityCategoryCalls());
1122         proto.write(ZenPolicyProto.REPEAT_CALLERS, getPriorityCategoryRepeatCallers());
1123         proto.write(ZenPolicyProto.ALARMS, getPriorityCategoryAlarms());
1124         proto.write(ZenPolicyProto.MEDIA, getPriorityCategoryMedia());
1125         proto.write(ZenPolicyProto.SYSTEM, getPriorityCategorySystem());
1126 
1127         proto.write(ZenPolicyProto.FULL_SCREEN_INTENT, getVisualEffectFullScreenIntent());
1128         proto.write(ZenPolicyProto.LIGHTS, getVisualEffectLights());
1129         proto.write(ZenPolicyProto.PEEK, getVisualEffectPeek());
1130         proto.write(ZenPolicyProto.STATUS_BAR, getVisualEffectStatusBar());
1131         proto.write(ZenPolicyProto.BADGE, getVisualEffectBadge());
1132         proto.write(ZenPolicyProto.AMBIENT, getVisualEffectAmbient());
1133         proto.write(ZenPolicyProto.NOTIFICATION_LIST, getVisualEffectNotificationList());
1134 
1135         proto.write(ZenPolicyProto.PRIORITY_MESSAGES, getPriorityMessageSenders());
1136         proto.write(ZenPolicyProto.PRIORITY_CALLS, getPriorityCallSenders());
1137         proto.end(token);
1138     }
1139 
1140     /**
1141      * Converts a policy to a statsd proto.
1142      * @hides
1143      */
toProto()1144     public byte[] toProto() {
1145         ByteArrayOutputStream bytes = new ByteArrayOutputStream();
1146         ProtoOutputStream proto = new ProtoOutputStream(bytes);
1147 
1148         proto.write(DNDPolicyProto.CALLS, getPriorityCategoryCalls());
1149         proto.write(DNDPolicyProto.REPEAT_CALLERS, getPriorityCategoryRepeatCallers());
1150         proto.write(DNDPolicyProto.MESSAGES, getPriorityCategoryMessages());
1151         proto.write(DNDPolicyProto.CONVERSATIONS, getPriorityCategoryConversations());
1152         proto.write(DNDPolicyProto.REMINDERS, getPriorityCategoryReminders());
1153         proto.write(DNDPolicyProto.EVENTS, getPriorityCategoryEvents());
1154         proto.write(DNDPolicyProto.ALARMS, getPriorityCategoryAlarms());
1155         proto.write(DNDPolicyProto.MEDIA, getPriorityCategoryMedia());
1156         proto.write(DNDPolicyProto.SYSTEM, getPriorityCategorySystem());
1157 
1158         proto.write(DNDPolicyProto.FULLSCREEN, getVisualEffectFullScreenIntent());
1159         proto.write(DNDPolicyProto.LIGHTS, getVisualEffectLights());
1160         proto.write(DNDPolicyProto.PEEK, getVisualEffectPeek());
1161         proto.write(DNDPolicyProto.STATUS_BAR, getVisualEffectStatusBar());
1162         proto.write(DNDPolicyProto.BADGE, getVisualEffectBadge());
1163         proto.write(DNDPolicyProto.AMBIENT, getVisualEffectAmbient());
1164         proto.write(DNDPolicyProto.NOTIFICATION_LIST, getVisualEffectNotificationList());
1165 
1166         proto.write(DNDPolicyProto.ALLOW_CALLS_FROM, getPriorityCallSenders());
1167         proto.write(DNDPolicyProto.ALLOW_MESSAGES_FROM, getPriorityMessageSenders());
1168         proto.write(DNDPolicyProto.ALLOW_CONVERSATIONS_FROM, getPriorityConversationSenders());
1169 
1170         proto.flush();
1171         return bytes.toByteArray();
1172     }
1173 
1174     /**
1175      * Makes deep copy of this ZenPolicy.
1176      * @hide
1177      */
copy()1178     public @NonNull ZenPolicy copy() {
1179         final Parcel parcel = Parcel.obtain();
1180         try {
1181             writeToParcel(parcel, 0);
1182             parcel.setDataPosition(0);
1183             return CREATOR.createFromParcel(parcel);
1184         } finally {
1185             parcel.recycle();
1186         }
1187     }
1188 }
1189