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 &amp; 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 &amp; 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