blob: 96949985cb847bdbfc5a4d5fd1c979c6d025b3d7 [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;
Beverlyb0989652019-03-04 11:37:52 -050020import android.annotation.NonNull;
Beverly174d7412018-08-22 16:34:41 -040021import android.app.Notification;
22import android.app.NotificationChannel;
23import android.os.Parcel;
24import android.os.Parcelable;
Beverlyac3159f2018-09-13 14:52:17 -040025import android.util.proto.ProtoOutputStream;
Beverly174d7412018-08-22 16:34:41 -040026
27import java.lang.annotation.Retention;
28import java.lang.annotation.RetentionPolicy;
29import java.util.ArrayList;
30import java.util.Collections;
31import 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 */
39public 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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
326 public @State int getVisualEffectNotificationList() {
327 return mVisualEffects.get(VISUAL_EFFECT_NOTIFICATION_LIST);
328 }
329
330 /**
Beverly12196702018-12-12 15:05:51 -0500331 * Whether this policy hides all visual effects
332 * @hide
333 */
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 */
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 /**
Beverly174d7412018-08-22 16:34:41 -0400357 * 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 */
Beverly4c9a4cd2019-03-06 09:50:22 -0500361 public static final class Builder {
Beverly174d7412018-08-22 16:34:41 -0400362 private ZenPolicy mZenPolicy;
363
364 public Builder() {
365 mZenPolicy = new ZenPolicy();
366 }
367
368 /**
Beverly12196702018-12-12 15:05:51 -0500369 * @hide
370 */
371 public Builder(ZenPolicy policy) {
372 if (policy != null) {
373 mZenPolicy = policy.copy();
374 } else {
375 mZenPolicy = new ZenPolicy();
376 }
377 }
378
379 /**
Beverly174d7412018-08-22 16:34:41 -0400380 * Builds the current ZenPolicy.
381 */
Beverlyb0989652019-03-04 11:37:52 -0500382 public @NonNull ZenPolicy build() {
Beverly174d7412018-08-22 16:34:41 -0400383 return mZenPolicy.copy();
384 }
385
386 /**
387 * Allows all notifications to bypass DND and unmutes all streams.
388 */
Beverlyb0989652019-03-04 11:37:52 -0500389 public @NonNull Builder allowAllSounds() {
Beverly174d7412018-08-22 16:34:41 -0400390 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 */
Beverlyb0989652019-03-04 11:37:52 -0500405 public @NonNull Builder disallowAllSounds() {
Beverly174d7412018-08-22 16:34:41 -0400406 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 */
Beverlyb0989652019-03-04 11:37:52 -0500417 public @NonNull Builder showAllVisualEffects() {
Beverly174d7412018-08-22 16:34:41 -0400418 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 */
Beverlyb0989652019-03-04 11:37:52 -0500427 public @NonNull Builder hideAllVisualEffects() {
Beverly174d7412018-08-22 16:34:41 -0400428 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 */
Beverlyb0989652019-03-04 11:37:52 -0500439 public @NonNull Builder unsetPriorityCategory(@PriorityCategory int category) {
Beverly174d7412018-08-22 16:34:41 -0400440 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 */
Beverlyb0989652019-03-04 11:37:52 -0500456 public @NonNull Builder unsetVisualEffect(@VisualEffect int effect) {
Beverly174d7412018-08-22 16:34:41 -0400457 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 */
Beverlyb0989652019-03-04 11:37:52 -0500465 public @NonNull Builder allowReminders(boolean allow) {
Beverly174d7412018-08-22 16:34:41 -0400466 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 */
Beverlyb0989652019-03-04 11:37:52 -0500475 public @NonNull Builder allowEvents(boolean allow) {
Beverly174d7412018-08-22 16:34:41 -0400476 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 */
Beverlyb0989652019-03-04 11:37:52 -0500487 public @NonNull Builder allowMessages(@PeopleType int audienceType) {
Beverly174d7412018-08-22 16:34:41 -0400488 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 */
Beverlyb0989652019-03-04 11:37:52 -0500511 public @NonNull Builder allowCalls(@PeopleType int audienceType) {
Beverly174d7412018-08-22 16:34:41 -0400512 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 */
Beverlyb0989652019-03-04 11:37:52 -0500534 public @NonNull Builder allowRepeatCallers(boolean allow) {
Beverly174d7412018-08-22 16:34:41 -0400535 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 */
Beverlyb0989652019-03-04 11:37:52 -0500546 public @NonNull Builder allowAlarms(boolean allow) {
Beverly174d7412018-08-22 16:34:41 -0400547 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 */
Beverlyb0989652019-03-04 11:37:52 -0500557 public @NonNull Builder allowMedia(boolean allow) {
Beverly174d7412018-08-22 16:34:41 -0400558 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 */
Beverlyb0989652019-03-04 11:37:52 -0500567 public @NonNull Builder allowSystem(boolean allow) {
Beverly174d7412018-08-22 16:34:41 -0400568 mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_SYSTEM,
569 allow ? STATE_ALLOW : STATE_DISALLOW);
570 return this;
571 }
572
573 /**
Beverly12196702018-12-12 15:05:51 -0500574 * Whether to allow {@link PriorityCategory} sounds to play when DND is active.
575 * @hide
576 */
Beverlyb0989652019-03-04 11:37:52 -0500577 public @NonNull Builder allowCategory(@PriorityCategory int category, boolean allow) {
Beverly12196702018-12-12 15:05:51 -0500578 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 /**
Beverly174d7412018-08-22 16:34:41 -0400602 * Whether {@link Notification#fullScreenIntent full screen intents} that are intercepted
603 * by DND are shown.
604 */
Beverlyb0989652019-03-04 11:37:52 -0500605 public @NonNull Builder showFullScreenIntent(boolean show) {
Beverly174d7412018-08-22 16:34:41 -0400606 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 */
Beverlyb0989652019-03-04 11:37:52 -0500615 public @NonNull Builder showLights(boolean show) {
Beverly174d7412018-08-22 16:34:41 -0400616 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 */
Beverlyb0989652019-03-04 11:37:52 -0500624 public @NonNull Builder showPeeking(boolean show) {
Beverly174d7412018-08-22 16:34:41 -0400625 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 */
Beverlyb0989652019-03-04 11:37:52 -0500634 public @NonNull Builder showStatusBarIcons(boolean show) {
Beverly174d7412018-08-22 16:34:41 -0400635 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 */
Beverlyb0989652019-03-04 11:37:52 -0500644 public @NonNull Builder showBadges(boolean show) {
Beverly174d7412018-08-22 16:34:41 -0400645 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 */
Beverlyb0989652019-03-04 11:37:52 -0500654 public @NonNull Builder showInAmbientDisplay(boolean show) {
Beverly174d7412018-08-22 16:34:41 -0400655 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 */
Beverlyb0989652019-03-04 11:37:52 -0500665 public @NonNull Builder showInNotificationList(boolean show) {
Beverly174d7412018-08-22 16:34:41 -0400666 mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_NOTIFICATION_LIST,
667 show ? STATE_ALLOW : STATE_DISALLOW);
668 return this;
669 }
Beverly12196702018-12-12 15:05:51 -0500670
671 /**
672 * Whether notifications intercepted by DND are prevented from appearing for
673 * {@link VisualEffect}
674 * @hide
675 */
Beverlyb0989652019-03-04 11:37:52 -0500676 public @NonNull Builder showVisualEffect(@VisualEffect int effect, boolean show) {
Beverly12196702018-12-12 15:05:51 -0500677 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 }
Beverly174d7412018-08-22 16:34:41 -0400702 }
703
704 @Override
705 public int describeContents() {
706 return 0;
707 }
708
709 @Override
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
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700717 public static final @android.annotation.NonNull Parcelable.Creator<ZenPolicy> CREATOR =
Beverly174d7412018-08-22 16:34:41 -0400718 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
736 public String toString() {
737 return new StringBuilder(ZenPolicy.class.getSimpleName())
738 .append('{')
739 .append("priorityCategories=[").append(priorityCategoriesToString())
740 .append("], visualEffects=[").append(visualEffectsToString())
Beverly12196702018-12-12 15:05:51 -0500741 .append("], priorityCalls=").append(peopleTypeToString(mPriorityCalls))
742 .append(", priorityMessages=").append(peopleTypeToString(mPriorityMessages))
Beverly174d7412018-08-22 16:34:41 -0400743 .append('}')
744 .toString();
745 }
746
747
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
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
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
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
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 }
Beverly12196702018-12-12 15:05:51 -0500827 return "invalidState{" + state + "}";
828 }
829
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 + "}";
Beverly174d7412018-08-22 16:34:41 -0400844 }
845
846 @Override
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
859 public int hashCode() {
860 return Objects.hash(mPriorityCategories, mVisualEffects, mPriorityCalls, mPriorityMessages);
861 }
862
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
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 */
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 */
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 */
934 public void apply(ZenPolicy policyToApply) {
Beverlyff2df9b2018-10-10 16:54:10 -0400935 if (policyToApply == null) {
936 return;
937 }
938
Beverly174d7412018-08-22 16:34:41 -0400939 // 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 /**
Beverlyac3159f2018-09-13 14:52:17 -0400974 * @hide
975 */
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 /**
Beverly174d7412018-08-22 16:34:41 -04001002 * Makes deep copy of this ZenPolicy.
1003 * @hide
1004 */
Beverlyb0989652019-03-04 11:37:52 -05001005 public @NonNull ZenPolicy copy() {
Beverly174d7412018-08-22 16:34:41 -04001006 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}