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