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