ParcelableData.java
/*
* Copyright 2021 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.multiprocess.parcelable;
import static androidx.work.Data.convertPrimitiveBooleanArray;
import static androidx.work.Data.convertPrimitiveByteArray;
import static androidx.work.Data.convertPrimitiveDoubleArray;
import static androidx.work.Data.convertPrimitiveFloatArray;
import static androidx.work.Data.convertPrimitiveIntArray;
import static androidx.work.Data.convertPrimitiveLongArray;
import static androidx.work.Data.convertToPrimitiveArray;
import static androidx.work.multiprocess.parcelable.ParcelUtils.readBooleanValue;
import static androidx.work.multiprocess.parcelable.ParcelUtils.writeBooleanValue;
import android.annotation.SuppressLint;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.work.Data;
import java.util.HashMap;
import java.util.Map;
/**
* {@link androidx.work.Data} but {@link android.os.Parcelable}.
*
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@SuppressLint("BanParcelableUsage")
public class ParcelableData implements Parcelable {
// The list of supported types.
private static final byte TYPE_NULL = 0;
private static final byte TYPE_BOOLEAN = 1;
private static final byte TYPE_BYTE = 2;
private static final byte TYPE_INTEGER = 3;
private static final byte TYPE_LONG = 4;
private static final byte TYPE_FLOAT = 5;
private static final byte TYPE_DOUBLE = 6;
private static final byte TYPE_STRING = 7;
private static final byte TYPE_BOOLEAN_ARRAY = 8;
private static final byte TYPE_BYTE_ARRAY = 9;
private static final byte TYPE_INTEGER_ARRAY = 10;
private static final byte TYPE_LONG_ARRAY = 11;
private static final byte TYPE_FLOAT_ARRAY = 12;
private static final byte TYPE_DOUBLE_ARRAY = 13;
private static final byte TYPE_STRING_ARRAY = 14;
private final Data mData;
public ParcelableData(@NonNull Data data) {
mData = data;
}
protected ParcelableData(@NonNull Parcel in) {
Map<String, Object> values = new HashMap<>();
// size
int size = in.readInt();
for (int i = 0; i < size; i++) {
// entries
addEntry(in, values);
}
mData = new Data(values);
}
public static final Creator<ParcelableData> CREATOR =
new Creator<ParcelableData>() {
@Override
public ParcelableData createFromParcel(@NonNull Parcel in) {
return new ParcelableData(in);
}
@Override
public ParcelableData[] newArray(int size) {
return new ParcelableData[size];
}
};
@NonNull
public Data getData() {
return mData;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel parcel, int flags) {
Map<String, Object> keyValueMap = mData.getKeyValueMap();
// size
parcel.writeInt(keyValueMap.size());
for (Map.Entry<String, Object> entry : keyValueMap.entrySet()) {
writeToParcel(parcel, entry.getKey(), entry.getValue());
}
}
private void writeToParcel(
@NonNull Parcel parcel,
@NonNull String key,
@Nullable Object value) {
// type + value
if (value == null) {
parcel.writeByte(TYPE_NULL);
} else {
Class<?> valueType = value.getClass();
if (valueType == Boolean.class) {
parcel.writeByte(TYPE_BOOLEAN);
boolean booleanValue = (Boolean) value;
writeBooleanValue(parcel, booleanValue);
} else if (valueType == Byte.class) {
parcel.writeByte(TYPE_BYTE);
byte byteValue = (Byte) value;
parcel.writeByte(byteValue);
} else if (valueType == Integer.class) {
parcel.writeByte(TYPE_INTEGER);
int intValue = (Integer) value;
parcel.writeInt(intValue);
} else if (valueType == Long.class) {
parcel.writeByte(TYPE_LONG);
Long longValue = (Long) value;
parcel.writeLong(longValue);
} else if (valueType == Float.class) {
parcel.writeByte(TYPE_FLOAT);
float floatValue = (Float) value;
parcel.writeFloat(floatValue);
} else if (valueType == Double.class) {
parcel.writeByte(TYPE_DOUBLE);
double doubleValue = (Double) value;
parcel.writeDouble(doubleValue);
} else if (valueType == String.class) {
parcel.writeByte(TYPE_STRING);
String stringValue = (String) value;
parcel.writeString(stringValue);
} else if (valueType == Boolean[].class) {
parcel.writeByte(TYPE_BOOLEAN_ARRAY);
Boolean[] booleanArray = (Boolean[]) value;
parcel.writeBooleanArray(convertToPrimitiveArray(booleanArray));
} else if (valueType == Byte[].class) {
parcel.writeByte(TYPE_BYTE_ARRAY);
Byte[] byteArray = (Byte[]) value;
parcel.writeByteArray(convertToPrimitiveArray(byteArray));
} else if (valueType == Integer[].class) {
parcel.writeByte(TYPE_INTEGER_ARRAY);
Integer[] integerArray = (Integer[]) value;
parcel.writeIntArray(convertToPrimitiveArray(integerArray));
} else if (valueType == Long[].class) {
parcel.writeByte(TYPE_LONG_ARRAY);
Long[] longArray = (Long[]) value;
parcel.writeLongArray(convertToPrimitiveArray(longArray));
} else if (valueType == Float[].class) {
parcel.writeByte(TYPE_FLOAT_ARRAY);
Float[] floatArray = (Float[]) value;
parcel.writeFloatArray(convertToPrimitiveArray(floatArray));
} else if (valueType == Double[].class) {
parcel.writeByte(TYPE_DOUBLE_ARRAY);
Double[] doubleArray = (Double[]) value;
parcel.writeDoubleArray(convertToPrimitiveArray(doubleArray));
} else if (valueType == String[].class) {
parcel.writeByte(TYPE_STRING_ARRAY);
String[] stringArray = (String[]) value;
parcel.writeStringArray(stringArray);
} else {
// Exhaustive check
String message = "Unsupported value type " + valueType.getName();
throw new IllegalArgumentException(message);
}
}
// key
parcel.writeString(key);
}
private void addEntry(@NonNull Parcel parcel, @NonNull Map<String, Object> values) {
// type
int type = parcel.readByte();
Object value = null;
switch (type) {
case TYPE_NULL:
break;
case TYPE_BYTE:
value = parcel.readByte();
break;
case TYPE_BOOLEAN:
value = readBooleanValue(parcel);
break;
case TYPE_INTEGER:
value = parcel.readInt();
break;
case TYPE_LONG:
value = parcel.readLong();
break;
case TYPE_FLOAT:
value = parcel.readFloat();
break;
case TYPE_DOUBLE:
value = parcel.readDouble();
break;
case TYPE_STRING:
value = parcel.readString();
break;
case TYPE_BOOLEAN_ARRAY:
value = convertPrimitiveBooleanArray(parcel.createBooleanArray());
break;
case TYPE_BYTE_ARRAY:
value = convertPrimitiveByteArray(parcel.createByteArray());
break;
case TYPE_INTEGER_ARRAY:
value = convertPrimitiveIntArray(parcel.createIntArray());
break;
case TYPE_LONG_ARRAY:
value = convertPrimitiveLongArray(parcel.createLongArray());
break;
case TYPE_FLOAT_ARRAY:
value = convertPrimitiveFloatArray(parcel.createFloatArray());
break;
case TYPE_DOUBLE_ARRAY:
value = convertPrimitiveDoubleArray(parcel.createDoubleArray());
break;
case TYPE_STRING_ARRAY:
value = parcel.createStringArray();
break;
default:
String message = "Unsupported type " + type;
throw new IllegalStateException(message);
}
String key = parcel.readString();
values.put(key, value);
}
}