1 /**
2  * Copyright (c) 2014, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.service.notification;
18 
19 import android.annotation.IntDef;
20 import android.content.Context;
21 import android.net.Uri;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 import android.util.proto.ProtoOutputStream;
25 
26 import java.lang.annotation.Retention;
27 import java.lang.annotation.RetentionPolicy;
28 import java.util.Objects;
29 
30 /**
31  * The current condition of an {@link android.app.AutomaticZenRule}, provided by the
32  * app that owns the rule. Used to tell the system to enter Do Not
33  * Disturb mode and request that the system exit Do Not Disturb mode.
34  */
35 public final class Condition implements Parcelable {
36 
37     public static final String SCHEME = "condition";
38 
39     /** @hide */
40     @IntDef(prefix = { "STATE_" }, value = {
41             STATE_FALSE,
42             STATE_TRUE,
43             STATE_UNKNOWN,
44             STATE_ERROR
45     })
46     @Retention(RetentionPolicy.SOURCE)
47     public @interface State {}
48 
49     /**
50      * Indicates that Do Not Disturb should be turned off. Note that all Conditions from all
51      * {@link android.app.AutomaticZenRule} providers must be off for Do Not Disturb to be turned
52      * off on the device.
53      */
54     public static final int STATE_FALSE = 0;
55     /**
56      * Indicates that Do Not Disturb should be turned on.
57      */
58     public static final int STATE_TRUE = 1;
59 
60     public static final int STATE_UNKNOWN = 2;
61     public static final int STATE_ERROR = 3;
62 
63     public static final int FLAG_RELEVANT_NOW = 1 << 0;
64     public static final int FLAG_RELEVANT_ALWAYS = 1 << 1;
65 
66     /**
67      * The URI representing the rule being updated.
68      * See {@link android.app.AutomaticZenRule#getConditionId()}.
69      */
70     public final Uri id;
71 
72     /**
73      * A summary of what the rule encoded in {@link #id} means when it is enabled. User visible
74      * if the state of the condition is {@link #STATE_TRUE}.
75      */
76     public final String summary;
77 
78     public final String line1;
79     public final String line2;
80 
81     /**
82      * The state of this condition. {@link #STATE_TRUE} will enable Do Not Disturb mode.
83      * {@link #STATE_FALSE} will turn Do Not Disturb off for this rule. Note that Do Not Disturb
84      * might still be enabled globally if other conditions are in a {@link #STATE_TRUE} state.
85      */
86     @State
87     public final int state;
88 
89     public final int flags;
90     public final int icon;
91 
92     /**
93      * An object representing the current state of a {@link android.app.AutomaticZenRule}.
94      * @param id the {@link android.app.AutomaticZenRule#getConditionId()} of the zen rule
95      * @param summary a user visible description of the rule state.
96      */
Condition(Uri id, String summary, int state)97     public Condition(Uri id, String summary, int state) {
98         this(id, summary, "", "", -1, state, FLAG_RELEVANT_ALWAYS);
99     }
100 
Condition(Uri id, String summary, String line1, String line2, int icon, int state, int flags)101     public Condition(Uri id, String summary, String line1, String line2, int icon,
102             int state, int flags) {
103         if (id == null) throw new IllegalArgumentException("id is required");
104         if (summary == null) throw new IllegalArgumentException("summary is required");
105         if (!isValidState(state)) throw new IllegalArgumentException("state is invalid: " + state);
106         this.id = id;
107         this.summary = summary;
108         this.line1 = line1;
109         this.line2 = line2;
110         this.icon = icon;
111         this.state = state;
112         this.flags = flags;
113     }
114 
Condition(Parcel source)115     public Condition(Parcel source) {
116         this((Uri)source.readParcelable(Condition.class.getClassLoader()),
117                 source.readString(),
118                 source.readString(),
119                 source.readString(),
120                 source.readInt(),
121                 source.readInt(),
122                 source.readInt());
123     }
124 
isValidState(int state)125     private static boolean isValidState(int state) {
126         return state >= STATE_FALSE && state <= STATE_ERROR;
127     }
128 
129     @Override
writeToParcel(Parcel dest, int flags)130     public void writeToParcel(Parcel dest, int flags) {
131         dest.writeParcelable(id, 0);
132         dest.writeString(summary);
133         dest.writeString(line1);
134         dest.writeString(line2);
135         dest.writeInt(icon);
136         dest.writeInt(state);
137         dest.writeInt(this.flags);
138     }
139 
140     @Override
toString()141     public String toString() {
142         return new StringBuilder(Condition.class.getSimpleName()).append('[')
143                 .append("state=").append(stateToString(state))
144                 .append(",id=").append(id)
145                 .append(",summary=").append(summary)
146                 .append(",line1=").append(line1)
147                 .append(",line2=").append(line2)
148                 .append(",icon=").append(icon)
149                 .append(",flags=").append(flags)
150                 .append(']').toString();
151     }
152 
153     /** @hide */
writeToProto(ProtoOutputStream proto, long fieldId)154     public void writeToProto(ProtoOutputStream proto, long fieldId) {
155         final long token = proto.start(fieldId);
156 
157         // id is guaranteed not to be null.
158         proto.write(ConditionProto.ID, id.toString());
159         proto.write(ConditionProto.SUMMARY, summary);
160         proto.write(ConditionProto.LINE_1, line1);
161         proto.write(ConditionProto.LINE_2, line2);
162         proto.write(ConditionProto.ICON, icon);
163         proto.write(ConditionProto.STATE, state);
164         proto.write(ConditionProto.FLAGS, flags);
165 
166         proto.end(token);
167     }
168 
stateToString(int state)169     public static String stateToString(int state) {
170         if (state == STATE_FALSE) return "STATE_FALSE";
171         if (state == STATE_TRUE) return "STATE_TRUE";
172         if (state == STATE_UNKNOWN) return "STATE_UNKNOWN";
173         if (state == STATE_ERROR) return "STATE_ERROR";
174         throw new IllegalArgumentException("state is invalid: " + state);
175     }
176 
relevanceToString(int flags)177     public static String relevanceToString(int flags) {
178         final boolean now = (flags & FLAG_RELEVANT_NOW) != 0;
179         final boolean always = (flags & FLAG_RELEVANT_ALWAYS) != 0;
180         if (!now && !always) return "NONE";
181         if (now && always) return "NOW, ALWAYS";
182         return now ? "NOW" : "ALWAYS";
183     }
184 
185     @Override
equals(Object o)186     public boolean equals(Object o) {
187         if (!(o instanceof Condition)) return false;
188         if (o == this) return true;
189         final Condition other = (Condition) o;
190         return Objects.equals(other.id, id)
191                 && Objects.equals(other.summary, summary)
192                 && Objects.equals(other.line1, line1)
193                 && Objects.equals(other.line2, line2)
194                 && other.icon == icon
195                 && other.state == state
196                 && other.flags == flags;
197     }
198 
199     @Override
hashCode()200     public int hashCode() {
201         return Objects.hash(id, summary, line1, line2, icon, state, flags);
202     }
203 
204     @Override
describeContents()205     public int describeContents() {
206         return 0;
207     }
208 
copy()209     public Condition copy() {
210         final Parcel parcel = Parcel.obtain();
211         try {
212             writeToParcel(parcel, 0);
213             parcel.setDataPosition(0);
214             return new Condition(parcel);
215         } finally {
216             parcel.recycle();
217         }
218     }
219 
newId(Context context)220     public static Uri.Builder newId(Context context) {
221         return new Uri.Builder()
222                 .scheme(Condition.SCHEME)
223                 .authority(context.getPackageName());
224     }
225 
isValidId(Uri id, String pkg)226     public static boolean isValidId(Uri id, String pkg) {
227         return id != null && SCHEME.equals(id.getScheme()) && pkg.equals(id.getAuthority());
228     }
229 
230     public static final @android.annotation.NonNull Parcelable.Creator<Condition> CREATOR
231             = new Parcelable.Creator<Condition>() {
232         @Override
233         public Condition createFromParcel(Parcel source) {
234             return new Condition(source);
235         }
236 
237         @Override
238         public Condition[] newArray(int size) {
239             return new Condition[size];
240         }
241     };
242 }
243