1 /** 2 * Copyright (c) 2015, 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.app; 18 19 import static com.android.internal.util.Preconditions.checkArgument; 20 21 import android.annotation.DrawableRes; 22 import android.annotation.FlaggedApi; 23 import android.annotation.IntDef; 24 import android.annotation.NonNull; 25 import android.annotation.Nullable; 26 import android.app.NotificationManager.InterruptionFilter; 27 import android.content.ComponentName; 28 import android.net.Uri; 29 import android.os.Parcel; 30 import android.os.Parcelable; 31 import android.service.notification.Condition; 32 import android.service.notification.ZenDeviceEffects; 33 import android.service.notification.ZenPolicy; 34 import android.view.WindowInsetsController; 35 36 import java.lang.annotation.Retention; 37 import java.lang.annotation.RetentionPolicy; 38 import java.util.ArrayList; 39 import java.util.Objects; 40 41 /** 42 * Rule instance information for a zen (aka DND or Attention Management) mode. 43 */ 44 public final class AutomaticZenRule implements Parcelable { 45 /* @hide */ 46 private static final int ENABLED = 1; 47 /* @hide */ 48 private static final int DISABLED = 0; 49 50 /** 51 * Rule is of an unknown type. This is the default value if not provided by the owning app, 52 * and the value returned if the true type was added in an API level lower than the calling 53 * app's targetSdk. 54 */ 55 @FlaggedApi(Flags.FLAG_MODES_API) 56 public static final int TYPE_UNKNOWN = -1; 57 /** 58 * Rule is of a known type, but not one of the specific types. 59 */ 60 @FlaggedApi(Flags.FLAG_MODES_API) 61 public static final int TYPE_OTHER = 0; 62 /** 63 * The type for rules triggered according to a time-based schedule. 64 */ 65 @FlaggedApi(Flags.FLAG_MODES_API) 66 public static final int TYPE_SCHEDULE_TIME = 1; 67 /** 68 * The type for rules triggered by calendar events. 69 */ 70 @FlaggedApi(Flags.FLAG_MODES_API) 71 public static final int TYPE_SCHEDULE_CALENDAR = 2; 72 /** 73 * The type for rules triggered by bedtime/sleeping, like time of day, or snore detection. 74 * 75 * <p>Only the 'Wellbeing' app may own rules of this type. 76 */ 77 @FlaggedApi(Flags.FLAG_MODES_API) 78 public static final int TYPE_BEDTIME = 3; 79 /** 80 * The type for rules triggered by driving detection, like Bluetooth connections or vehicle 81 * sounds. 82 */ 83 @FlaggedApi(Flags.FLAG_MODES_API) 84 public static final int TYPE_DRIVING = 4; 85 /** 86 * The type for rules triggered by the user entering an immersive activity, like opening an app 87 * using {@link WindowInsetsController#hide(int)}. 88 */ 89 @FlaggedApi(Flags.FLAG_MODES_API) 90 public static final int TYPE_IMMERSIVE = 5; 91 /** 92 * The type for rules that have a {@link ZenPolicy} that implies that the 93 * device should not make sound and potentially hide some visual effects; may be triggered 94 * when entering a location where silence is requested, like a theater. 95 */ 96 @FlaggedApi(Flags.FLAG_MODES_API) 97 public static final int TYPE_THEATER = 6; 98 /** 99 * The type for rules created and managed by a device owner. These rules may not be fully 100 * editable by the device user. 101 * 102 * <p>Only a 'Device Owner' app may own rules of this type. 103 */ 104 @FlaggedApi(Flags.FLAG_MODES_API) 105 public static final int TYPE_MANAGED = 7; 106 107 /** @hide */ 108 @IntDef(prefix = { "TYPE_" }, value = { 109 TYPE_UNKNOWN, TYPE_OTHER, TYPE_SCHEDULE_TIME, TYPE_SCHEDULE_CALENDAR, TYPE_BEDTIME, 110 TYPE_DRIVING, TYPE_IMMERSIVE, TYPE_THEATER, TYPE_MANAGED 111 }) 112 @Retention(RetentionPolicy.SOURCE) 113 public @interface Type {} 114 115 /** 116 * Enum for the user-modifiable fields in this object. 117 * @hide 118 */ 119 @IntDef(flag = true, prefix = { "FIELD_" }, value = { 120 FIELD_NAME, 121 FIELD_INTERRUPTION_FILTER, 122 FIELD_ICON 123 }) 124 @Retention(RetentionPolicy.SOURCE) 125 public @interface ModifiableField {} 126 127 /** 128 * @hide 129 */ 130 @FlaggedApi(Flags.FLAG_MODES_API) 131 public static final int FIELD_NAME = 1 << 0; 132 /** 133 * @hide 134 */ 135 @FlaggedApi(Flags.FLAG_MODES_API) 136 public static final int FIELD_INTERRUPTION_FILTER = 1 << 1; 137 /** 138 * @hide 139 */ 140 @FlaggedApi(Flags.FLAG_MODES_API) 141 public static final int FIELD_ICON = 1 << 2; 142 143 private boolean enabled; 144 private String name; 145 private @InterruptionFilter int interruptionFilter; 146 private Uri conditionId; 147 private ComponentName owner; 148 private ComponentName configurationActivity; 149 private long creationTime; 150 private ZenPolicy mZenPolicy; 151 private ZenDeviceEffects mDeviceEffects; 152 // TODO: b/310620812 - Remove this once FLAG_MODES_API is inlined. 153 private boolean mModified = false; 154 private String mPkg; 155 private int mType = Flags.modesApi() ? TYPE_UNKNOWN : 0; 156 private int mIconResId; 157 private String mTriggerDescription; 158 private boolean mAllowManualInvocation; 159 160 /** 161 * The maximum string length for any string contained in this automatic zen rule. This pertains 162 * both to fields in the rule itself (such as its name) and items with sub-fields. 163 * @hide 164 */ 165 public static final int MAX_STRING_LENGTH = 1000; 166 167 /** 168 * The maximum string length for the trigger description rule, given UI constraints. 169 * @hide 170 */ 171 public static final int MAX_DESC_LENGTH = 150; 172 173 /** 174 * Creates an automatic zen rule. 175 * 176 * @param name The name of the rule. 177 * @param owner The Condition Provider service that owns this rule. 178 * @param interruptionFilter The interruption filter defines which notifications are allowed to 179 * interrupt the user (e.g. via sound & vibration) while this rule 180 * is active. 181 * @param enabled Whether the rule is enabled. 182 * 183 * @deprecated Use {@link AutomaticZenRule.Builder} to construct an {@link AutomaticZenRule}. 184 */ 185 @Deprecated AutomaticZenRule(String name, ComponentName owner, Uri conditionId, int interruptionFilter, boolean enabled)186 public AutomaticZenRule(String name, ComponentName owner, Uri conditionId, 187 int interruptionFilter, boolean enabled) { 188 this(name, owner, null, conditionId, null, interruptionFilter, enabled); 189 } 190 191 /** 192 * Creates an automatic zen rule. 193 * 194 * <p>Note: Prefer {@link AutomaticZenRule.Builder} to construct an {@link AutomaticZenRule}. 195 * 196 * @param name The name of the rule. 197 * @param owner The Condition Provider service that owns this rule. This can be null if you're 198 * using {@link NotificationManager#setAutomaticZenRuleState(String, Condition)} 199 * instead of {@link android.service.notification.ConditionProviderService}. 200 * @param configurationActivity An activity that handles 201 * {@link NotificationManager#ACTION_AUTOMATIC_ZEN_RULE} that shows 202 * the user 203 * more information about this rule and/or allows them to 204 * configure it. This is required if you are not using a 205 * {@link android.service.notification.ConditionProviderService}. 206 * If you are, it overrides the information specified in your 207 * manifest. 208 * @param conditionId A representation of the state that should cause your app to apply the 209 * given interruption filter. 210 * @param interruptionFilter The interruption filter defines which notifications are allowed to 211 * interrupt the user (e.g. via sound & vibration) while this rule 212 * is active. 213 * @param policy The policy defines which notifications are allowed to interrupt the user 214 * while this rule is active. This overrides the global policy while this rule is 215 * action ({@link Condition#STATE_TRUE}). 216 * @param enabled Whether the rule is enabled. 217 */ AutomaticZenRule(@onNull String name, @Nullable ComponentName owner, @Nullable ComponentName configurationActivity, @NonNull Uri conditionId, @Nullable ZenPolicy policy, int interruptionFilter, boolean enabled)218 public AutomaticZenRule(@NonNull String name, @Nullable ComponentName owner, 219 @Nullable ComponentName configurationActivity, @NonNull Uri conditionId, 220 @Nullable ZenPolicy policy, int interruptionFilter, boolean enabled) { 221 this.name = getTrimmedString(name); 222 this.owner = getTrimmedComponentName(owner); 223 this.configurationActivity = getTrimmedComponentName(configurationActivity); 224 this.conditionId = getTrimmedUri(conditionId); 225 this.interruptionFilter = interruptionFilter; 226 this.enabled = enabled; 227 this.mZenPolicy = policy; 228 } 229 230 /** 231 * @hide 232 */ 233 // TODO: b/310620812 - Remove when the flag is inlined (all system callers should use Builder). AutomaticZenRule(String name, ComponentName owner, ComponentName configurationActivity, Uri conditionId, ZenPolicy policy, int interruptionFilter, boolean enabled, long creationTime)234 public AutomaticZenRule(String name, ComponentName owner, ComponentName configurationActivity, 235 Uri conditionId, ZenPolicy policy, int interruptionFilter, boolean enabled, 236 long creationTime) { 237 this(name, owner, configurationActivity, conditionId, policy, interruptionFilter, enabled); 238 this.creationTime = creationTime; 239 } 240 AutomaticZenRule(Parcel source)241 public AutomaticZenRule(Parcel source) { 242 enabled = source.readInt() == ENABLED; 243 if (source.readInt() == ENABLED) { 244 name = getTrimmedString(source.readString()); 245 } 246 interruptionFilter = source.readInt(); 247 conditionId = getTrimmedUri(source.readParcelable(null, android.net.Uri.class)); 248 owner = getTrimmedComponentName( 249 source.readParcelable(null, android.content.ComponentName.class)); 250 configurationActivity = getTrimmedComponentName( 251 source.readParcelable(null, android.content.ComponentName.class)); 252 creationTime = source.readLong(); 253 mZenPolicy = source.readParcelable(null, ZenPolicy.class); 254 mModified = source.readInt() == ENABLED; 255 mPkg = source.readString(); 256 if (Flags.modesApi()) { 257 mDeviceEffects = source.readParcelable(null, ZenDeviceEffects.class); 258 mAllowManualInvocation = source.readBoolean(); 259 mIconResId = source.readInt(); 260 mTriggerDescription = getTrimmedString(source.readString(), MAX_DESC_LENGTH); 261 mType = source.readInt(); 262 } 263 } 264 265 /** 266 * Returns the {@link ComponentName} of the condition provider service that owns this rule. 267 */ getOwner()268 public ComponentName getOwner() { 269 return owner; 270 } 271 272 /** 273 * Returns the {@link ComponentName} of the activity that shows configuration options 274 * for this rule. 275 */ getConfigurationActivity()276 public @Nullable ComponentName getConfigurationActivity() { 277 return configurationActivity; 278 } 279 280 /** 281 * Returns the representation of the state that causes this rule to become active. 282 */ getConditionId()283 public Uri getConditionId() { 284 return conditionId; 285 } 286 287 /** 288 * Returns the interruption filter that is applied when this rule is active. 289 */ getInterruptionFilter()290 public int getInterruptionFilter() { 291 return interruptionFilter; 292 } 293 294 /** 295 * Returns the name of this rule. 296 */ getName()297 public String getName() { 298 return name; 299 } 300 301 /** 302 * Returns whether this rule is enabled. 303 */ isEnabled()304 public boolean isEnabled() { 305 return enabled; 306 } 307 308 /** 309 * Returns whether this rule's name has been modified by the user. 310 * @hide 311 */ 312 // TODO: b/310620812 - Consider removing completely. Seems not be used anywhere except tests. isModified()313 public boolean isModified() { 314 return mModified; 315 } 316 317 /** 318 * Gets the zen policy. 319 */ 320 @Nullable getZenPolicy()321 public ZenPolicy getZenPolicy() { 322 return mZenPolicy == null ? null : this.mZenPolicy.copy(); 323 } 324 325 /** Gets the {@link ZenDeviceEffects} of this rule. */ 326 @Nullable 327 @FlaggedApi(Flags.FLAG_MODES_API) getDeviceEffects()328 public ZenDeviceEffects getDeviceEffects() { 329 return mDeviceEffects; 330 } 331 332 /** 333 * Returns the time this rule was created, represented as milliseconds since the epoch. 334 */ getCreationTime()335 public long getCreationTime() { 336 return creationTime; 337 } 338 339 /** 340 * Sets the representation of the state that causes this rule to become active. 341 */ setConditionId(Uri conditionId)342 public void setConditionId(Uri conditionId) { 343 this.conditionId = getTrimmedUri(conditionId); 344 } 345 346 /** 347 * Sets the interruption filter that is applied when this rule is active. 348 * @param interruptionFilter The do not disturb mode to enter when this rule is active. 349 */ setInterruptionFilter(@nterruptionFilter int interruptionFilter)350 public void setInterruptionFilter(@InterruptionFilter int interruptionFilter) { 351 this.interruptionFilter = interruptionFilter; 352 } 353 354 /** 355 * Sets the name of this rule. 356 */ setName(String name)357 public void setName(String name) { 358 this.name = getTrimmedString(name); 359 } 360 361 /** 362 * Enables this rule. 363 */ setEnabled(boolean enabled)364 public void setEnabled(boolean enabled) { 365 this.enabled = enabled; 366 } 367 368 /** 369 * Sets modified state of this rule. 370 * @hide 371 */ setModified(boolean modified)372 public void setModified(boolean modified) { 373 this.mModified = modified; 374 } 375 376 /** 377 * Sets the zen policy. 378 * 379 * <p>When updating an existing rule via {@link NotificationManager#updateAutomaticZenRule}, 380 * a {@code null} value here means the previous policy is retained. 381 */ setZenPolicy(@ullable ZenPolicy zenPolicy)382 public void setZenPolicy(@Nullable ZenPolicy zenPolicy) { 383 this.mZenPolicy = (zenPolicy == null ? null : zenPolicy.copy()); 384 } 385 386 /** 387 * Sets the {@link ZenDeviceEffects} associated to this rule. Device effects specify changes to 388 * the device behavior that should apply while the rule is active, but are not directly related 389 * to suppressing notifications (for example: disabling always-on display). 390 * 391 * <p>When updating an existing rule via {@link NotificationManager#updateAutomaticZenRule}, 392 * a {@code null} value here means the previous set of effects is retained. 393 */ 394 @FlaggedApi(Flags.FLAG_MODES_API) setDeviceEffects(@ullable ZenDeviceEffects deviceEffects)395 public void setDeviceEffects(@Nullable ZenDeviceEffects deviceEffects) { 396 mDeviceEffects = deviceEffects; 397 } 398 399 /** 400 * Sets the configuration activity - an activity that handles 401 * {@link NotificationManager#ACTION_AUTOMATIC_ZEN_RULE} that shows the user more information 402 * about this rule and/or allows them to configure it. This is required to be non-null for rules 403 * that are not backed by a {@link android.service.notification.ConditionProviderService}. 404 * 405 * <p>This is exclusive with the {@code owner} supplied in the constructor; rules where a 406 * configuration activity is set will not use the 407 * {@link android.service.notification.ConditionProviderService} supplied there to determine 408 * whether the rule should be active. 409 */ setConfigurationActivity(@ullable ComponentName componentName)410 public void setConfigurationActivity(@Nullable ComponentName componentName) { 411 this.configurationActivity = getTrimmedComponentName(componentName); 412 } 413 414 /** 415 * @hide 416 */ setPackageName(String pkgName)417 public void setPackageName(String pkgName) { 418 mPkg = pkgName; 419 } 420 421 /** 422 * @hide 423 */ getPackageName()424 public String getPackageName() { 425 return mPkg; 426 } 427 428 /** 429 * Gets the type of the rule. 430 */ 431 @FlaggedApi(Flags.FLAG_MODES_API) getType()432 public @Type int getType() { 433 return mType; 434 } 435 436 /** 437 * Sets the type of the rule. 438 * @hide 439 */ 440 @FlaggedApi(Flags.FLAG_MODES_API) setType(@ype int type)441 public void setType(@Type int type) { 442 mType = checkValidType(type); 443 } 444 445 /** 446 * Gets the user visible description of when this rule is active 447 * (see {@link Condition#STATE_TRUE}). 448 */ 449 @FlaggedApi(Flags.FLAG_MODES_API) getTriggerDescription()450 public @Nullable String getTriggerDescription() { 451 return mTriggerDescription; 452 } 453 454 /** 455 * Sets a user visible description of when this rule will be active 456 * (see {@link Condition#STATE_TRUE}). 457 * 458 * A description should be a (localized) string like "Mon-Fri, 9pm-7am" or 459 * "When connected to [Car Name]". 460 * @hide 461 */ 462 @FlaggedApi(Flags.FLAG_MODES_API) setTriggerDescription(@ullable String triggerDescription)463 public void setTriggerDescription(@Nullable String triggerDescription) { 464 mTriggerDescription = triggerDescription; 465 } 466 467 /** 468 * Gets the resource id of the drawable icon for this rule. 469 */ 470 @FlaggedApi(Flags.FLAG_MODES_API) getIconResId()471 public @DrawableRes int getIconResId() { 472 return mIconResId; 473 } 474 475 /** 476 * Sets a resource id of a tintable vector drawable representing the rule in image form. 477 * @hide 478 */ 479 @FlaggedApi(Flags.FLAG_MODES_API) setIconResId(int iconResId)480 public void setIconResId(int iconResId) { 481 mIconResId = iconResId; 482 } 483 484 /** 485 * Gets whether this rule can be manually activated by the user even when the triggering 486 * condition for the rule is not met. 487 */ 488 @FlaggedApi(Flags.FLAG_MODES_API) isManualInvocationAllowed()489 public boolean isManualInvocationAllowed() { 490 return mAllowManualInvocation; 491 } 492 493 /** 494 * Sets whether this rule can be manually activated by the user even when the triggering 495 * condition for the rule is not met. 496 * @hide 497 */ 498 @FlaggedApi(Flags.FLAG_MODES_API) setManualInvocationAllowed(boolean allowManualInvocation)499 public void setManualInvocationAllowed(boolean allowManualInvocation) { 500 mAllowManualInvocation = allowManualInvocation; 501 } 502 503 /** @hide */ 504 @FlaggedApi(Flags.FLAG_MODES_API) validate()505 public void validate() { 506 if (Flags.modesApi()) { 507 checkValidType(mType); 508 if (mDeviceEffects != null) { 509 mDeviceEffects.validate(); 510 } 511 } 512 } 513 514 @FlaggedApi(Flags.FLAG_MODES_API) 515 @Type checkValidType(@ype int type)516 private static int checkValidType(@Type int type) { 517 checkArgument(type >= TYPE_UNKNOWN && type <= TYPE_MANAGED, 518 "Rule type must be one of TYPE_UNKNOWN, TYPE_OTHER, TYPE_SCHEDULE_TIME, " 519 + "TYPE_SCHEDULE_CALENDAR, TYPE_BEDTIME, TYPE_DRIVING, TYPE_IMMERSIVE, " 520 + "TYPE_THEATER, or TYPE_MANAGED"); 521 return type; 522 } 523 524 @Override describeContents()525 public int describeContents() { 526 return 0; 527 } 528 529 @Override writeToParcel(Parcel dest, int flags)530 public void writeToParcel(Parcel dest, int flags) { 531 dest.writeInt(enabled ? ENABLED : DISABLED); 532 if (name != null) { 533 dest.writeInt(1); 534 dest.writeString(name); 535 } else { 536 dest.writeInt(0); 537 } 538 dest.writeInt(interruptionFilter); 539 dest.writeParcelable(conditionId, 0); 540 dest.writeParcelable(owner, 0); 541 dest.writeParcelable(configurationActivity, 0); 542 dest.writeLong(creationTime); 543 dest.writeParcelable(mZenPolicy, 0); 544 dest.writeInt(mModified ? ENABLED : DISABLED); 545 dest.writeString(mPkg); 546 if (Flags.modesApi()) { 547 dest.writeParcelable(mDeviceEffects, 0); 548 dest.writeBoolean(mAllowManualInvocation); 549 dest.writeInt(mIconResId); 550 dest.writeString(mTriggerDescription); 551 dest.writeInt(mType); 552 } 553 } 554 555 @Override toString()556 public String toString() { 557 StringBuilder sb = new StringBuilder(AutomaticZenRule.class.getSimpleName()).append('[') 558 .append("enabled=").append(enabled) 559 .append(",name=").append(name) 560 .append(",interruptionFilter=").append(interruptionFilter) 561 .append(",pkg=").append(mPkg) 562 .append(",conditionId=").append(conditionId) 563 .append(",owner=").append(owner) 564 .append(",configActivity=").append(configurationActivity) 565 .append(",creationTime=").append(creationTime) 566 .append(",mZenPolicy=").append(mZenPolicy); 567 568 if (Flags.modesApi()) { 569 sb.append(",deviceEffects=").append(mDeviceEffects) 570 .append(",allowManualInvocation=").append(mAllowManualInvocation) 571 .append(",iconResId=").append(mIconResId) 572 .append(",triggerDescription=").append(mTriggerDescription) 573 .append(",type=").append(mType); 574 } 575 576 return sb.append(']').toString(); 577 } 578 579 /** @hide */ fieldsToString(@odifiableField int bitmask)580 public static String fieldsToString(@ModifiableField int bitmask) { 581 ArrayList<String> modified = new ArrayList<>(); 582 if ((bitmask & FIELD_NAME) != 0) { 583 modified.add("FIELD_NAME"); 584 } 585 if ((bitmask & FIELD_INTERRUPTION_FILTER) != 0) { 586 modified.add("FIELD_INTERRUPTION_FILTER"); 587 } 588 if ((bitmask & FIELD_ICON) != 0) { 589 modified.add("FIELD_ICON"); 590 } 591 return "{" + String.join(",", modified) + "}"; 592 } 593 594 @Override equals(@ullable Object o)595 public boolean equals(@Nullable Object o) { 596 if (!(o instanceof AutomaticZenRule)) return false; 597 if (o == this) return true; 598 final AutomaticZenRule other = (AutomaticZenRule) o; 599 boolean finalEquals = other.enabled == enabled 600 && other.mModified == mModified 601 && Objects.equals(other.name, name) 602 && other.interruptionFilter == interruptionFilter 603 && Objects.equals(other.conditionId, conditionId) 604 && Objects.equals(other.owner, owner) 605 && Objects.equals(other.mZenPolicy, mZenPolicy) 606 && Objects.equals(other.configurationActivity, configurationActivity) 607 && Objects.equals(other.mPkg, mPkg) 608 && other.creationTime == creationTime; 609 if (Flags.modesApi()) { 610 return finalEquals 611 && Objects.equals(other.mDeviceEffects, mDeviceEffects) 612 && other.mAllowManualInvocation == mAllowManualInvocation 613 && other.mIconResId == mIconResId 614 && Objects.equals(other.mTriggerDescription, mTriggerDescription) 615 && other.mType == mType; 616 } 617 return finalEquals; 618 } 619 620 @Override hashCode()621 public int hashCode() { 622 if (Flags.modesApi()) { 623 return Objects.hash(enabled, name, interruptionFilter, conditionId, owner, 624 configurationActivity, mZenPolicy, mDeviceEffects, mModified, creationTime, 625 mPkg, mAllowManualInvocation, mIconResId, mTriggerDescription, mType); 626 } 627 return Objects.hash(enabled, name, interruptionFilter, conditionId, owner, 628 configurationActivity, mZenPolicy, mModified, creationTime, mPkg); 629 } 630 631 public static final @android.annotation.NonNull Parcelable.Creator<AutomaticZenRule> CREATOR 632 = new Parcelable.Creator<AutomaticZenRule>() { 633 @Override 634 public AutomaticZenRule createFromParcel(Parcel source) { 635 return new AutomaticZenRule(source); 636 } 637 @Override 638 public AutomaticZenRule[] newArray(int size) { 639 return new AutomaticZenRule[size]; 640 } 641 }; 642 643 /** 644 * If the package or class name of the provided ComponentName are longer than MAX_STRING_LENGTH, 645 * return a trimmed version that truncates each of the package and class name at the max length. 646 */ getTrimmedComponentName(ComponentName cn)647 private static ComponentName getTrimmedComponentName(ComponentName cn) { 648 if (cn == null) return null; 649 return new ComponentName(getTrimmedString(cn.getPackageName()), 650 getTrimmedString(cn.getClassName())); 651 } 652 653 /** 654 * Returns a truncated copy of the string if the string is longer than MAX_STRING_LENGTH. 655 */ getTrimmedString(String input)656 private static String getTrimmedString(String input) { 657 return getTrimmedString(input, MAX_STRING_LENGTH); 658 } 659 getTrimmedString(String input, int length)660 private static String getTrimmedString(String input, int length) { 661 if (input != null && input.length() > length) { 662 return input.substring(0, length); 663 } 664 return input; 665 } 666 667 /** 668 * Returns a truncated copy of the Uri by trimming the string representation to the maximum 669 * string length. 670 */ getTrimmedUri(Uri input)671 private static Uri getTrimmedUri(Uri input) { 672 if (input != null && input.toString().length() > MAX_STRING_LENGTH) { 673 return Uri.parse(getTrimmedString(input.toString())); 674 } 675 return input; 676 } 677 678 @FlaggedApi(Flags.FLAG_MODES_API) 679 public static final class Builder { 680 private String mName; 681 private ComponentName mOwner; 682 private Uri mConditionId; 683 private int mInterruptionFilter = NotificationManager.INTERRUPTION_FILTER_PRIORITY; 684 private boolean mEnabled = true; 685 private ComponentName mConfigurationActivity = null; 686 private ZenPolicy mPolicy = null; 687 private ZenDeviceEffects mDeviceEffects = null; 688 private int mType = TYPE_UNKNOWN; 689 private String mDescription; 690 private int mIconResId; 691 private boolean mAllowManualInvocation; 692 private long mCreationTime; 693 private String mPkg; 694 Builder(@onNull AutomaticZenRule rule)695 public Builder(@NonNull AutomaticZenRule rule) { 696 mName = rule.getName(); 697 mOwner = rule.getOwner(); 698 mConditionId = rule.getConditionId(); 699 mInterruptionFilter = rule.getInterruptionFilter(); 700 mEnabled = rule.isEnabled(); 701 mConfigurationActivity = rule.getConfigurationActivity(); 702 mPolicy = rule.getZenPolicy(); 703 mDeviceEffects = rule.getDeviceEffects(); 704 mType = rule.getType(); 705 mDescription = rule.getTriggerDescription(); 706 mIconResId = rule.getIconResId(); 707 mAllowManualInvocation = rule.isManualInvocationAllowed(); 708 mCreationTime = rule.getCreationTime(); 709 mPkg = rule.getPackageName(); 710 } 711 Builder(@onNull String name, @NonNull Uri conditionId)712 public Builder(@NonNull String name, @NonNull Uri conditionId) { 713 mName = Objects.requireNonNull(name); 714 mConditionId = Objects.requireNonNull(conditionId); 715 } 716 717 /** 718 * Sets the name of this rule. 719 */ setName(@onNull String name)720 public @NonNull Builder setName(@NonNull String name) { 721 mName = name; 722 return this; 723 } 724 725 /** 726 * Sets the component name of the 727 * {@link android.service.notification.ConditionProviderService} that manages this rule 728 * (but note that {@link android.service.notification.ConditionProviderService} is 729 * deprecated in favor of using {@link NotificationManager#setAutomaticZenRuleState} to 730 * notify the system about the state of your rule). 731 * 732 * <p>This is exclusive with {@link #setConfigurationActivity}; rules where a configuration 733 * activity is set will not use the component set here to determine whether the rule 734 * should be active. 735 */ setOwner(@ullable ComponentName owner)736 public @NonNull Builder setOwner(@Nullable ComponentName owner) { 737 mOwner = owner; 738 return this; 739 } 740 741 /** 742 * Sets the representation of the state that causes this rule to become active. 743 */ setConditionId(@onNull Uri conditionId)744 public @NonNull Builder setConditionId(@NonNull Uri conditionId) { 745 mConditionId = conditionId; 746 return this; 747 } 748 749 /** 750 * Sets the interruption filter that is applied when this rule is active. 751 */ setInterruptionFilter( @nterruptionFilter int interruptionFilter)752 public @NonNull Builder setInterruptionFilter( 753 @InterruptionFilter int interruptionFilter) { 754 mInterruptionFilter = interruptionFilter; 755 return this; 756 } 757 758 /** 759 * Enables this rule. Rules are enabled by default. 760 */ setEnabled(boolean enabled)761 public @NonNull Builder setEnabled(boolean enabled) { 762 mEnabled = enabled; 763 return this; 764 } 765 766 /** 767 * Sets the configuration activity - an activity that handles 768 * {@link NotificationManager#ACTION_AUTOMATIC_ZEN_RULE} that shows the user more 769 * information about this rule and/or allows them to configure it. This is required to be 770 * non-null for rules that are not backed by a 771 * {@link android.service.notification.ConditionProviderService}. 772 * 773 * <p>This is exclusive with {@link #setOwner}; rules where a configuration 774 * activity is set will not use the 775 * {@link android.service.notification.ConditionProviderService} supplied there to determine 776 * whether the rule should be active. 777 */ setConfigurationActivity( @ullable ComponentName configurationActivity)778 public @NonNull Builder setConfigurationActivity( 779 @Nullable ComponentName configurationActivity) { 780 mConfigurationActivity = configurationActivity; 781 return this; 782 } 783 784 /** 785 * Sets the zen policy. 786 * 787 * <p>When updating an existing rule via {@link NotificationManager#updateAutomaticZenRule}, 788 * a {@code null} value here means the previous policy is retained. 789 */ setZenPolicy(@ullable ZenPolicy policy)790 public @NonNull Builder setZenPolicy(@Nullable ZenPolicy policy) { 791 mPolicy = policy; 792 return this; 793 } 794 795 /** 796 * Sets the {@link ZenDeviceEffects} associated to this rule. Device effects specify changes 797 * to the device behavior that should apply while the rule is active, but are not directly 798 * related to suppressing notifications (for example: disabling always-on display). 799 * 800 * <p>When updating an existing rule via {@link NotificationManager#updateAutomaticZenRule}, 801 * a {@code null} value here means the previous set of effects is retained. 802 */ 803 @NonNull setDeviceEffects(@ullable ZenDeviceEffects deviceEffects)804 public Builder setDeviceEffects(@Nullable ZenDeviceEffects deviceEffects) { 805 mDeviceEffects = deviceEffects; 806 return this; 807 } 808 809 /** 810 * Sets the type of the rule. 811 */ setType(@ype int type)812 public @NonNull Builder setType(@Type int type) { 813 mType = checkValidType(type); 814 return this; 815 } 816 817 /** 818 * Sets a user visible description of when this rule will be active 819 * (see {@link Condition#STATE_TRUE}). 820 * 821 * <p>A description should be a (localized) string like "Mon-Fri, 9pm-7am" or 822 * "When connected to [Car Name]". 823 */ setTriggerDescription(@ullable String description)824 public @NonNull Builder setTriggerDescription(@Nullable String description) { 825 mDescription = description; 826 return this; 827 } 828 829 /** 830 * Sets a resource id of a tintable vector drawable representing the rule in image form. 831 */ setIconResId(@rawableRes int iconResId)832 public @NonNull Builder setIconResId(@DrawableRes int iconResId) { 833 mIconResId = iconResId; 834 return this; 835 } 836 837 /** 838 * Sets whether this rule can be manually activated by the user even when the triggering 839 * condition for the rule is not met. 840 */ setManualInvocationAllowed(boolean allowManualInvocation)841 public @NonNull Builder setManualInvocationAllowed(boolean allowManualInvocation) { 842 mAllowManualInvocation = allowManualInvocation; 843 return this; 844 } 845 846 /** 847 * Sets the time at which this rule was created, in milliseconds since epoch 848 * @hide 849 */ setCreationTime(long creationTime)850 public @NonNull Builder setCreationTime(long creationTime) { 851 mCreationTime = creationTime; 852 return this; 853 } 854 855 /** 856 * Sets the package that owns this rule 857 * @hide 858 */ setPackage(@onNull String pkg)859 public @NonNull Builder setPackage(@NonNull String pkg) { 860 mPkg = pkg; 861 return this; 862 } 863 build()864 public @NonNull AutomaticZenRule build() { 865 AutomaticZenRule rule = new AutomaticZenRule(mName, mOwner, mConfigurationActivity, 866 mConditionId, mPolicy, mInterruptionFilter, mEnabled); 867 rule.mDeviceEffects = mDeviceEffects; 868 rule.creationTime = mCreationTime; 869 rule.mType = mType; 870 rule.mTriggerDescription = mDescription; 871 rule.mIconResId = mIconResId; 872 rule.mAllowManualInvocation = mAllowManualInvocation; 873 rule.setPackageName(mPkg); 874 875 return rule; 876 } 877 } 878 } 879