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