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