| /* |
| * Copyright 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package androidx.work.impl.model |
| |
| import android.net.Uri |
| import android.os.Build |
| import androidx.room.TypeConverter |
| import androidx.work.BackoffPolicy |
| import androidx.work.Constraints |
| import androidx.work.Constraints.ContentUriTrigger |
| import androidx.work.NetworkType |
| import androidx.work.OutOfQuotaPolicy |
| import androidx.work.WorkInfo |
| import java.io.ByteArrayInputStream |
| import java.io.ByteArrayOutputStream |
| import java.io.IOException |
| import java.io.ObjectInputStream |
| import java.io.ObjectOutputStream |
| import java.lang.IllegalArgumentException |
| |
| /** |
| * TypeConverters for WorkManager enums and classes. |
| */ |
| object WorkTypeConverters { |
| /** |
| * Integer identifiers that map to [WorkInfo.State]. |
| */ |
| object StateIds { |
| const val ENQUEUED = 0 |
| const val RUNNING = 1 |
| const val SUCCEEDED = 2 |
| const val FAILED = 3 |
| const val BLOCKED = 4 |
| const val CANCELLED = 5 |
| const val COMPLETED_STATES = "($SUCCEEDED, $FAILED, $CANCELLED)" |
| } |
| |
| /** |
| * Integer identifiers that map to [BackoffPolicy]. |
| */ |
| private object BackoffPolicyIds { |
| const val EXPONENTIAL = 0 |
| const val LINEAR = 1 |
| } |
| |
| /** |
| * Integer identifiers that map to [NetworkType]. |
| */ |
| private object NetworkTypeIds { |
| const val NOT_REQUIRED = 0 |
| const val CONNECTED = 1 |
| const val UNMETERED = 2 |
| const val NOT_ROAMING = 3 |
| const val METERED = 4 |
| const val TEMPORARILY_UNMETERED = 5 |
| } |
| |
| /** |
| * Integer identifiers that map to [OutOfQuotaPolicy]. |
| */ |
| private object OutOfPolicyIds { |
| const val RUN_AS_NON_EXPEDITED_WORK_REQUEST = 0 |
| const val DROP_WORK_REQUEST = 1 |
| } |
| |
| /** |
| * TypeConverter for a State to an int. |
| * |
| * @param state The input State |
| * @return The associated int constant |
| */ |
| @JvmStatic |
| @TypeConverter |
| fun stateToInt(state: WorkInfo.State): Int { |
| return when (state) { |
| WorkInfo.State.ENQUEUED -> StateIds.ENQUEUED |
| WorkInfo.State.RUNNING -> StateIds.RUNNING |
| WorkInfo.State.SUCCEEDED -> StateIds.SUCCEEDED |
| WorkInfo.State.FAILED -> StateIds.FAILED |
| WorkInfo.State.BLOCKED -> StateIds.BLOCKED |
| WorkInfo.State.CANCELLED -> StateIds.CANCELLED |
| } |
| } |
| |
| /** |
| * TypeConverter for an int to a State. |
| * |
| * @param value The input integer |
| * @return The associated State enum value |
| */ |
| @JvmStatic |
| @TypeConverter |
| fun intToState(value: Int): WorkInfo.State { |
| return when (value) { |
| StateIds.ENQUEUED -> WorkInfo.State.ENQUEUED |
| StateIds.RUNNING -> WorkInfo.State.RUNNING |
| StateIds.SUCCEEDED -> WorkInfo.State.SUCCEEDED |
| StateIds.FAILED -> WorkInfo.State.FAILED |
| StateIds.BLOCKED -> WorkInfo.State.BLOCKED |
| StateIds.CANCELLED -> WorkInfo.State.CANCELLED |
| else -> throw IllegalArgumentException("Could not convert $value to State") |
| } |
| } |
| |
| /** |
| * TypeConverter for a BackoffPolicy to an int. |
| * |
| * @param backoffPolicy The input BackoffPolicy |
| * @return The associated int constant |
| */ |
| @JvmStatic |
| @TypeConverter |
| fun backoffPolicyToInt(backoffPolicy: BackoffPolicy): Int { |
| return when (backoffPolicy) { |
| BackoffPolicy.EXPONENTIAL -> BackoffPolicyIds.EXPONENTIAL |
| BackoffPolicy.LINEAR -> BackoffPolicyIds.LINEAR |
| } |
| } |
| |
| /** |
| * TypeConverter for an int to a BackoffPolicy. |
| * |
| * @param value The input integer |
| * @return The associated BackoffPolicy enum value |
| */ |
| @JvmStatic |
| @TypeConverter |
| fun intToBackoffPolicy(value: Int): BackoffPolicy { |
| return when (value) { |
| BackoffPolicyIds.EXPONENTIAL -> BackoffPolicy.EXPONENTIAL |
| BackoffPolicyIds.LINEAR -> BackoffPolicy.LINEAR |
| else -> throw IllegalArgumentException("Could not convert $value to BackoffPolicy") |
| } |
| } |
| |
| /** |
| * TypeConverter for a NetworkType to an int. |
| * |
| * @param networkType The input NetworkType |
| * @return The associated int constant |
| */ |
| @JvmStatic |
| @TypeConverter |
| fun networkTypeToInt(networkType: NetworkType): Int { |
| return when (networkType) { |
| NetworkType.NOT_REQUIRED -> NetworkTypeIds.NOT_REQUIRED |
| NetworkType.CONNECTED -> NetworkTypeIds.CONNECTED |
| NetworkType.UNMETERED -> NetworkTypeIds.UNMETERED |
| NetworkType.NOT_ROAMING -> NetworkTypeIds.NOT_ROAMING |
| NetworkType.METERED -> NetworkTypeIds.METERED |
| else -> { |
| if (Build.VERSION.SDK_INT >= 30 && networkType == NetworkType.TEMPORARILY_UNMETERED) |
| NetworkTypeIds.TEMPORARILY_UNMETERED |
| else |
| throw IllegalArgumentException("Could not convert $networkType to int") |
| } |
| } |
| } |
| |
| /** |
| * TypeConverter for an int to a NetworkType. |
| * |
| * @param value The input integer |
| * @return The associated NetworkType enum value |
| */ |
| @JvmStatic |
| @TypeConverter |
| fun intToNetworkType(value: Int): NetworkType { |
| return when (value) { |
| NetworkTypeIds.NOT_REQUIRED -> NetworkType.NOT_REQUIRED |
| NetworkTypeIds.CONNECTED -> NetworkType.CONNECTED |
| NetworkTypeIds.UNMETERED -> NetworkType.UNMETERED |
| NetworkTypeIds.NOT_ROAMING -> NetworkType.NOT_ROAMING |
| NetworkTypeIds.METERED -> NetworkType.METERED |
| else -> { |
| if (Build.VERSION.SDK_INT >= 30 && value == NetworkTypeIds.TEMPORARILY_UNMETERED) { |
| return NetworkType.TEMPORARILY_UNMETERED |
| } else throw IllegalArgumentException("Could not convert $value to NetworkType") |
| } |
| } |
| } |
| |
| /** |
| * Converts a [OutOfQuotaPolicy] to an int. |
| * |
| * @param policy The [OutOfQuotaPolicy] policy being used |
| * @return the corresponding int representation. |
| */ |
| @JvmStatic |
| @TypeConverter |
| fun outOfQuotaPolicyToInt(policy: OutOfQuotaPolicy): Int { |
| return when (policy) { |
| OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST -> |
| OutOfPolicyIds.RUN_AS_NON_EXPEDITED_WORK_REQUEST |
| OutOfQuotaPolicy.DROP_WORK_REQUEST -> OutOfPolicyIds.DROP_WORK_REQUEST |
| } |
| } |
| |
| /** |
| * Converter from an int to a [OutOfQuotaPolicy]. |
| * |
| * @param value The input integer |
| * @return An [OutOfQuotaPolicy] |
| */ |
| @JvmStatic |
| @TypeConverter |
| fun intToOutOfQuotaPolicy(value: Int): OutOfQuotaPolicy { |
| return when (value) { |
| OutOfPolicyIds.RUN_AS_NON_EXPEDITED_WORK_REQUEST -> |
| OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST |
| OutOfPolicyIds.DROP_WORK_REQUEST -> OutOfQuotaPolicy.DROP_WORK_REQUEST |
| else -> throw IllegalArgumentException("Could not convert $value to OutOfQuotaPolicy") |
| } |
| } |
| |
| /** |
| * Converts a set of [Constraints.ContentUriTrigger]s to byte array representation |
| * @param triggers the list of [Constraints.ContentUriTrigger]s to convert |
| * @return corresponding byte array representation |
| */ |
| @JvmStatic |
| @TypeConverter |
| fun setOfTriggersToByteArray(triggers: Set<ContentUriTrigger>): ByteArray { |
| if (triggers.isEmpty()) { |
| return ByteArray(0) |
| } |
| val outputStream = ByteArrayOutputStream() |
| outputStream.use { |
| ObjectOutputStream(outputStream).use { objectOutputStream -> |
| objectOutputStream.writeInt(triggers.size) |
| for (trigger in triggers) { |
| objectOutputStream.writeUTF(trigger.uri.toString()) |
| objectOutputStream.writeBoolean(trigger.isTriggeredForDescendants) |
| } |
| } |
| } |
| return outputStream.toByteArray() |
| } |
| |
| /** |
| * Converts a byte array to set of [ContentUriTrigger]s |
| * @param bytes byte array representation to convert |
| * @return set of [ContentUriTrigger] |
| */ |
| @JvmStatic |
| @TypeConverter |
| fun byteArrayToSetOfTriggers(bytes: ByteArray): Set<ContentUriTrigger> { |
| val triggers = mutableSetOf<ContentUriTrigger>() |
| if (bytes.isEmpty()) { |
| // bytes will be null if there are no Content Uri Triggers |
| return triggers |
| } |
| val inputStream = ByteArrayInputStream(bytes) |
| inputStream.use { |
| try { |
| ObjectInputStream(inputStream).use { objectInputStream -> |
| repeat(objectInputStream.readInt()) { |
| val uri = Uri.parse(objectInputStream.readUTF()) |
| val triggersForDescendants = objectInputStream.readBoolean() |
| triggers.add(ContentUriTrigger(uri, triggersForDescendants)) |
| } |
| } |
| } catch (e: IOException) { |
| e.printStackTrace() |
| } |
| } |
| return triggers |
| } |
| } |