1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.service.notification; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.SuppressLint; 23 import android.annotation.TestApi; 24 import android.app.Notification; 25 import android.app.NotificationChannel; 26 import android.os.Parcel; 27 import android.os.Parcelable; 28 import android.util.proto.ProtoOutputStream; 29 30 import androidx.annotation.VisibleForTesting; 31 32 import java.io.ByteArrayOutputStream; 33 import java.lang.annotation.Retention; 34 import java.lang.annotation.RetentionPolicy; 35 import java.util.ArrayList; 36 import java.util.Collections; 37 import java.util.List; 38 import java.util.Objects; 39 40 /** 41 * ZenPolicy determines whether to allow certain notifications and their corresponding sounds to 42 * play when a device is in Do Not Disturb mode. 43 * ZenPolicy also dictates the visual effects of notifications that are intercepted when 44 * a device is in Do Not Disturb mode. 45 */ 46 public final class ZenPolicy implements Parcelable { 47 48 /** 49 * Enum for the user-modifiable fields in this object. 50 * @hide 51 */ 52 @IntDef(flag = true, prefix = { "FIELD_" }, value = { 53 FIELD_MESSAGES, 54 FIELD_CALLS, 55 FIELD_CONVERSATIONS, 56 FIELD_ALLOW_CHANNELS, 57 FIELD_PRIORITY_CATEGORY_REMINDERS, 58 FIELD_PRIORITY_CATEGORY_EVENTS, 59 FIELD_PRIORITY_CATEGORY_REPEAT_CALLERS, 60 FIELD_PRIORITY_CATEGORY_ALARMS, 61 FIELD_PRIORITY_CATEGORY_MEDIA, 62 FIELD_PRIORITY_CATEGORY_SYSTEM, 63 FIELD_VISUAL_EFFECT_FULL_SCREEN_INTENT, 64 FIELD_VISUAL_EFFECT_LIGHTS, 65 FIELD_VISUAL_EFFECT_PEEK, 66 FIELD_VISUAL_EFFECT_STATUS_BAR, 67 FIELD_VISUAL_EFFECT_BADGE, 68 FIELD_VISUAL_EFFECT_AMBIENT, 69 FIELD_VISUAL_EFFECT_NOTIFICATION_LIST, 70 }) 71 @Retention(RetentionPolicy.SOURCE) 72 public @interface ModifiableField {} 73 74 /** 75 * Covers modifications to MESSAGE_SENDERS and PRIORITY_CATEGORY_MESSAGES, which are set at 76 * the same time. 77 * @hide 78 */ 79 public static final int FIELD_MESSAGES = 1 << 0; 80 /** 81 * Covers modifications to CALL_SENDERS and PRIORITY_CATEGORY_CALLS, which are set at 82 * the same time. 83 * @hide 84 */ 85 public static final int FIELD_CALLS = 1 << 1; 86 /** 87 * Covers modifications to CONVERSATION_SENDERS and PRIORITY_CATEGORY_CONVERSATIONS, which are 88 * set at the same time. 89 * @hide 90 */ 91 public static final int FIELD_CONVERSATIONS = 1 << 2; 92 /** 93 * @hide 94 */ 95 public static final int FIELD_ALLOW_CHANNELS = 1 << 3; 96 /** 97 * @hide 98 */ 99 public static final int FIELD_PRIORITY_CATEGORY_REMINDERS = 1 << 4; 100 /** 101 * @hide 102 */ 103 public static final int FIELD_PRIORITY_CATEGORY_EVENTS = 1 << 5; 104 /** 105 * @hide 106 */ 107 public static final int FIELD_PRIORITY_CATEGORY_REPEAT_CALLERS = 1 << 6; 108 /** 109 * @hide 110 */ 111 public static final int FIELD_PRIORITY_CATEGORY_ALARMS = 1 << 7; 112 /** 113 * @hide 114 */ 115 public static final int FIELD_PRIORITY_CATEGORY_MEDIA = 1 << 8; 116 /** 117 * @hide 118 */ 119 public static final int FIELD_PRIORITY_CATEGORY_SYSTEM = 1 << 9; 120 /** 121 * @hide 122 */ 123 public static final int FIELD_VISUAL_EFFECT_FULL_SCREEN_INTENT = 1 << 10; 124 /** 125 * @hide 126 */ 127 public static final int FIELD_VISUAL_EFFECT_LIGHTS = 1 << 11; 128 /** 129 * @hide 130 */ 131 public static final int FIELD_VISUAL_EFFECT_PEEK = 1 << 12; 132 /** 133 * @hide 134 */ 135 public static final int FIELD_VISUAL_EFFECT_STATUS_BAR = 1 << 13; 136 /** 137 * @hide 138 */ 139 public static final int FIELD_VISUAL_EFFECT_BADGE = 1 << 14; 140 /** 141 * @hide 142 */ 143 public static final int FIELD_VISUAL_EFFECT_AMBIENT = 1 << 15; 144 /** 145 * @hide 146 */ 147 public static final int FIELD_VISUAL_EFFECT_NOTIFICATION_LIST = 1 << 16; 148 149 private List<Integer> mPriorityCategories; 150 private List<Integer> mVisualEffects; 151 private @PeopleType int mPriorityMessages = PEOPLE_TYPE_UNSET; 152 private @PeopleType int mPriorityCalls = PEOPLE_TYPE_UNSET; 153 private @ConversationSenders int mConversationSenders = CONVERSATION_SENDERS_UNSET; 154 private @ChannelType int mAllowChannels = CHANNEL_POLICY_UNSET; 155 156 /** @hide */ 157 @IntDef(prefix = { "PRIORITY_CATEGORY_" }, value = { 158 PRIORITY_CATEGORY_REMINDERS, 159 PRIORITY_CATEGORY_EVENTS, 160 PRIORITY_CATEGORY_MESSAGES, 161 PRIORITY_CATEGORY_CALLS, 162 PRIORITY_CATEGORY_REPEAT_CALLERS, 163 PRIORITY_CATEGORY_ALARMS, 164 PRIORITY_CATEGORY_MEDIA, 165 PRIORITY_CATEGORY_SYSTEM, 166 PRIORITY_CATEGORY_CONVERSATIONS, 167 }) 168 @Retention(RetentionPolicy.SOURCE) 169 public @interface PriorityCategory {} 170 171 /** @hide */ 172 public static final int PRIORITY_CATEGORY_REMINDERS = 0; 173 /** @hide */ 174 public static final int PRIORITY_CATEGORY_EVENTS = 1; 175 /** @hide */ 176 public static final int PRIORITY_CATEGORY_MESSAGES = 2; 177 /** @hide */ 178 public static final int PRIORITY_CATEGORY_CALLS = 3; 179 /** @hide */ 180 public static final int PRIORITY_CATEGORY_REPEAT_CALLERS = 4; 181 /** @hide */ 182 public static final int PRIORITY_CATEGORY_ALARMS = 5; 183 /** @hide */ 184 public static final int PRIORITY_CATEGORY_MEDIA = 6; 185 /** @hide */ 186 public static final int PRIORITY_CATEGORY_SYSTEM = 7; 187 /** @hide */ 188 public static final int PRIORITY_CATEGORY_CONVERSATIONS = 8; 189 190 /** 191 * Total number of priority categories. Keep updated with any updates to PriorityCategory enum. 192 * If this changes, you must update {@link ZenModeDiff.PolicyDiff} to include new categories. 193 * @hide 194 */ 195 @VisibleForTesting 196 public static final int NUM_PRIORITY_CATEGORIES = 9; 197 198 /** @hide */ 199 @IntDef(prefix = { "VISUAL_EFFECT_" }, value = { 200 VISUAL_EFFECT_FULL_SCREEN_INTENT, 201 VISUAL_EFFECT_LIGHTS, 202 VISUAL_EFFECT_PEEK, 203 VISUAL_EFFECT_STATUS_BAR, 204 VISUAL_EFFECT_BADGE, 205 VISUAL_EFFECT_AMBIENT, 206 VISUAL_EFFECT_NOTIFICATION_LIST, 207 }) 208 @Retention(RetentionPolicy.SOURCE) 209 public @interface VisualEffect {} 210 211 /** @hide */ 212 public static final int VISUAL_EFFECT_FULL_SCREEN_INTENT = 0; 213 /** @hide */ 214 public static final int VISUAL_EFFECT_LIGHTS = 1; 215 /** @hide */ 216 public static final int VISUAL_EFFECT_PEEK = 2; 217 /** @hide */ 218 public static final int VISUAL_EFFECT_STATUS_BAR = 3; 219 /** @hide */ 220 public static final int VISUAL_EFFECT_BADGE = 4; 221 /** @hide */ 222 public static final int VISUAL_EFFECT_AMBIENT = 5; 223 /** @hide */ 224 public static final int VISUAL_EFFECT_NOTIFICATION_LIST = 6; 225 226 /** 227 * Total number of visual effects. Keep updated with any updates to VisualEffect enum. 228 * If this changes, you must update {@link ZenModeDiff.PolicyDiff} to include new categories. 229 * @hide 230 */ 231 @VisibleForTesting 232 public static final int NUM_VISUAL_EFFECTS = 7; 233 234 /** @hide */ 235 @IntDef(prefix = { "PEOPLE_TYPE_" }, value = { 236 PEOPLE_TYPE_UNSET, 237 PEOPLE_TYPE_ANYONE, 238 PEOPLE_TYPE_CONTACTS, 239 PEOPLE_TYPE_STARRED, 240 PEOPLE_TYPE_NONE, 241 }) 242 @Retention(RetentionPolicy.SOURCE) 243 public @interface PeopleType {} 244 245 /** 246 * Used to indicate no preference for the type of people that can bypass dnd for either 247 * calls or messages. 248 */ 249 public static final int PEOPLE_TYPE_UNSET = 0; 250 251 /** 252 * Used to indicate all calls or messages can bypass dnd. 253 */ 254 public static final int PEOPLE_TYPE_ANYONE = 1; 255 256 /** 257 * Used to indicate calls or messages from contacts can bypass dnd. 258 */ 259 public static final int PEOPLE_TYPE_CONTACTS = 2; 260 261 /** 262 * Used to indicate calls or messages from starred contacts can bypass dnd. 263 */ 264 public static final int PEOPLE_TYPE_STARRED = 3; 265 266 /** 267 * Used to indicate no calls or messages can bypass dnd. 268 */ 269 public static final int PEOPLE_TYPE_NONE = 4; 270 271 272 /** @hide */ 273 @IntDef(prefix = { "CONVERSATION_SENDERS_" }, value = { 274 CONVERSATION_SENDERS_UNSET, 275 CONVERSATION_SENDERS_ANYONE, 276 CONVERSATION_SENDERS_IMPORTANT, 277 CONVERSATION_SENDERS_NONE, 278 }) 279 @Retention(RetentionPolicy.SOURCE) 280 public @interface ConversationSenders {} 281 282 /** 283 * Used to indicate no preference for the type of conversations that can bypass dnd. 284 */ 285 public static final int CONVERSATION_SENDERS_UNSET = 0; 286 287 /** 288 * Used to indicate all conversations can bypass dnd. 289 */ 290 public static final int CONVERSATION_SENDERS_ANYONE = 1; 291 292 /** 293 * Used to indicate important conversations can bypass dnd. 294 */ 295 public static final int CONVERSATION_SENDERS_IMPORTANT = 2; 296 297 /** 298 * Used to indicate no conversations can bypass dnd. 299 */ 300 public static final int CONVERSATION_SENDERS_NONE = 3; 301 302 /** @hide */ 303 @IntDef(prefix = { "STATE_" }, value = { 304 STATE_UNSET, 305 STATE_ALLOW, 306 STATE_DISALLOW, 307 }) 308 @Retention(RetentionPolicy.SOURCE) 309 public @interface State {} 310 311 /** 312 * Indicates no preference for whether a type of sound or visual effect is or isn't allowed 313 * to play/show when DND is active. Will default to the current set policy. 314 */ 315 public static final int STATE_UNSET = 0; 316 317 /** 318 * Indicates a type of sound or visual effect is allowed to play/show when DND is active. 319 */ 320 public static final int STATE_ALLOW = 1; 321 322 /** 323 * Indicates a type of sound or visual effect is not allowed to play/show when DND is active. 324 */ 325 public static final int STATE_DISALLOW = 2; 326 327 @IntDef(prefix = { "CHANNEL_POLICY_" }, value = { 328 CHANNEL_POLICY_UNSET, 329 CHANNEL_POLICY_PRIORITY, 330 CHANNEL_POLICY_NONE, 331 }) 332 @Retention(RetentionPolicy.SOURCE) 333 private @interface ChannelType {} 334 335 /** 336 * Indicates no explicit setting for which channels may bypass DND when this policy is active. 337 * Defaults to {@link #CHANNEL_POLICY_PRIORITY}. 338 * 339 * @hide 340 */ 341 public static final int CHANNEL_POLICY_UNSET = 0; 342 343 /** 344 * Indicates that channels marked as {@link NotificationChannel#canBypassDnd()} can bypass DND 345 * when this policy is active. 346 * 347 * @hide 348 */ 349 public static final int CHANNEL_POLICY_PRIORITY = 1; 350 351 /** 352 * Indicates that no channels can bypass DND when this policy is active, even those marked as 353 * {@link NotificationChannel#canBypassDnd()}. 354 * 355 * @hide 356 */ 357 public static final int CHANNEL_POLICY_NONE = 2; 358 359 /** @hide */ ZenPolicy()360 public ZenPolicy() { 361 mPriorityCategories = new ArrayList<>(Collections.nCopies(NUM_PRIORITY_CATEGORIES, 0)); 362 mVisualEffects = new ArrayList<>(Collections.nCopies(NUM_VISUAL_EFFECTS, 0)); 363 } 364 365 /** @hide */ ZenPolicy(List<Integer> priorityCategories, List<Integer> visualEffects, @PeopleType int priorityMessages, @PeopleType int priorityCalls, @ConversationSenders int conversationSenders, @ChannelType int allowChannels)366 public ZenPolicy(List<Integer> priorityCategories, List<Integer> visualEffects, 367 @PeopleType int priorityMessages, @PeopleType int priorityCalls, 368 @ConversationSenders int conversationSenders, @ChannelType int allowChannels) { 369 mPriorityCategories = priorityCategories; 370 mVisualEffects = visualEffects; 371 mPriorityMessages = priorityMessages; 372 mPriorityCalls = priorityCalls; 373 mConversationSenders = conversationSenders; 374 mAllowChannels = allowChannels; 375 } 376 377 /** 378 * Base Zen Policy used when {@link android.app.NotificationManager#setInterruptionFilter} is 379 * called with {@link android.app.NotificationManager#INTERRUPTION_FILTER_ALARMS} or an 380 * {@link android.app.AutomaticZenRule} specifies said filter. 381 * 382 * <p>Note that <em>visual effects</em> for filtered notifications are unset in this base 383 * policy, so should be merged on top of the default policy's visual effects (see 384 * {@link #overwrittenWith(ZenPolicy)}). 385 * 386 * @hide 387 */ getBasePolicyInterruptionFilterAlarms()388 public static ZenPolicy getBasePolicyInterruptionFilterAlarms() { 389 return new ZenPolicy.Builder() 390 .disallowAllSounds() 391 .allowAlarms(true) 392 .allowMedia(true) 393 .allowPriorityChannels(false) 394 .build(); 395 } 396 397 /** 398 * Base Zen Policy used when {@link android.app.NotificationManager#setInterruptionFilter} is 399 * called with {@link android.app.NotificationManager#INTERRUPTION_FILTER_NONE} or an 400 * {@link android.app.AutomaticZenRule} specifies said filter. 401 * 402 * <p>Note that <em>visual effects</em> for filtered notifications are unset in this base 403 * policy, so it should be merged on top of the device default policy's visual effects (see 404 * {@link #overwrittenWith(ZenPolicy)}). 405 * 406 * @hide 407 */ getBasePolicyInterruptionFilterNone()408 public static ZenPolicy getBasePolicyInterruptionFilterNone() { 409 return new ZenPolicy.Builder() 410 .disallowAllSounds() 411 .allowPriorityChannels(false) 412 .build(); 413 } 414 415 /** 416 * Conversation type that can bypass DND. 417 * @return {@link #CONVERSATION_SENDERS_UNSET}, {@link #CONVERSATION_SENDERS_ANYONE}, 418 * {@link #CONVERSATION_SENDERS_IMPORTANT}, {@link #CONVERSATION_SENDERS_NONE}. 419 */ getPriorityConversationSenders()420 public @ConversationSenders int getPriorityConversationSenders() { 421 return mConversationSenders; 422 } 423 424 /** 425 * Message senders that can bypass DND. 426 * @return {@link #PEOPLE_TYPE_UNSET}, {@link #PEOPLE_TYPE_ANYONE}, 427 * {@link #PEOPLE_TYPE_CONTACTS}, {@link #PEOPLE_TYPE_STARRED} or {@link #PEOPLE_TYPE_NONE} 428 */ getPriorityMessageSenders()429 public @PeopleType int getPriorityMessageSenders() { 430 return mPriorityMessages; 431 } 432 433 /** 434 * Callers that can bypass DND. 435 * @return {@link #PEOPLE_TYPE_UNSET}, {@link #PEOPLE_TYPE_ANYONE}, 436 * {@link #PEOPLE_TYPE_CONTACTS}, {@link #PEOPLE_TYPE_STARRED} or {@link #PEOPLE_TYPE_NONE} 437 */ getPriorityCallSenders()438 public @PeopleType int getPriorityCallSenders() { 439 return mPriorityCalls; 440 } 441 442 /** 443 * Whether this policy wants to allow conversation notifications 444 * (see {@link NotificationChannel#getConversationId()}) to play sounds and visually appear 445 * or to intercept them when DND is active. 446 * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW} 447 */ getPriorityCategoryConversations()448 public @State int getPriorityCategoryConversations() { 449 return mPriorityCategories.get(PRIORITY_CATEGORY_CONVERSATIONS); 450 } 451 452 /** 453 * Whether this policy wants to allow notifications with category 454 * {@link Notification#CATEGORY_REMINDER} to play sounds and visually appear 455 * or to intercept them when DND is active. 456 * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW} 457 */ getPriorityCategoryReminders()458 public @State int getPriorityCategoryReminders() { 459 return mPriorityCategories.get(PRIORITY_CATEGORY_REMINDERS); 460 } 461 462 /** 463 * Whether this policy wants to allow notifications with category 464 * {@link Notification#CATEGORY_EVENT} to play sounds and visually appear 465 * or to intercept them when DND is active. 466 * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW} 467 */ getPriorityCategoryEvents()468 public @State int getPriorityCategoryEvents() { 469 return mPriorityCategories.get(PRIORITY_CATEGORY_EVENTS); 470 } 471 472 /** 473 * Whether this policy wants to allow notifications with category 474 * {@link Notification#CATEGORY_MESSAGE} to play sounds and visually appear 475 * or to intercept them when DND is active. Types of message senders that are allowed 476 * are specified by {@link #getPriorityMessageSenders}. 477 * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW} 478 */ getPriorityCategoryMessages()479 public @State int getPriorityCategoryMessages() { 480 return mPriorityCategories.get(PRIORITY_CATEGORY_MESSAGES); 481 } 482 483 /** 484 * Whether this policy wants to allow notifications with category 485 * {@link Notification#CATEGORY_CALL} to play sounds and visually appear 486 * or to intercept them when DND is active. Types of callers that are allowed 487 * are specified by {@link #getPriorityCallSenders()}. 488 * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW} 489 */ getPriorityCategoryCalls()490 public @State int getPriorityCategoryCalls() { 491 return mPriorityCategories.get(PRIORITY_CATEGORY_CALLS); 492 } 493 494 /** 495 * Whether this policy wants to allow repeat callers (notifications with category 496 * {@link Notification#CATEGORY_CALL} that have recently called) to play sounds and 497 * visually appear or to intercept them when DND is active. 498 * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW} 499 */ getPriorityCategoryRepeatCallers()500 public @State int getPriorityCategoryRepeatCallers() { 501 return mPriorityCategories.get(PRIORITY_CATEGORY_REPEAT_CALLERS); 502 } 503 504 /** 505 * Whether this policy wants to allow notifications with category 506 * {@link Notification#CATEGORY_ALARM} to play sounds and visually appear 507 * or to intercept them when DND is active. 508 * When alarms are {@link #STATE_DISALLOW disallowed}, the alarm stream will be muted when DND 509 * is active. 510 * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW} 511 */ getPriorityCategoryAlarms()512 public @State int getPriorityCategoryAlarms() { 513 return mPriorityCategories.get(PRIORITY_CATEGORY_ALARMS); 514 } 515 516 /** 517 * Whether this policy wants to allow media notifications to play sounds and visually appear 518 * or to intercept them when DND is active. 519 * When media is {@link #STATE_DISALLOW disallowed}, the media stream will be muted when DND is 520 * active. 521 * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW} 522 */ getPriorityCategoryMedia()523 public @State int getPriorityCategoryMedia() { 524 return mPriorityCategories.get(PRIORITY_CATEGORY_MEDIA); 525 } 526 527 /** 528 * Whether this policy wants to allow system sounds when DND is active. 529 * When system is {@link #STATE_DISALLOW}, the system stream will be muted when DND is active. 530 * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW} 531 */ getPriorityCategorySystem()532 public @State int getPriorityCategorySystem() { 533 return mPriorityCategories.get(PRIORITY_CATEGORY_SYSTEM); 534 } 535 536 /** 537 * Whether this policy allows {@link Notification#fullScreenIntent full screen intents} from 538 * notifications intercepted by DND. 539 */ getVisualEffectFullScreenIntent()540 public @State int getVisualEffectFullScreenIntent() { 541 return mVisualEffects.get(VISUAL_EFFECT_FULL_SCREEN_INTENT); 542 } 543 544 /** 545 * Whether this policy allows {@link NotificationChannel#shouldShowLights() notification 546 * lights} from notifications intercepted by DND. 547 */ getVisualEffectLights()548 public @State int getVisualEffectLights() { 549 return mVisualEffects.get(VISUAL_EFFECT_LIGHTS); 550 } 551 552 /** 553 * Whether this policy allows peeking from notifications intercepted by DND. 554 */ getVisualEffectPeek()555 public @State int getVisualEffectPeek() { 556 return mVisualEffects.get(VISUAL_EFFECT_PEEK); 557 } 558 559 /** 560 * Whether this policy allows notifications intercepted by DND from appearing in the status bar 561 * on devices that support status bars. 562 */ getVisualEffectStatusBar()563 public @State int getVisualEffectStatusBar() { 564 return mVisualEffects.get(VISUAL_EFFECT_STATUS_BAR); 565 } 566 567 /** 568 * Whether this policy allows {@link NotificationChannel#canShowBadge() badges} from 569 * notifications intercepted by DND on devices that support badging. 570 */ getVisualEffectBadge()571 public @State int getVisualEffectBadge() { 572 return mVisualEffects.get(VISUAL_EFFECT_BADGE); 573 } 574 575 /** 576 * Whether this policy allows notifications intercepted by DND from appearing on ambient 577 * displays on devices that support ambient display. 578 */ getVisualEffectAmbient()579 public @State int getVisualEffectAmbient() { 580 return mVisualEffects.get(VISUAL_EFFECT_AMBIENT); 581 } 582 583 /** 584 * Whether this policy allows notifications intercepted by DND from appearing in notification 585 * list views like the notification shade or lockscreen on devices that support those 586 * views. 587 */ getVisualEffectNotificationList()588 public @State int getVisualEffectNotificationList() { 589 return mVisualEffects.get(VISUAL_EFFECT_NOTIFICATION_LIST); 590 } 591 592 /** 593 * @hide 594 */ getAllowedChannels()595 public @ChannelType int getAllowedChannels() { 596 return mAllowChannels; 597 } 598 599 /** 600 * Whether this policy allows {@link NotificationChannel channels} marked as 601 * {@link NotificationChannel#canBypassDnd()} to bypass DND. If {@link #STATE_ALLOW}, these 602 * channels may bypass; if {@link #STATE_DISALLOW}, then even notifications from channels 603 * with {@link NotificationChannel#canBypassDnd()} will be intercepted. 604 */ getPriorityChannelsAllowed()605 public @State int getPriorityChannelsAllowed() { 606 switch (mAllowChannels) { 607 case CHANNEL_POLICY_PRIORITY: 608 return STATE_ALLOW; 609 case CHANNEL_POLICY_NONE: 610 return STATE_DISALLOW; 611 default: 612 return STATE_UNSET; 613 } 614 } 615 616 /** 617 * Whether this policy hides all visual effects 618 * @hide 619 */ shouldHideAllVisualEffects()620 public boolean shouldHideAllVisualEffects() { 621 for (int i = 0; i < mVisualEffects.size(); i++) { 622 if (mVisualEffects.get(i) != STATE_DISALLOW) { 623 return false; 624 } 625 } 626 return true; 627 } 628 629 /** 630 * Whether this policy shows all visual effects 631 * @hide 632 */ shouldShowAllVisualEffects()633 public boolean shouldShowAllVisualEffects() { 634 for (int i = 0; i < mVisualEffects.size(); i++) { 635 if (mVisualEffects.get(i) != STATE_ALLOW) { 636 return false; 637 } 638 } 639 return true; 640 } 641 642 /** 643 * Builder class for {@link ZenPolicy} objects. 644 * Provides a convenient way to set the various fields of a {@link ZenPolicy}. If a field 645 * is not set, it is (@link STATE_UNSET} and will not change the current set policy. 646 */ 647 public static final class Builder { 648 private ZenPolicy mZenPolicy; 649 Builder()650 public Builder() { 651 mZenPolicy = new ZenPolicy(); 652 } 653 654 /** 655 * @hide 656 */ 657 @SuppressLint("UnflaggedApi") 658 @TestApi Builder(@ullable ZenPolicy policy)659 public Builder(@Nullable ZenPolicy policy) { 660 if (policy != null) { 661 mZenPolicy = policy.copy(); 662 } else { 663 mZenPolicy = new ZenPolicy(); 664 } 665 } 666 667 /** 668 * Builds the current ZenPolicy. 669 */ build()670 public @NonNull ZenPolicy build() { 671 return new ZenPolicy(new ArrayList<>(mZenPolicy.mPriorityCategories), 672 new ArrayList<>(mZenPolicy.mVisualEffects), 673 mZenPolicy.mPriorityMessages, mZenPolicy.mPriorityCalls, 674 mZenPolicy.mConversationSenders, mZenPolicy.mAllowChannels); 675 } 676 677 /** 678 * Allows all notifications to bypass DND and unmutes all streams. 679 */ allowAllSounds()680 public @NonNull Builder allowAllSounds() { 681 for (int i = 0; i < mZenPolicy.mPriorityCategories.size(); i++) { 682 mZenPolicy.mPriorityCategories.set(i, STATE_ALLOW); 683 } 684 mZenPolicy.mPriorityMessages = PEOPLE_TYPE_ANYONE; 685 mZenPolicy.mPriorityCalls = PEOPLE_TYPE_ANYONE; 686 mZenPolicy.mConversationSenders = CONVERSATION_SENDERS_ANYONE; 687 return this; 688 } 689 690 /** 691 * Intercepts all notifications and prevents them from playing sounds 692 * when DND is active. Also mutes alarm, system and media streams. 693 * Notification channels can still play sounds only if they 694 * {@link NotificationChannel#canBypassDnd can bypass DND}. If no channels can bypass DND, 695 * the ringer stream is also muted. 696 */ disallowAllSounds()697 public @NonNull Builder disallowAllSounds() { 698 for (int i = 0; i < mZenPolicy.mPriorityCategories.size(); i++) { 699 mZenPolicy.mPriorityCategories.set(i, STATE_DISALLOW); 700 } 701 mZenPolicy.mPriorityMessages = PEOPLE_TYPE_NONE; 702 mZenPolicy.mPriorityCalls = PEOPLE_TYPE_NONE; 703 mZenPolicy.mConversationSenders = CONVERSATION_SENDERS_NONE; 704 return this; 705 } 706 707 /** 708 * Allows notifications intercepted by DND to show on all surfaces when DND is active. 709 */ showAllVisualEffects()710 public @NonNull Builder showAllVisualEffects() { 711 for (int i = 0; i < mZenPolicy.mVisualEffects.size(); i++) { 712 mZenPolicy.mVisualEffects.set(i, STATE_ALLOW); 713 } 714 return this; 715 } 716 717 /** 718 * Disallows notifications intercepted by DND from showing when DND is active. 719 */ hideAllVisualEffects()720 public @NonNull Builder hideAllVisualEffects() { 721 for (int i = 0; i < mZenPolicy.mVisualEffects.size(); i++) { 722 mZenPolicy.mVisualEffects.set(i, STATE_DISALLOW); 723 } 724 return this; 725 } 726 727 /** 728 * Unsets a priority category, neither allowing or disallowing. When applying this policy, 729 * unset categories will default to the current applied policy. 730 * @hide 731 */ unsetPriorityCategory(@riorityCategory int category)732 public @NonNull Builder unsetPriorityCategory(@PriorityCategory int category) { 733 mZenPolicy.mPriorityCategories.set(category, STATE_UNSET); 734 735 if (category == PRIORITY_CATEGORY_MESSAGES) { 736 mZenPolicy.mPriorityMessages = PEOPLE_TYPE_UNSET; 737 } else if (category == PRIORITY_CATEGORY_CALLS) { 738 mZenPolicy.mPriorityCalls = PEOPLE_TYPE_UNSET; 739 } else if (category == PRIORITY_CATEGORY_CONVERSATIONS) { 740 mZenPolicy.mConversationSenders = CONVERSATION_SENDERS_UNSET; 741 } 742 743 return this; 744 } 745 746 /** 747 * Unsets a visual effect, neither allowing or disallowing. When applying this policy, 748 * unset effects will default to the current applied policy. 749 * @hide 750 */ unsetVisualEffect(@isualEffect int effect)751 public @NonNull Builder unsetVisualEffect(@VisualEffect int effect) { 752 mZenPolicy.mVisualEffects.set(effect, STATE_UNSET); 753 return this; 754 } 755 756 /** 757 * Whether to allow notifications with category {@link Notification#CATEGORY_REMINDER} 758 * to play sounds and visually appear or to intercept them when DND is active. 759 */ allowReminders(boolean allow)760 public @NonNull Builder allowReminders(boolean allow) { 761 mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_REMINDERS, 762 allow ? STATE_ALLOW : STATE_DISALLOW); 763 return this; 764 } 765 766 /** 767 * Whether to allow notifications with category {@link Notification#CATEGORY_EVENT} 768 * to play sounds and visually appear or to intercept them when DND is active. 769 */ allowEvents(boolean allow)770 public @NonNull Builder allowEvents(boolean allow) { 771 mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_EVENTS, 772 allow ? STATE_ALLOW : STATE_DISALLOW); 773 return this; 774 } 775 776 /** 777 * Whether to allow conversation notifications 778 * (see {@link NotificationChannel#setConversationId(String, String)}) 779 * that match audienceType to play sounds and visually appear or to intercept 780 * them when DND is active. 781 * @param audienceType callers that are allowed to bypass DND 782 */ allowConversations(@onversationSenders int audienceType)783 public @NonNull Builder allowConversations(@ConversationSenders int audienceType) { 784 if (audienceType == STATE_UNSET) { 785 return unsetPriorityCategory(PRIORITY_CATEGORY_CONVERSATIONS); 786 } 787 788 if (audienceType == CONVERSATION_SENDERS_NONE) { 789 mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_CONVERSATIONS, STATE_DISALLOW); 790 } else if (audienceType == CONVERSATION_SENDERS_ANYONE 791 || audienceType == CONVERSATION_SENDERS_IMPORTANT) { 792 mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_CONVERSATIONS, STATE_ALLOW); 793 } else { 794 return this; 795 } 796 797 mZenPolicy.mConversationSenders = audienceType; 798 return this; 799 } 800 801 /** 802 * Whether to allow notifications with category {@link Notification#CATEGORY_MESSAGE} 803 * that match audienceType to play sounds and visually appear or to intercept 804 * them when DND is active. 805 * @param audienceType message senders that are allowed to bypass DND 806 */ allowMessages(@eopleType int audienceType)807 public @NonNull Builder allowMessages(@PeopleType int audienceType) { 808 if (audienceType == STATE_UNSET) { 809 return unsetPriorityCategory(PRIORITY_CATEGORY_MESSAGES); 810 } 811 812 if (audienceType == PEOPLE_TYPE_NONE) { 813 mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_MESSAGES, STATE_DISALLOW); 814 } else if (audienceType == PEOPLE_TYPE_ANYONE || audienceType == PEOPLE_TYPE_CONTACTS 815 || audienceType == PEOPLE_TYPE_STARRED) { 816 mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_MESSAGES, STATE_ALLOW); 817 } else { 818 return this; 819 } 820 821 mZenPolicy.mPriorityMessages = audienceType; 822 return this; 823 } 824 825 /** 826 * Whether to allow notifications with category {@link Notification#CATEGORY_CALL} 827 * that match audienceType to play sounds and visually appear or to intercept 828 * them when DND is active. 829 * @param audienceType callers that are allowed to bypass DND 830 */ allowCalls(@eopleType int audienceType)831 public @NonNull Builder allowCalls(@PeopleType int audienceType) { 832 if (audienceType == STATE_UNSET) { 833 return unsetPriorityCategory(PRIORITY_CATEGORY_CALLS); 834 } 835 836 if (audienceType == PEOPLE_TYPE_NONE) { 837 mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_CALLS, STATE_DISALLOW); 838 } else if (audienceType == PEOPLE_TYPE_ANYONE || audienceType == PEOPLE_TYPE_CONTACTS 839 || audienceType == PEOPLE_TYPE_STARRED) { 840 mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_CALLS, STATE_ALLOW); 841 } else { 842 return this; 843 } 844 845 mZenPolicy.mPriorityCalls = audienceType; 846 return this; 847 } 848 849 /** 850 * Whether to allow repeat callers (notifications with category 851 * {@link Notification#CATEGORY_CALL} that have recently called 852 * to play sounds and visually appear. 853 */ allowRepeatCallers(boolean allow)854 public @NonNull Builder allowRepeatCallers(boolean allow) { 855 mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_REPEAT_CALLERS, 856 allow ? STATE_ALLOW : STATE_DISALLOW); 857 return this; 858 } 859 860 /** 861 * Whether to allow notifications with category {@link Notification#CATEGORY_ALARM} 862 * to play sounds and visually appear or to intercept them when DND is active. 863 * Disallowing alarms will mute the alarm stream when DND is active. 864 */ allowAlarms(boolean allow)865 public @NonNull Builder allowAlarms(boolean allow) { 866 mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_ALARMS, 867 allow ? STATE_ALLOW : STATE_DISALLOW); 868 return this; 869 } 870 871 /** 872 * Whether to allow media notifications to play sounds and visually 873 * appear or to intercept them when DND is active. 874 * Disallowing media will mute the media stream when DND is active. 875 */ allowMedia(boolean allow)876 public @NonNull Builder allowMedia(boolean allow) { 877 mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_MEDIA, 878 allow ? STATE_ALLOW : STATE_DISALLOW); 879 return this; 880 } 881 882 /** 883 * Whether to allow system sounds to play when DND is active. 884 * Disallowing system sounds will mute the system stream when DND is active. 885 */ allowSystem(boolean allow)886 public @NonNull Builder allowSystem(boolean allow) { 887 mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_SYSTEM, 888 allow ? STATE_ALLOW : STATE_DISALLOW); 889 return this; 890 } 891 892 /** 893 * Whether to allow {@link PriorityCategory} sounds to play when DND is active. 894 * @hide 895 */ allowCategory(@riorityCategory int category, boolean allow)896 public @NonNull Builder allowCategory(@PriorityCategory int category, boolean allow) { 897 switch (category) { 898 case PRIORITY_CATEGORY_ALARMS: 899 allowAlarms(allow); 900 break; 901 case PRIORITY_CATEGORY_MEDIA: 902 allowMedia(allow); 903 break; 904 case PRIORITY_CATEGORY_SYSTEM: 905 allowSystem(allow); 906 break; 907 case PRIORITY_CATEGORY_REMINDERS: 908 allowReminders(allow); 909 break; 910 case PRIORITY_CATEGORY_EVENTS: 911 allowEvents(allow); 912 break; 913 case PRIORITY_CATEGORY_REPEAT_CALLERS: 914 allowRepeatCallers(allow); 915 break; 916 } 917 return this; 918 } 919 920 /** 921 * Whether {@link Notification#fullScreenIntent full screen intents} that are intercepted 922 * by DND are shown. 923 */ showFullScreenIntent(boolean show)924 public @NonNull Builder showFullScreenIntent(boolean show) { 925 mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_FULL_SCREEN_INTENT, 926 show ? STATE_ALLOW : STATE_DISALLOW); 927 return this; 928 } 929 930 /** 931 * Whether {@link NotificationChannel#shouldShowLights() notification lights} from 932 * notifications intercepted by DND are blocked. 933 */ showLights(boolean show)934 public @NonNull Builder showLights(boolean show) { 935 mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_LIGHTS, 936 show ? STATE_ALLOW : STATE_DISALLOW); 937 return this; 938 } 939 940 /** 941 * Whether notifications intercepted by DND are prevented from peeking. 942 */ showPeeking(boolean show)943 public @NonNull Builder showPeeking(boolean show) { 944 mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_PEEK, 945 show ? STATE_ALLOW : STATE_DISALLOW); 946 return this; 947 } 948 949 /** 950 * Whether notifications intercepted by DND are prevented from appearing in the status bar 951 * on devices that support status bars. 952 */ showStatusBarIcons(boolean show)953 public @NonNull Builder showStatusBarIcons(boolean show) { 954 mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_STATUS_BAR, 955 show ? STATE_ALLOW : STATE_DISALLOW); 956 return this; 957 } 958 959 /** 960 * Whether {@link NotificationChannel#canShowBadge() badges} from 961 * notifications intercepted by DND are allowed on devices that support badging. 962 */ showBadges(boolean show)963 public @NonNull Builder showBadges(boolean show) { 964 mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_BADGE, 965 show ? STATE_ALLOW : STATE_DISALLOW); 966 return this; 967 } 968 969 /** 970 * Whether notification intercepted by DND are prevented from appearing on ambient displays 971 * on devices that support ambient display. 972 */ showInAmbientDisplay(boolean show)973 public @NonNull Builder showInAmbientDisplay(boolean show) { 974 mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_AMBIENT, 975 show ? STATE_ALLOW : STATE_DISALLOW); 976 return this; 977 } 978 979 /** 980 * Whether notification intercepted by DND are prevented from appearing in notification 981 * list views like the notification shade or lockscreen on devices that support those 982 * views. 983 */ showInNotificationList(boolean show)984 public @NonNull Builder showInNotificationList(boolean show) { 985 mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_NOTIFICATION_LIST, 986 show ? STATE_ALLOW : STATE_DISALLOW); 987 return this; 988 } 989 990 /** 991 * Whether notifications intercepted by DND are prevented from appearing for 992 * {@link VisualEffect} 993 * @hide 994 */ showVisualEffect(@isualEffect int effect, boolean show)995 public @NonNull Builder showVisualEffect(@VisualEffect int effect, boolean show) { 996 switch (effect) { 997 case VISUAL_EFFECT_FULL_SCREEN_INTENT: 998 showFullScreenIntent(show); 999 break; 1000 case VISUAL_EFFECT_LIGHTS: 1001 showLights(show); 1002 break; 1003 case VISUAL_EFFECT_PEEK: 1004 showPeeking(show); 1005 break; 1006 case VISUAL_EFFECT_STATUS_BAR: 1007 showStatusBarIcons(show); 1008 break; 1009 case VISUAL_EFFECT_BADGE: 1010 showBadges(show); 1011 break; 1012 case VISUAL_EFFECT_AMBIENT: 1013 showInAmbientDisplay(show); 1014 break; 1015 case VISUAL_EFFECT_NOTIFICATION_LIST: 1016 showInNotificationList(show); 1017 break; 1018 } 1019 return this; 1020 } 1021 1022 /** 1023 * Set whether priority channels are permitted to break through DND. 1024 */ 1025 @SuppressLint("BuilderSetStyle") allowPriorityChannels(boolean allow)1026 public @NonNull Builder allowPriorityChannels(boolean allow) { 1027 mZenPolicy.mAllowChannels = allow ? CHANNEL_POLICY_PRIORITY : CHANNEL_POLICY_NONE; 1028 return this; 1029 } 1030 1031 /** @hide */ allowChannels(@hannelType int channelType)1032 public @NonNull Builder allowChannels(@ChannelType int channelType) { 1033 mZenPolicy.mAllowChannels = channelType; 1034 return this; 1035 } 1036 } 1037 1038 @Override describeContents()1039 public int describeContents() { 1040 return 0; 1041 } 1042 1043 @Override writeToParcel(Parcel dest, int flags)1044 public void writeToParcel(Parcel dest, int flags) { 1045 dest.writeList(mPriorityCategories); 1046 dest.writeList(mVisualEffects); 1047 dest.writeInt(mPriorityMessages); 1048 dest.writeInt(mPriorityCalls); 1049 dest.writeInt(mConversationSenders); 1050 dest.writeInt(mAllowChannels); 1051 } 1052 1053 public static final @NonNull Creator<ZenPolicy> CREATOR = 1054 new Creator<ZenPolicy>() { 1055 @Override 1056 public ZenPolicy createFromParcel(Parcel source) { 1057 return new ZenPolicy( 1058 trimList(source.readArrayList(Integer.class.getClassLoader(), 1059 Integer.class), NUM_PRIORITY_CATEGORIES), 1060 trimList(source.readArrayList(Integer.class.getClassLoader(), 1061 Integer.class), NUM_VISUAL_EFFECTS), 1062 source.readInt(), source.readInt(), source.readInt(), 1063 source.readInt() 1064 ); 1065 } 1066 1067 @Override 1068 public ZenPolicy[] newArray(int size) { 1069 return new ZenPolicy[size]; 1070 } 1071 }; 1072 1073 @Override toString()1074 public String toString() { 1075 return new StringBuilder(ZenPolicy.class.getSimpleName()) 1076 .append('{') 1077 .append("priorityCategories=[").append(priorityCategoriesToString()) 1078 .append("], visualEffects=[").append(visualEffectsToString()) 1079 .append("], priorityCallsSenders=").append(peopleTypeToString(mPriorityCalls)) 1080 .append(", priorityMessagesSenders=").append(peopleTypeToString(mPriorityMessages)) 1081 .append(", priorityConversationSenders=").append( 1082 conversationTypeToString(mConversationSenders)) 1083 .append(", allowChannels=").append(channelTypeToString(mAllowChannels)) 1084 .append('}').toString(); 1085 } 1086 1087 /** @hide */ fieldsToString(@odifiableField int bitmask)1088 public static String fieldsToString(@ModifiableField int bitmask) { 1089 ArrayList<String> modified = new ArrayList<>(); 1090 if ((bitmask & FIELD_MESSAGES) != 0) { 1091 modified.add("FIELD_MESSAGES"); 1092 } 1093 if ((bitmask & FIELD_CALLS) != 0) { 1094 modified.add("FIELD_CALLS"); 1095 } 1096 if ((bitmask & FIELD_CONVERSATIONS) != 0) { 1097 modified.add("FIELD_CONVERSATIONS"); 1098 } 1099 if ((bitmask & FIELD_ALLOW_CHANNELS) != 0) { 1100 modified.add("FIELD_ALLOW_CHANNELS"); 1101 } 1102 if ((bitmask & FIELD_PRIORITY_CATEGORY_REMINDERS) != 0) { 1103 modified.add("FIELD_PRIORITY_CATEGORY_REMINDERS"); 1104 } 1105 if ((bitmask & FIELD_PRIORITY_CATEGORY_EVENTS) != 0) { 1106 modified.add("FIELD_PRIORITY_CATEGORY_EVENTS"); 1107 } 1108 if ((bitmask & FIELD_PRIORITY_CATEGORY_REPEAT_CALLERS) != 0) { 1109 modified.add("FIELD_PRIORITY_CATEGORY_REPEAT_CALLERS"); 1110 } 1111 if ((bitmask & FIELD_PRIORITY_CATEGORY_ALARMS) != 0) { 1112 modified.add("FIELD_PRIORITY_CATEGORY_ALARMS"); 1113 } 1114 if ((bitmask & FIELD_PRIORITY_CATEGORY_MEDIA) != 0) { 1115 modified.add("FIELD_PRIORITY_CATEGORY_MEDIA"); 1116 } 1117 if ((bitmask & FIELD_PRIORITY_CATEGORY_SYSTEM) != 0) { 1118 modified.add("FIELD_PRIORITY_CATEGORY_SYSTEM"); 1119 } 1120 if ((bitmask & FIELD_VISUAL_EFFECT_FULL_SCREEN_INTENT) != 0) { 1121 modified.add("FIELD_VISUAL_EFFECT_FULL_SCREEN_INTENT"); 1122 } 1123 if ((bitmask & FIELD_VISUAL_EFFECT_LIGHTS) != 0) { 1124 modified.add("FIELD_VISUAL_EFFECT_LIGHTS"); 1125 } 1126 if ((bitmask & FIELD_VISUAL_EFFECT_PEEK) != 0) { 1127 modified.add("FIELD_VISUAL_EFFECT_PEEK"); 1128 } 1129 if ((bitmask & FIELD_VISUAL_EFFECT_STATUS_BAR) != 0) { 1130 modified.add("FIELD_VISUAL_EFFECT_STATUS_BAR"); 1131 } 1132 if ((bitmask & FIELD_VISUAL_EFFECT_BADGE) != 0) { 1133 modified.add("FIELD_VISUAL_EFFECT_BADGE"); 1134 } 1135 if ((bitmask & FIELD_VISUAL_EFFECT_AMBIENT) != 0) { 1136 modified.add("FIELD_VISUAL_EFFECT_AMBIENT"); 1137 } 1138 if ((bitmask & FIELD_VISUAL_EFFECT_NOTIFICATION_LIST) != 0) { 1139 modified.add("FIELD_VISUAL_EFFECT_NOTIFICATION_LIST"); 1140 } 1141 return "{" + String.join(",", modified) + "}"; 1142 } 1143 1144 // Returns a list containing the first maxLength elements of the input list if the list is 1145 // longer than that size. For the lists in ZenPolicy, this should not happen unless the input 1146 // is corrupt. trimList(ArrayList<Integer> list, int maxLength)1147 private static ArrayList<Integer> trimList(ArrayList<Integer> list, int maxLength) { 1148 if (list == null || list.size() <= maxLength) { 1149 return list; 1150 } 1151 return new ArrayList<>(list.subList(0, maxLength)); 1152 } 1153 priorityCategoriesToString()1154 private String priorityCategoriesToString() { 1155 StringBuilder builder = new StringBuilder(); 1156 for (int i = 0; i < mPriorityCategories.size(); i++) { 1157 if (mPriorityCategories.get(i) != STATE_UNSET) { 1158 builder.append(indexToCategory(i)) 1159 .append("=") 1160 .append(stateToString(mPriorityCategories.get(i))) 1161 .append(" "); 1162 } 1163 1164 } 1165 return builder.toString(); 1166 } 1167 visualEffectsToString()1168 private String visualEffectsToString() { 1169 StringBuilder builder = new StringBuilder(); 1170 for (int i = 0; i < mVisualEffects.size(); i++) { 1171 if (mVisualEffects.get(i) != STATE_UNSET) { 1172 builder.append(indexToVisualEffect(i)) 1173 .append("=") 1174 .append(stateToString(mVisualEffects.get(i))) 1175 .append(" "); 1176 } 1177 1178 } 1179 return builder.toString(); 1180 } 1181 indexToVisualEffect(@isualEffect int visualEffectIndex)1182 private String indexToVisualEffect(@VisualEffect int visualEffectIndex) { 1183 switch (visualEffectIndex) { 1184 case VISUAL_EFFECT_FULL_SCREEN_INTENT: 1185 return "fullScreenIntent"; 1186 case VISUAL_EFFECT_LIGHTS: 1187 return "lights"; 1188 case VISUAL_EFFECT_PEEK: 1189 return "peek"; 1190 case VISUAL_EFFECT_STATUS_BAR: 1191 return "statusBar"; 1192 case VISUAL_EFFECT_BADGE: 1193 return "badge"; 1194 case VISUAL_EFFECT_AMBIENT: 1195 return "ambient"; 1196 case VISUAL_EFFECT_NOTIFICATION_LIST: 1197 return "notificationList"; 1198 } 1199 return null; 1200 } 1201 indexToCategory(@riorityCategory int categoryIndex)1202 private String indexToCategory(@PriorityCategory int categoryIndex) { 1203 switch (categoryIndex) { 1204 case PRIORITY_CATEGORY_REMINDERS: 1205 return "reminders"; 1206 case PRIORITY_CATEGORY_EVENTS: 1207 return "events"; 1208 case PRIORITY_CATEGORY_MESSAGES: 1209 return "messages"; 1210 case PRIORITY_CATEGORY_CALLS: 1211 return "calls"; 1212 case PRIORITY_CATEGORY_REPEAT_CALLERS: 1213 return "repeatCallers"; 1214 case PRIORITY_CATEGORY_ALARMS: 1215 return "alarms"; 1216 case PRIORITY_CATEGORY_MEDIA: 1217 return "media"; 1218 case PRIORITY_CATEGORY_SYSTEM: 1219 return "system"; 1220 case PRIORITY_CATEGORY_CONVERSATIONS: 1221 return "convs"; 1222 } 1223 return null; 1224 } 1225 stateToString(@tate int state)1226 private String stateToString(@State int state) { 1227 switch (state) { 1228 case STATE_UNSET: 1229 return "unset"; 1230 case STATE_DISALLOW: 1231 return "disallow"; 1232 case STATE_ALLOW: 1233 return "allow"; 1234 } 1235 return "invalidState{" + state + "}"; 1236 } 1237 1238 /** 1239 * @hide 1240 */ peopleTypeToString(@eopleType int peopleType)1241 public static String peopleTypeToString(@PeopleType int peopleType) { 1242 switch (peopleType) { 1243 case PEOPLE_TYPE_ANYONE: 1244 return "anyone"; 1245 case PEOPLE_TYPE_CONTACTS: 1246 return "contacts"; 1247 case PEOPLE_TYPE_NONE: 1248 return "none"; 1249 case PEOPLE_TYPE_STARRED: 1250 return "starred_contacts"; 1251 case STATE_UNSET: 1252 return "unset"; 1253 } 1254 return "invalidPeopleType{" + peopleType + "}"; 1255 } 1256 1257 /** 1258 * @hide 1259 */ conversationTypeToString(@onversationSenders int conversationType)1260 public static String conversationTypeToString(@ConversationSenders int conversationType) { 1261 switch (conversationType) { 1262 case CONVERSATION_SENDERS_ANYONE: 1263 return "anyone"; 1264 case CONVERSATION_SENDERS_IMPORTANT: 1265 return "important"; 1266 case CONVERSATION_SENDERS_NONE: 1267 return "none"; 1268 case CONVERSATION_SENDERS_UNSET: 1269 return "unset"; 1270 } 1271 return "invalidConversationType{" + conversationType + "}"; 1272 } 1273 1274 /** 1275 * @hide 1276 */ channelTypeToString(@hannelType int channelType)1277 public static String channelTypeToString(@ChannelType int channelType) { 1278 switch (channelType) { 1279 case CHANNEL_POLICY_UNSET: 1280 return "unset"; 1281 case CHANNEL_POLICY_PRIORITY: 1282 return "priority"; 1283 case CHANNEL_POLICY_NONE: 1284 return "none"; 1285 } 1286 return "invalidChannelType{" + channelType + "}"; 1287 } 1288 1289 @Override equals(@ullable Object o)1290 public boolean equals(@Nullable Object o) { 1291 if (!(o instanceof ZenPolicy)) return false; 1292 if (o == this) return true; 1293 final ZenPolicy other = (ZenPolicy) o; 1294 1295 return Objects.equals(other.mPriorityCategories, mPriorityCategories) 1296 && Objects.equals(other.mVisualEffects, mVisualEffects) 1297 && other.mPriorityCalls == mPriorityCalls 1298 && other.mPriorityMessages == mPriorityMessages 1299 && other.mConversationSenders == mConversationSenders 1300 && other.mAllowChannels == mAllowChannels; 1301 } 1302 1303 @Override hashCode()1304 public int hashCode() { 1305 return Objects.hash(mPriorityCategories, mVisualEffects, mPriorityCalls, 1306 mPriorityMessages, mConversationSenders, mAllowChannels); 1307 } 1308 getZenPolicyPriorityCategoryState(@riorityCategory int category)1309 private @State int getZenPolicyPriorityCategoryState(@PriorityCategory int 1310 category) { 1311 switch (category) { 1312 case PRIORITY_CATEGORY_REMINDERS: 1313 return getPriorityCategoryReminders(); 1314 case PRIORITY_CATEGORY_EVENTS: 1315 return getPriorityCategoryEvents(); 1316 case PRIORITY_CATEGORY_MESSAGES: 1317 return getPriorityCategoryMessages(); 1318 case PRIORITY_CATEGORY_CALLS: 1319 return getPriorityCategoryCalls(); 1320 case PRIORITY_CATEGORY_REPEAT_CALLERS: 1321 return getPriorityCategoryRepeatCallers(); 1322 case PRIORITY_CATEGORY_ALARMS: 1323 return getPriorityCategoryAlarms(); 1324 case PRIORITY_CATEGORY_MEDIA: 1325 return getPriorityCategoryMedia(); 1326 case PRIORITY_CATEGORY_SYSTEM: 1327 return getPriorityCategorySystem(); 1328 case PRIORITY_CATEGORY_CONVERSATIONS: 1329 return getPriorityCategoryConversations(); 1330 } 1331 return -1; 1332 } 1333 getZenPolicyVisualEffectState(@isualEffect int effect)1334 private @State int getZenPolicyVisualEffectState(@VisualEffect int effect) { 1335 switch (effect) { 1336 case VISUAL_EFFECT_FULL_SCREEN_INTENT: 1337 return getVisualEffectFullScreenIntent(); 1338 case VISUAL_EFFECT_LIGHTS: 1339 return getVisualEffectLights(); 1340 case VISUAL_EFFECT_PEEK: 1341 return getVisualEffectPeek(); 1342 case VISUAL_EFFECT_STATUS_BAR: 1343 return getVisualEffectStatusBar(); 1344 case VISUAL_EFFECT_BADGE: 1345 return getVisualEffectBadge(); 1346 case VISUAL_EFFECT_AMBIENT: 1347 return getVisualEffectAmbient(); 1348 case VISUAL_EFFECT_NOTIFICATION_LIST: 1349 return getVisualEffectNotificationList(); 1350 } 1351 return -1; 1352 } 1353 1354 /** @hide */ stateToBoolean(@tate int state, boolean defaultVal)1355 public static boolean stateToBoolean(@State int state, boolean defaultVal) { 1356 switch (state) { 1357 case STATE_ALLOW: 1358 return true; 1359 case STATE_DISALLOW: 1360 return false; 1361 default: 1362 return defaultVal; 1363 } 1364 } 1365 1366 /** @hide */ isCategoryAllowed(@riorityCategory int category, boolean defaultVal)1367 public boolean isCategoryAllowed(@PriorityCategory int category, boolean defaultVal) { 1368 return stateToBoolean(getZenPolicyPriorityCategoryState(category), defaultVal); 1369 } 1370 1371 /** @hide */ isVisualEffectAllowed(@isualEffect int effect, boolean defaultVal)1372 public boolean isVisualEffectAllowed(@VisualEffect int effect, boolean defaultVal) { 1373 return stateToBoolean(getZenPolicyVisualEffectState(effect), defaultVal); 1374 } 1375 1376 /** 1377 * Applies another policy on top of this policy. For each field, the resulting policy will have 1378 * most restrictive setting that is set of the two policies (if only one has a field set, the 1379 * result will inherit that policy's setting). 1380 * 1381 * @hide 1382 */ apply(ZenPolicy policyToApply)1383 public void apply(ZenPolicy policyToApply) { 1384 if (policyToApply == null) { 1385 return; 1386 } 1387 1388 // apply priority categories 1389 for (int category = 0; category < mPriorityCategories.size(); category++) { 1390 if (mPriorityCategories.get(category) == STATE_DISALLOW) { 1391 // if a priority category is already disallowed by the policy, cannot allow 1392 continue; 1393 } 1394 1395 @State int newState = policyToApply.mPriorityCategories.get(category); 1396 if (newState != STATE_UNSET) { 1397 mPriorityCategories.set(category, newState); 1398 1399 if (category == PRIORITY_CATEGORY_MESSAGES 1400 && mPriorityMessages < policyToApply.mPriorityMessages) { 1401 mPriorityMessages = policyToApply.mPriorityMessages; 1402 } else if (category == PRIORITY_CATEGORY_CALLS 1403 && mPriorityCalls < policyToApply.mPriorityCalls) { 1404 mPriorityCalls = policyToApply.mPriorityCalls; 1405 } else if (category == PRIORITY_CATEGORY_CONVERSATIONS 1406 && mConversationSenders < policyToApply.mConversationSenders) { 1407 mConversationSenders = policyToApply.mConversationSenders; 1408 } 1409 } 1410 } 1411 1412 // apply visual effects 1413 for (int visualEffect = 0; visualEffect < mVisualEffects.size(); visualEffect++) { 1414 if (mVisualEffects.get(visualEffect) == STATE_DISALLOW) { 1415 // if a visual effect is already disallowed by the policy, cannot allow 1416 continue; 1417 } 1418 1419 if (policyToApply.mVisualEffects.get(visualEffect) != STATE_UNSET) { 1420 mVisualEffects.set(visualEffect, policyToApply.mVisualEffects.get(visualEffect)); 1421 } 1422 } 1423 1424 // apply allowed channels -> if no channels are allowed, can't newly allow them 1425 if (mAllowChannels != CHANNEL_POLICY_NONE 1426 && policyToApply.mAllowChannels != CHANNEL_POLICY_UNSET) { 1427 mAllowChannels = policyToApply.mAllowChannels; 1428 } 1429 } 1430 1431 /** 1432 * Overwrites any policy values in this ZenPolicy with set values from newPolicy and 1433 * returns a copy of the resulting ZenPolicy. 1434 * Unlike apply(), values set in newPolicy will always be kept over pre-existing 1435 * fields. Any values in newPolicy that are not set keep their currently set values. 1436 * 1437 * @hide 1438 */ 1439 @TestApi overwrittenWith(@ullable ZenPolicy newPolicy)1440 public @NonNull ZenPolicy overwrittenWith(@Nullable ZenPolicy newPolicy) { 1441 ZenPolicy result = this.copy(); 1442 1443 if (newPolicy == null) { 1444 return result; 1445 } 1446 1447 // set priority categories 1448 for (int category = 0; category < mPriorityCategories.size(); category++) { 1449 @State int newState = newPolicy.mPriorityCategories.get(category); 1450 if (newState != STATE_UNSET) { 1451 result.mPriorityCategories.set(category, newState); 1452 1453 if (category == PRIORITY_CATEGORY_MESSAGES) { 1454 result.mPriorityMessages = newPolicy.mPriorityMessages; 1455 } else if (category == PRIORITY_CATEGORY_CALLS) { 1456 result.mPriorityCalls = newPolicy.mPriorityCalls; 1457 } else if (category == PRIORITY_CATEGORY_CONVERSATIONS) { 1458 result.mConversationSenders = newPolicy.mConversationSenders; 1459 } 1460 } 1461 } 1462 1463 // set visual effects 1464 for (int visualEffect = 0; visualEffect < mVisualEffects.size(); visualEffect++) { 1465 if (newPolicy.mVisualEffects.get(visualEffect) != STATE_UNSET) { 1466 result.mVisualEffects.set(visualEffect, newPolicy.mVisualEffects.get(visualEffect)); 1467 } 1468 } 1469 1470 // set allowed channels 1471 if (newPolicy.mAllowChannels != CHANNEL_POLICY_UNSET) { 1472 result.mAllowChannels = newPolicy.mAllowChannels; 1473 } 1474 1475 return result; 1476 } 1477 1478 /** 1479 * @hide 1480 */ dumpDebug(ProtoOutputStream proto, long fieldId)1481 public void dumpDebug(ProtoOutputStream proto, long fieldId) { 1482 final long token = proto.start(fieldId); 1483 1484 proto.write(ZenPolicyProto.REMINDERS, getPriorityCategoryReminders()); 1485 proto.write(ZenPolicyProto.EVENTS, getPriorityCategoryEvents()); 1486 proto.write(ZenPolicyProto.MESSAGES, getPriorityCategoryMessages()); 1487 proto.write(ZenPolicyProto.CALLS, getPriorityCategoryCalls()); 1488 proto.write(ZenPolicyProto.REPEAT_CALLERS, getPriorityCategoryRepeatCallers()); 1489 proto.write(ZenPolicyProto.ALARMS, getPriorityCategoryAlarms()); 1490 proto.write(ZenPolicyProto.MEDIA, getPriorityCategoryMedia()); 1491 proto.write(ZenPolicyProto.SYSTEM, getPriorityCategorySystem()); 1492 1493 proto.write(ZenPolicyProto.FULL_SCREEN_INTENT, getVisualEffectFullScreenIntent()); 1494 proto.write(ZenPolicyProto.LIGHTS, getVisualEffectLights()); 1495 proto.write(ZenPolicyProto.PEEK, getVisualEffectPeek()); 1496 proto.write(ZenPolicyProto.STATUS_BAR, getVisualEffectStatusBar()); 1497 proto.write(ZenPolicyProto.BADGE, getVisualEffectBadge()); 1498 proto.write(ZenPolicyProto.AMBIENT, getVisualEffectAmbient()); 1499 proto.write(ZenPolicyProto.NOTIFICATION_LIST, getVisualEffectNotificationList()); 1500 1501 proto.write(ZenPolicyProto.PRIORITY_MESSAGES, getPriorityMessageSenders()); 1502 proto.write(ZenPolicyProto.PRIORITY_CALLS, getPriorityCallSenders()); 1503 proto.end(token); 1504 } 1505 1506 /** 1507 * Converts a policy to a statsd proto. 1508 * @hide 1509 */ toProto()1510 public byte[] toProto() { 1511 // TODO: b/308672510 - log user-customized ZenPolicy fields to DNDPolicyProto. 1512 ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 1513 ProtoOutputStream proto = new ProtoOutputStream(bytes); 1514 1515 proto.write(DNDPolicyProto.CALLS, getPriorityCategoryCalls()); 1516 proto.write(DNDPolicyProto.REPEAT_CALLERS, getPriorityCategoryRepeatCallers()); 1517 proto.write(DNDPolicyProto.MESSAGES, getPriorityCategoryMessages()); 1518 proto.write(DNDPolicyProto.CONVERSATIONS, getPriorityCategoryConversations()); 1519 proto.write(DNDPolicyProto.REMINDERS, getPriorityCategoryReminders()); 1520 proto.write(DNDPolicyProto.EVENTS, getPriorityCategoryEvents()); 1521 proto.write(DNDPolicyProto.ALARMS, getPriorityCategoryAlarms()); 1522 proto.write(DNDPolicyProto.MEDIA, getPriorityCategoryMedia()); 1523 proto.write(DNDPolicyProto.SYSTEM, getPriorityCategorySystem()); 1524 1525 proto.write(DNDPolicyProto.FULLSCREEN, getVisualEffectFullScreenIntent()); 1526 proto.write(DNDPolicyProto.LIGHTS, getVisualEffectLights()); 1527 proto.write(DNDPolicyProto.PEEK, getVisualEffectPeek()); 1528 proto.write(DNDPolicyProto.STATUS_BAR, getVisualEffectStatusBar()); 1529 proto.write(DNDPolicyProto.BADGE, getVisualEffectBadge()); 1530 proto.write(DNDPolicyProto.AMBIENT, getVisualEffectAmbient()); 1531 proto.write(DNDPolicyProto.NOTIFICATION_LIST, getVisualEffectNotificationList()); 1532 1533 proto.write(DNDPolicyProto.ALLOW_CALLS_FROM, getPriorityCallSenders()); 1534 proto.write(DNDPolicyProto.ALLOW_MESSAGES_FROM, getPriorityMessageSenders()); 1535 proto.write(DNDPolicyProto.ALLOW_CONVERSATIONS_FROM, getPriorityConversationSenders()); 1536 proto.write(DNDPolicyProto.ALLOW_CHANNELS, getPriorityChannelsAllowed()); 1537 1538 proto.flush(); 1539 return bytes.toByteArray(); 1540 } 1541 1542 /** 1543 * Makes deep copy of this ZenPolicy. 1544 * @hide 1545 */ copy()1546 public @NonNull ZenPolicy copy() { 1547 final Parcel parcel = Parcel.obtain(); 1548 try { 1549 writeToParcel(parcel, 0); 1550 parcel.setDataPosition(0); 1551 return CREATOR.createFromParcel(parcel); 1552 } finally { 1553 parcel.recycle(); 1554 } 1555 } 1556 } 1557