1 /*
2  * Copyright 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.work;
18 
19 import android.arch.persistence.room.ColumnInfo;
20 import android.net.Uri;
21 import android.os.Build;
22 import android.support.annotation.NonNull;
23 import android.support.annotation.RequiresApi;
24 
25 /**
26  * The constraints that can be applied to one {@link WorkRequest}.
27  */
28 public final class Constraints {
29 
30     public static final Constraints NONE = new Constraints.Builder().build();
31 
32     @ColumnInfo(name = "required_network_type")
33     NetworkType mRequiredNetworkType;
34 
35     @ColumnInfo(name = "requires_charging")
36     boolean mRequiresCharging;
37 
38     @ColumnInfo(name = "requires_device_idle")
39     boolean mRequiresDeviceIdle;
40 
41     @ColumnInfo(name = "requires_battery_not_low")
42     boolean mRequiresBatteryNotLow;
43 
44     @ColumnInfo(name = "requires_storage_not_low")
45     boolean mRequiresStorageNotLow;
46 
47     @ColumnInfo(name = "content_uri_triggers")
48     ContentUriTriggers mContentUriTriggers;
49 
Constraints()50     public Constraints() { // stub required for room
51     }
52 
Constraints(Builder builder)53     private Constraints(Builder builder) {
54         mRequiresCharging = builder.mRequiresCharging;
55         mRequiresDeviceIdle = Build.VERSION.SDK_INT >= 23 && builder.mRequiresDeviceIdle;
56         mRequiredNetworkType = builder.mRequiredNetworkType;
57         mRequiresBatteryNotLow = builder.mRequiresBatteryNotLow;
58         mRequiresStorageNotLow = builder.mRequiresStorageNotLow;
59         mContentUriTriggers = (Build.VERSION.SDK_INT >= 24)
60                 ? builder.mContentUriTriggers
61                 : new ContentUriTriggers();
62     }
63 
getRequiredNetworkType()64     public @NonNull NetworkType getRequiredNetworkType() {
65         return mRequiredNetworkType;
66     }
67 
setRequiredNetworkType(@onNull NetworkType requiredNetworkType)68     public void setRequiredNetworkType(@NonNull NetworkType requiredNetworkType) {
69         mRequiredNetworkType = requiredNetworkType;
70     }
71 
72     /**
73      * @return If the constraints require charging.
74      */
requiresCharging()75     public boolean requiresCharging() {
76         return mRequiresCharging;
77     }
78 
setRequiresCharging(boolean requiresCharging)79     public void setRequiresCharging(boolean requiresCharging) {
80         mRequiresCharging = requiresCharging;
81     }
82 
83     /**
84      * @return If the constraints require device idle.
85      */
86     @RequiresApi(23)
requiresDeviceIdle()87     public boolean requiresDeviceIdle() {
88         return mRequiresDeviceIdle;
89     }
90 
91     @RequiresApi(23)
setRequiresDeviceIdle(boolean requiresDeviceIdle)92     public void setRequiresDeviceIdle(boolean requiresDeviceIdle) {
93         mRequiresDeviceIdle = requiresDeviceIdle;
94     }
95 
96     /**
97      * @return If the constraints require battery not low status.
98      */
requiresBatteryNotLow()99     public boolean requiresBatteryNotLow() {
100         return mRequiresBatteryNotLow;
101     }
102 
setRequiresBatteryNotLow(boolean requiresBatteryNotLow)103     public void setRequiresBatteryNotLow(boolean requiresBatteryNotLow) {
104         mRequiresBatteryNotLow = requiresBatteryNotLow;
105     }
106 
107     /**
108      * @return If the constraints require storage not low status.
109      */
requiresStorageNotLow()110     public boolean requiresStorageNotLow() {
111         return mRequiresStorageNotLow;
112     }
113 
setRequiresStorageNotLow(boolean requiresStorageNotLow)114     public void setRequiresStorageNotLow(boolean requiresStorageNotLow) {
115         mRequiresStorageNotLow = requiresStorageNotLow;
116     }
117 
118     @RequiresApi(24)
setContentUriTriggers(ContentUriTriggers mContentUriTriggers)119     public void setContentUriTriggers(ContentUriTriggers mContentUriTriggers) {
120         this.mContentUriTriggers = mContentUriTriggers;
121     }
122 
123     @RequiresApi(24)
getContentUriTriggers()124     public ContentUriTriggers getContentUriTriggers() {
125         return mContentUriTriggers;
126     }
127 
128     /**
129      * @return {@code true} if {@link ContentUriTriggers} is not empty
130      */
131     @RequiresApi(24)
hasContentUriTriggers()132     public boolean hasContentUriTriggers() {
133         return mContentUriTriggers.size() > 0;
134     }
135 
136     @Override
equals(Object o)137     public boolean equals(Object o) {
138         if (this == o) {
139             return true;
140         }
141         if (o == null || getClass() != o.getClass()) {
142             return false;
143         }
144         Constraints other = (Constraints) o;
145         return mRequiredNetworkType == other.mRequiredNetworkType
146                 && mRequiresCharging == other.mRequiresCharging
147                 && mRequiresDeviceIdle == other.mRequiresDeviceIdle
148                 && mRequiresBatteryNotLow == other.mRequiresBatteryNotLow
149                 && mRequiresStorageNotLow == other.mRequiresStorageNotLow
150                 && (mContentUriTriggers != null ? mContentUriTriggers.equals(
151                         other.mContentUriTriggers) : other.mContentUriTriggers == null);
152     }
153 
154     @Override
hashCode()155     public int hashCode() {
156         int result = mRequiredNetworkType.hashCode();
157         result = 31 * result + (mRequiresCharging ? 1 : 0);
158         result = 31 * result + (mRequiresDeviceIdle ? 1 : 0);
159         result = 31 * result + (mRequiresBatteryNotLow ? 1 : 0);
160         result = 31 * result + (mRequiresStorageNotLow ? 1 : 0);
161         result = 31 * result + (mContentUriTriggers != null ? mContentUriTriggers.hashCode() : 0);
162         return result;
163     }
164 
165     /**
166      * Builder for {@link Constraints} class.
167      */
168     public static final class Builder {
169         private boolean mRequiresCharging = false;
170         private boolean mRequiresDeviceIdle = false;
171         private NetworkType mRequiredNetworkType = NetworkType.NOT_REQUIRED;
172         private boolean mRequiresBatteryNotLow = false;
173         private boolean mRequiresStorageNotLow = false;
174         private ContentUriTriggers mContentUriTriggers = new ContentUriTriggers();
175 
176         /**
177          * Specify whether device should be plugged in for {@link WorkRequest} to run.
178          * Default is false.
179          *
180          * @param requiresCharging true if device must be plugged in, false otherwise
181          * @return current builder
182          */
setRequiresCharging(boolean requiresCharging)183         public Builder setRequiresCharging(boolean requiresCharging) {
184             this.mRequiresCharging = requiresCharging;
185             return this;
186         }
187 
188         /**
189          * Specify whether device should be idle for {@link WorkRequest} to run. Default is
190          * false.
191          *
192          * @param requiresDeviceIdle true if device must be idle, false otherwise
193          * @return current builder
194          */
195         @RequiresApi(23)
setRequiresDeviceIdle(boolean requiresDeviceIdle)196         public Builder setRequiresDeviceIdle(boolean requiresDeviceIdle) {
197             this.mRequiresDeviceIdle = requiresDeviceIdle;
198             return this;
199         }
200 
201         /**
202          * Specify whether device should have a particular {@link NetworkType} for
203          * {@link WorkRequest} to run. Default is {@link NetworkType#NOT_REQUIRED}.
204          *
205          * @param networkType type of network required
206          * @return current builder
207          */
setRequiredNetworkType(@onNull NetworkType networkType)208         public Builder setRequiredNetworkType(@NonNull NetworkType networkType) {
209             this.mRequiredNetworkType = networkType;
210             return this;
211         }
212 
213         /**
214          * Specify whether device battery should not be below critical threshold for
215          * {@link WorkRequest} to run. Default is false.
216          *
217          * @param requiresBatteryNotLow true if battery should not be below critical threshold,
218          *                              false otherwise
219          * @return current builder
220          */
setRequiresBatteryNotLow(boolean requiresBatteryNotLow)221         public Builder setRequiresBatteryNotLow(boolean requiresBatteryNotLow) {
222             this.mRequiresBatteryNotLow = requiresBatteryNotLow;
223             return this;
224         }
225 
226         /**
227          * Specify whether device available storage should not be below critical threshold for
228          * {@link WorkRequest} to run. Default is {@code false}.
229          *
230          * @param requiresStorageNotLow true if available storage should not be below critical
231          *                              threshold, false otherwise
232          * @return current builder
233          */
setRequiresStorageNotLow(boolean requiresStorageNotLow)234         public Builder setRequiresStorageNotLow(boolean requiresStorageNotLow) {
235             this.mRequiresStorageNotLow = requiresStorageNotLow;
236             return this;
237         }
238 
239         /**
240          * Specify whether {@link WorkRequest} should run when a content {@link android.net.Uri}
241          * is updated.  This method requires API 24 or higher.
242          *
243          * @param uri {@link android.net.Uri} to observe
244          * @param triggerForDescendants {@code true} if any changes in descendants cause this
245          *                              {@link WorkRequest} to run
246          * @return The current {@link Builder}
247          */
248         @RequiresApi(24)
addContentUriTrigger(Uri uri, boolean triggerForDescendants)249         public Builder addContentUriTrigger(Uri uri, boolean triggerForDescendants) {
250             mContentUriTriggers.add(uri, triggerForDescendants);
251             return this;
252         }
253 
254         /**
255          * Generates the {@link Constraints} from this Builder.
256          *
257          * @return new {@link Constraints} which can be attached to a {@link WorkRequest}
258          */
build()259         public Constraints build() {
260             return new Constraints(this);
261         }
262     }
263 }
264