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