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