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.impl.model; 18 19 import static androidx.work.BackoffPolicy.EXPONENTIAL; 20 import static androidx.work.BackoffPolicy.LINEAR; 21 import static androidx.work.State.BLOCKED; 22 import static androidx.work.State.CANCELLED; 23 import static androidx.work.State.ENQUEUED; 24 import static androidx.work.State.FAILED; 25 import static androidx.work.State.RUNNING; 26 import static androidx.work.State.SUCCEEDED; 27 28 import android.arch.persistence.room.TypeConverter; 29 import android.net.Uri; 30 31 import androidx.work.BackoffPolicy; 32 import androidx.work.ContentUriTriggers; 33 import androidx.work.NetworkType; 34 import androidx.work.State; 35 36 import java.io.ByteArrayInputStream; 37 import java.io.ByteArrayOutputStream; 38 import java.io.IOException; 39 import java.io.ObjectInputStream; 40 import java.io.ObjectOutputStream; 41 42 /** 43 * TypeConverters for WorkManager enums and classes. 44 */ 45 46 public class WorkTypeConverters { 47 48 /** 49 * Integer identifiers that map to {@link State}. 50 */ 51 public interface StateIds { 52 int ENQUEUED = 0; 53 int RUNNING = 1; 54 int SUCCEEDED = 2; 55 int FAILED = 3; 56 int BLOCKED = 4; 57 int CANCELLED = 5; 58 59 String COMPLETED_STATES = "(" + SUCCEEDED + ", " + FAILED + ", " + CANCELLED + ")"; 60 } 61 62 /** 63 * Integer identifiers that map to {@link BackoffPolicy}. 64 */ 65 public interface BackoffPolicyIds { 66 int EXPONENTIAL = 0; 67 int LINEAR = 1; 68 } 69 70 /** 71 * Integer identifiers that map to {@link NetworkType}. 72 */ 73 public interface NetworkTypeIds { 74 int NOT_REQUIRED = 0; 75 int CONNECTED = 1; 76 int UNMETERED = 2; 77 int NOT_ROAMING = 3; 78 int METERED = 4; 79 } 80 81 /** 82 * TypeConverter for a State to an int. 83 * 84 * @param state The input State 85 * @return The associated int constant 86 */ 87 @TypeConverter stateToInt(State state)88 public static int stateToInt(State state) { 89 switch (state) { 90 case ENQUEUED: 91 return StateIds.ENQUEUED; 92 93 case RUNNING: 94 return StateIds.RUNNING; 95 96 case SUCCEEDED: 97 return StateIds.SUCCEEDED; 98 99 case FAILED: 100 return StateIds.FAILED; 101 102 case BLOCKED: 103 return StateIds.BLOCKED; 104 105 case CANCELLED: 106 return StateIds.CANCELLED; 107 108 default: 109 throw new IllegalArgumentException( 110 "Could not convert " + state + " to int"); 111 } 112 } 113 114 /** 115 * TypeConverter for an int to a State. 116 * 117 * @param value The input integer 118 * @return The associated State enum value 119 */ 120 @TypeConverter intToState(int value)121 public static State intToState(int value) { 122 switch (value) { 123 case StateIds.ENQUEUED: 124 return ENQUEUED; 125 126 case StateIds.RUNNING: 127 return RUNNING; 128 129 case StateIds.SUCCEEDED: 130 return SUCCEEDED; 131 132 case StateIds.FAILED: 133 return FAILED; 134 135 case StateIds.BLOCKED: 136 return BLOCKED; 137 138 case StateIds.CANCELLED: 139 return CANCELLED; 140 141 default: 142 throw new IllegalArgumentException( 143 "Could not convert " + value + " to State"); 144 } 145 } 146 147 /** 148 * TypeConverter for a BackoffPolicy to an int. 149 * 150 * @param backoffPolicy The input BackoffPolicy 151 * @return The associated int constant 152 */ 153 @TypeConverter backoffPolicyToInt(BackoffPolicy backoffPolicy)154 public static int backoffPolicyToInt(BackoffPolicy backoffPolicy) { 155 switch (backoffPolicy) { 156 case EXPONENTIAL: 157 return BackoffPolicyIds.EXPONENTIAL; 158 159 case LINEAR: 160 return BackoffPolicyIds.LINEAR; 161 162 default: 163 throw new IllegalArgumentException( 164 "Could not convert " + backoffPolicy + " to int"); 165 } 166 } 167 168 /** 169 * TypeConverter for an int to a BackoffPolicy. 170 * 171 * @param value The input integer 172 * @return The associated BackoffPolicy enum value 173 */ 174 @TypeConverter intToBackoffPolicy(int value)175 public static BackoffPolicy intToBackoffPolicy(int value) { 176 switch (value) { 177 case BackoffPolicyIds.EXPONENTIAL: 178 return EXPONENTIAL; 179 180 case BackoffPolicyIds.LINEAR: 181 return LINEAR; 182 183 default: 184 throw new IllegalArgumentException( 185 "Could not convert " + value + " to BackoffPolicy"); 186 } 187 } 188 189 /** 190 * TypeConverter for a NetworkType to an int. 191 * 192 * @param networkType The input NetworkType 193 * @return The associated int constant 194 */ 195 @TypeConverter networkTypeToInt(NetworkType networkType)196 public static int networkTypeToInt(NetworkType networkType) { 197 switch (networkType) { 198 case NOT_REQUIRED: 199 return NetworkTypeIds.NOT_REQUIRED; 200 201 case CONNECTED: 202 return NetworkTypeIds.CONNECTED; 203 204 case UNMETERED: 205 return NetworkTypeIds.UNMETERED; 206 207 case NOT_ROAMING: 208 return NetworkTypeIds.NOT_ROAMING; 209 210 case METERED: 211 return NetworkTypeIds.METERED; 212 213 default: 214 throw new IllegalArgumentException( 215 "Could not convert " + networkType + " to int"); 216 } 217 } 218 219 /** 220 * TypeConverter for an int to a NetworkType. 221 * 222 * @param value The input integer 223 * @return The associated NetworkType enum value 224 */ 225 @TypeConverter intToNetworkType(int value)226 public static NetworkType intToNetworkType(int value) { 227 switch (value) { 228 case NetworkTypeIds.NOT_REQUIRED: 229 return NetworkType.NOT_REQUIRED; 230 231 case NetworkTypeIds.CONNECTED: 232 return NetworkType.CONNECTED; 233 234 case NetworkTypeIds.UNMETERED: 235 return NetworkType.UNMETERED; 236 237 case NetworkTypeIds.NOT_ROAMING: 238 return NetworkType.NOT_ROAMING; 239 240 case NetworkTypeIds.METERED: 241 return NetworkType.METERED; 242 243 default: 244 throw new IllegalArgumentException( 245 "Could not convert " + value + " to NetworkType"); 246 } 247 } 248 249 /** 250 * Converts a list of {@link ContentUriTriggers.Trigger}s to byte array representation 251 * @param triggers the list of {@link ContentUriTriggers.Trigger}s to convert 252 * @return corresponding byte array representation 253 */ 254 @TypeConverter contentUriTriggersToByteArray(ContentUriTriggers triggers)255 public static byte[] contentUriTriggersToByteArray(ContentUriTriggers triggers) { 256 if (triggers.size() == 0) { 257 // Return null for no triggers. Needed for SQL query check in ForegroundProcessor 258 return null; 259 } 260 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 261 ObjectOutputStream objectOutputStream = null; 262 try { 263 objectOutputStream = new ObjectOutputStream(outputStream); 264 objectOutputStream.writeInt(triggers.size()); 265 for (ContentUriTriggers.Trigger trigger : triggers) { 266 objectOutputStream.writeUTF(trigger.getUri().toString()); 267 objectOutputStream.writeBoolean(trigger.shouldTriggerForDescendants()); 268 } 269 } catch (IOException e) { 270 e.printStackTrace(); 271 } finally { 272 if (objectOutputStream != null) { 273 try { 274 objectOutputStream.close(); 275 } catch (IOException e) { 276 e.printStackTrace(); 277 } 278 } 279 try { 280 outputStream.close(); 281 } catch (IOException e) { 282 e.printStackTrace(); 283 } 284 } 285 return outputStream.toByteArray(); 286 } 287 288 /** 289 * Converts a byte array to list of {@link ContentUriTriggers.Trigger}s 290 * @param bytes byte array representation to convert 291 * @return list of {@link ContentUriTriggers.Trigger}s 292 */ 293 @TypeConverter byteArrayToContentUriTriggers(byte[] bytes)294 public static ContentUriTriggers byteArrayToContentUriTriggers(byte[] bytes) { 295 ContentUriTriggers triggers = new ContentUriTriggers(); 296 if (bytes == null) { 297 // bytes will be null if there are no Content Uri Triggers 298 return triggers; 299 } 300 ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes); 301 ObjectInputStream objectInputStream = null; 302 try { 303 objectInputStream = new ObjectInputStream(inputStream); 304 for (int i = objectInputStream.readInt(); i > 0; i--) { 305 Uri uri = Uri.parse(objectInputStream.readUTF()); 306 boolean triggersForDescendants = objectInputStream.readBoolean(); 307 triggers.add(uri, triggersForDescendants); 308 } 309 } catch (IOException e) { 310 e.printStackTrace(); 311 } finally { 312 if (objectInputStream != null) { 313 try { 314 objectInputStream.close(); 315 } catch (IOException e) { 316 e.printStackTrace(); 317 } 318 } 319 try { 320 inputStream.close(); 321 } catch (IOException e) { 322 e.printStackTrace(); 323 } 324 } 325 return triggers; 326 } 327 WorkTypeConverters()328 private WorkTypeConverters() { 329 } 330 } 331