VancedMicroG/play-services-wearable/src/main/java/org/microg/gms/wearable/databundle/DataBundleUtil.java

659 lines
22 KiB
Java

/*
* Copyright 2013-2016 microG Project Team
*
* 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 org.microg.gms.wearable.databundle;
import android.util.SparseArray;
import com.google.android.gms.wearable.Asset;
import com.google.android.gms.wearable.DataMap;
import com.squareup.wire.Wire;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import okio.ByteString;
public class DataBundleUtil {
public static DataMap readDataMap(byte[] bytes, List<Asset> assets) {
try {
return readDataMap(new Wire().parseFrom(bytes, DataBundle.class), assets);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static DataMap readDataMap(DataBundle dataBundle, List<Asset> assets) {
return readDataMap(dataBundle.entries, assets);
}
public static DataMap readDataMap(List<DataBundleEntry> entries, List<Asset> assets) {
DataMap dataMap = new DataMap();
for (DataBundleEntry entry : entries) {
readAndStore(dataMap, entry.key, entry.typedValue, assets);
}
return dataMap;
}
public static byte[] createBytes(DataMap dataMap) {
AssetAnnotatedDataBundle dataBundle = createDataBundle(dataMap);
if (!dataBundle.getAssets().isEmpty()) {
throw new UnsupportedOperationException();
}
return dataBundle.getData();
}
public static AssetAnnotatedDataBundle createDataBundle(DataMap dataMap) {
AssetAnnotatedDataBundle dataBundle = new AssetAnnotatedDataBundle();
dataBundle.assets = new ArrayList<Asset>();
dataBundle.dataBundle = new DataBundle(createEntryList(dataMap, dataBundle.assets));
return dataBundle;
}
private static List<DataBundleEntry> createEntryList(DataMap dataMap, List<Asset> assets) {
List<DataBundleEntry> entries = new ArrayList<DataBundleEntry>();
for (String key : dataMap.keySet()) {
entries.add(getTypeHelper(dataMap.getType(key)).loadAndCreateEntry(dataMap, key, assets));
}
return entries;
}
private static void readAndStore(DataMap dataMap, String key, DataBundleTypedValue value, List<Asset> assets) {
if (value.type == null) return;
getTypeHelper(value.type).readAndStore(dataMap, key, value, assets);
}
private static SparseArray<TypeHelper> typeHelperByCode;
private static void rememberTypeReader(TypeHelper typeHelper) {
typeHelperByCode.put(typeHelper.type, typeHelper);
}
static TypeHelper getTypeHelper(int type) {
if (typeHelperByCode.get(type) != null) {
return typeHelperByCode.get(type);
} else {
throw new IllegalArgumentException();
}
}
static TypeHelper getTypeHelper(DataMap.StoredType type) {
return getTypeHelper(type.getTypeCode());
}
static TypeHelper getListInnerTypeHelper(DataMap.StoredType type) {
return getTypeHelper(type.getListType());
}
public static final int BYTE_ARRAY_TYPE_CODE = 1;
static TypeHelper<byte[]> BYTEARRAY = new TypeHelper<byte[]>(BYTE_ARRAY_TYPE_CODE) {
@Override
byte[] read(DataBundleValue value, List<Asset> assets) {
return value.byteArray.toByteArray();
}
@Override
DataBundleValue create(byte[] value, List<Asset> assets) {
return new DataBundleValue.Builder().byteArray(ByteString.of(value)).build();
}
@Override
void store(DataMap dataMap, String key, byte[] value) {
dataMap.putByteArray(key, value);
}
@Override
byte[] load(DataMap dataMap, String key) {
return dataMap.getByteArray(key);
}
};
public static final int STRING_TYPE_CODE = 2;
static TypeHelper<String> STRING = new TypeHelper<String>(STRING_TYPE_CODE) {
@Override
String read(DataBundleValue value, List<Asset> assets) {
return value.stringVal;
}
@Override
DataBundleValue create(String value, List<Asset> assets) {
return new DataBundleValue.Builder().stringVal(value).build();
}
@Override
void store(DataMap dataMap, String key, String value) {
dataMap.putString(key, value);
}
@Override
void storeList(DataMap dataMap, String key, ArrayList<String> valueList) {
dataMap.putStringArrayList(key, valueList);
}
@Override
String load(DataMap dataMap, String key) {
return dataMap.getString(key);
}
@Override
AnnotatedArrayList<String> loadList(DataMap dataMap, String key) {
AnnotatedArrayList<String> list = new AnnotatedArrayList<String>(this);
list.addAll(dataMap.getStringArrayList(key));
return list;
}
};
public static final int DOUBLE_TYPE_CODE = 3;
static TypeHelper<Double> DOUBLE = new TypeHelper<Double>(DOUBLE_TYPE_CODE) {
@Override
Double read(DataBundleValue value, List<Asset> assets) {
return value.doubleVal;
}
@Override
DataBundleValue create(Double value, List<Asset> assets) {
return new DataBundleValue.Builder().doubleVal(value).build();
}
@Override
void store(DataMap dataMap, String key, Double value) {
dataMap.putDouble(key, value);
}
@Override
Double load(DataMap dataMap, String key) {
return dataMap.getDouble(key);
}
};
public static final int FLOAT_TYPE_CODE = 4;
static TypeHelper<Float> FLOAT = new TypeHelper<Float>(FLOAT_TYPE_CODE) {
@Override
Float read(DataBundleValue value, List<Asset> assets) {
return value.floatVal;
}
@Override
DataBundleValue create(Float value, List<Asset> assets) {
return new DataBundleValue.Builder().floatVal(value).build();
}
@Override
void store(DataMap dataMap, String key, Float value) {
dataMap.putFloat(key, value);
}
@Override
Float load(DataMap dataMap, String key) {
return dataMap.getFloat(key);
}
};
public static final int LONG_TYPE_CODE = 5;
static TypeHelper<Long> LONG = new TypeHelper<Long>(LONG_TYPE_CODE) {
@Override
Long read(DataBundleValue value, List<Asset> assets) {
return value.longVal;
}
@Override
DataBundleValue create(Long value, List<Asset> assets) {
return new DataBundleValue.Builder().longVal(value).build();
}
@Override
void store(DataMap dataMap, String key, Long value) {
dataMap.putLong(key, value);
}
@Override
Long load(DataMap dataMap, String key) {
return dataMap.getLong(key);
}
};
public static final int INTEGER_TYPE_CODE = 6;
static TypeHelper<Integer> INTEGER = new TypeHelper<Integer>(INTEGER_TYPE_CODE) {
@Override
Integer read(DataBundleValue value, List<Asset> assets) {
return value.intVal;
}
@Override
DataBundleValue create(Integer value, List<Asset> assets) {
return new DataBundleValue.Builder().intVal(value).build();
}
@Override
void store(DataMap dataMap, String key, Integer value) {
dataMap.putInt(key, value);
}
@Override
void storeList(DataMap dataMap, String key, ArrayList<Integer> valueList) {
dataMap.putIntegerArrayList(key, valueList);
}
@Override
Integer load(DataMap dataMap, String key) {
return dataMap.getInt(key);
}
@Override
AnnotatedArrayList<Integer> loadList(DataMap dataMap, String key) {
AnnotatedArrayList<Integer> list = new AnnotatedArrayList<Integer>(this);
list.addAll(dataMap.getIntegerArrayList(key));
return list;
}
};
public static final int BYTE_TYPE_CODE = 7;
static TypeHelper<Byte> BYTE = new TypeHelper<Byte>(BYTE_TYPE_CODE) {
@Override
Byte read(DataBundleValue value, List<Asset> assets) {
return (byte) (int) value.byteVal;
}
@Override
DataBundleValue create(Byte value, List<Asset> assets) {
return new DataBundleValue.Builder().byteVal((int) (byte) value).build();
}
@Override
void store(DataMap dataMap, String key, Byte value) {
dataMap.putByte(key, value);
}
@Override
Byte load(DataMap dataMap, String key) {
return dataMap.getByte(key);
}
};
public static final int BOOLEAN_TYPE_CODE = 8;
static TypeHelper<Boolean> BOOLEAN = new TypeHelper<Boolean>(BOOLEAN_TYPE_CODE) {
@Override
Boolean read(DataBundleValue value, List<Asset> assets) {
return value.booleanVal;
}
@Override
DataBundleValue create(Boolean value, List<Asset> assets) {
return new DataBundleValue.Builder().booleanVal(value).build();
}
@Override
void store(DataMap dataMap, String key, Boolean value) {
dataMap.putBoolean(key, value);
}
@Override
Boolean load(DataMap dataMap, String key) {
return dataMap.getBoolean(key);
}
};
public static final int DATAMAP_TYPE_CODE = 9;
static TypeHelper<DataMap> DATAMAP = new TypeHelper<DataMap>(DATAMAP_TYPE_CODE) {
@Override
DataMap read(DataBundleValue value, List<Asset> assets) {
return readDataMap(value.map, assets);
}
@Override
DataBundleValue create(DataMap value, List<Asset> assets) {
return new DataBundleValue.Builder().map(createEntryList(value, assets)).build();
}
@Override
void store(DataMap dataMap, String key, DataMap value) {
dataMap.putDataMap(key, value);
}
@Override
void storeList(DataMap dataMap, String key, ArrayList<DataMap> valueList) {
dataMap.putDataMapArrayList(key, valueList);
}
@Override
DataMap load(DataMap dataMap, String key) {
return dataMap.getDataMap(key);
}
@Override
AnnotatedArrayList<DataMap> loadList(DataMap dataMap, String key) {
AnnotatedArrayList<DataMap> list = new AnnotatedArrayList<DataMap>(this);
list.addAll(dataMap.getDataMapArrayList(key));
return list;
}
};
public static final int LIST_TYPE_CODE = 10;
static TypeHelper<AnnotatedArrayList<?>> ARRAYLIST = new TypeHelper<AnnotatedArrayList<?>>(LIST_TYPE_CODE) {
@Override
AnnotatedArrayList read(DataBundleValue value, List<Asset> assets) {
TypeHelper innerTypeHelper = NULL;
for (DataBundleTypedValue typedValue : value.list) {
if (innerTypeHelper == NULL) {
innerTypeHelper = getTypeHelper(typedValue.type);
} else if (typedValue.type != innerTypeHelper.type && typedValue.type != NULL.type) {
throw new IllegalArgumentException("List has elements of different types: " + innerTypeHelper.type + " and " + typedValue.type);
}
}
return innerTypeHelper.readList(value.list, assets);
}
@Override
DataBundleValue create(AnnotatedArrayList<?> value, List<Asset> assets) {
return new DataBundleValue.Builder().list(value.createList(assets)).build();
}
@Override
void store(DataMap dataMap, String key, AnnotatedArrayList value) {
value.store(dataMap, key);
}
@Override
AnnotatedArrayList load(DataMap dataMap, String key) {
return getListInnerTypeHelper(dataMap.getType(key)).loadList(dataMap, key);
}
};
public static final int STRING_ARRAY_TYPE_CODE = 11;
static TypeHelper<String[]> STRINGARRAY = new TypeHelper<String[]>(STRING_ARRAY_TYPE_CODE) {
@Override
String[] read(DataBundleValue value, List<Asset> assets) {
return value.stringArray.toArray(new String[value.stringArray.size()]);
}
@Override
DataBundleValue create(String[] value, List<Asset> assets) {
return new DataBundleValue.Builder().stringArray(Arrays.asList(value)).build();
}
@Override
void store(DataMap dataMap, String key, String[] value) {
dataMap.putStringArray(key, value);
}
@Override
String[] load(DataMap dataMap, String key) {
return dataMap.getStringArray(key);
}
};
public static final int LONG_ARRAY_TYPE_CODE = 12;
static TypeHelper<long[]> LONGARRAY = new TypeHelper<long[]>(LONG_ARRAY_TYPE_CODE) {
@Override
long[] read(DataBundleValue value, List<Asset> assets) {
long[] longArr = new long[value.longArray.size()];
for (int i = 0; i < value.longArray.size(); i++) {
longArr[i] = value.longArray.get(i);
}
return longArr;
}
@Override
DataBundleValue create(long[] value, List<Asset> assets) {
List<Long> longList = new ArrayList<Long>(value.length);
for (long l : value) {
longList.add(l);
}
return new DataBundleValue.Builder().longArray(longList).build();
}
@Override
void store(DataMap dataMap, String key, long[] value) {
dataMap.putLongArray(key, value);
}
@Override
long[] load(DataMap dataMap, String key) {
return dataMap.getLongArray(key);
}
};
public static final int ASSET_TYPE_CODE = 13;
static TypeHelper<Asset> ASSET = new TypeHelper<Asset>(ASSET_TYPE_CODE) {
@Override
Asset read(DataBundleValue value, List<Asset> assets) {
return assets.get(value.assetIndex);
}
@Override
DataBundleValue create(Asset value, List<Asset> assets) {
int index;
if (assets.contains(value)) {
index = assets.indexOf(value);
} else {
index = assets.size();
assets.add(value);
}
return new DataBundleValue.Builder().assetIndex(index).build();
}
@Override
void store(DataMap dataMap, String key, Asset value) {
dataMap.putAsset(key, value);
}
@Override
Asset load(DataMap dataMap, String key) {
return dataMap.getAsset(key);
}
};
public static final int NULL_TYPE_CODE = 14;
static TypeHelper<String> NULL = new TypeHelper<String>(NULL_TYPE_CODE) {
@Override
String read(DataBundleValue value, List<Asset> assets) {
return null;
}
@Override
DataBundleValue create(String value, List<Asset> assets) {
return new DataBundleValue.Builder().build();
}
@Override
void store(DataMap dataMap, String key, String value) {
dataMap.putString(key, value);
}
@Override
void storeList(DataMap dataMap, String key, ArrayList<String> valueList) {
dataMap.putStringArrayList(key, valueList);
}
@Override
String load(DataMap dataMap, String key) {
return null;
}
@Override
AnnotatedArrayList<String> loadList(DataMap dataMap, String key) {
AnnotatedArrayList<String> list = new AnnotatedArrayList<String>(this);
list.addAll(dataMap.getStringArrayList(key));
return list;
}
};
public static final int FLOAT_ARRAY_TYPE_CODE = 15;
static TypeHelper<float[]> FLOATARRAY = new TypeHelper<float[]>(FLOAT_ARRAY_TYPE_CODE) {
@Override
float[] read(DataBundleValue value, List<Asset> assets) {
float[] floatArr = new float[value.floatArray.size()];
for (int i = 0; i < value.floatArray.size(); i++) {
floatArr[i] = value.floatArray.get(i);
}
return floatArr;
}
@Override
DataBundleValue create(float[] value, List<Asset> assets) {
List<Float> floatList = new ArrayList<Float>(value.length);
for (float f : value) {
floatList.add(f);
}
return new DataBundleValue.Builder().floatArray(floatList).build();
}
@Override
void store(DataMap dataMap, String key, float[] value) {
dataMap.putFloatArray(key, value);
}
@Override
float[] load(DataMap dataMap, String key) {
return dataMap.getFloatArray(key);
}
};
static {
typeHelperByCode = new SparseArray<TypeHelper>();
rememberTypeReader(BYTEARRAY);
rememberTypeReader(STRING);
rememberTypeReader(DOUBLE);
rememberTypeReader(FLOAT);
rememberTypeReader(LONG);
rememberTypeReader(INTEGER);
rememberTypeReader(BYTE);
rememberTypeReader(BOOLEAN);
rememberTypeReader(DATAMAP);
rememberTypeReader(ARRAYLIST);
rememberTypeReader(STRINGARRAY);
rememberTypeReader(LONGARRAY);
rememberTypeReader(ASSET);
rememberTypeReader(NULL);
rememberTypeReader(FLOATARRAY);
}
static class AssetAnnotatedDataBundle {
private DataBundle dataBundle;
private List<Asset> assets;
public List<Asset> getAssets() {
return assets;
}
public byte[] getData() {
return dataBundle.toByteArray();
}
}
static class AnnotatedArrayList<T> extends ArrayList<T> {
private TypeHelper<T> innerType;
public AnnotatedArrayList(TypeHelper<T> innerType) {
this.innerType = innerType;
}
void store(DataMap dataMap, String key) {
innerType.storeList(dataMap, key, this);
}
public List<DataBundleTypedValue> createList(List<Asset> assets) {
return innerType.createList(this, assets);
}
}
static abstract class TypeHelper<T> {
private int type;
public TypeHelper(int type) {
this.type = type;
}
abstract T read(DataBundleValue value, List<Asset> assets);
abstract DataBundleValue create(T value, List<Asset> assets);
T read(DataBundleTypedValue value, List<Asset> assets) {
if (value.type == NULL_TYPE_CODE) {
return null;
} else if (value.type == type) {
return read(value.value, assets);
} else {
throw new IllegalArgumentException();
}
}
abstract void store(DataMap dataMap, String key, T value);
void storeList(DataMap dataMap, String key, ArrayList<T> valueList) {
throw new UnsupportedOperationException();
}
abstract T load(DataMap dataMap, String key);
AnnotatedArrayList<T> loadList(DataMap dataMap, String key) {
throw new UnsupportedOperationException();
}
void readAndStore(DataMap dataMap, String key, DataBundleValue value, List<Asset> assets) {
store(dataMap, key, read(value, assets));
}
void readAndStore(DataMap dataMap, String key, DataBundleTypedValue value, List<Asset> assets) {
store(dataMap, key, read(value, assets));
}
void readAndStore(DataMap dataMap, DataBundleEntry entry, List<Asset> assets) {
readAndStore(dataMap, entry.key, entry.typedValue, assets);
}
AnnotatedArrayList<T> readList(List<DataBundleTypedValue> values, List<Asset> assets) {
AnnotatedArrayList<T> list = new AnnotatedArrayList<T>(this);
for (DataBundleTypedValue value : values) {
list.add(read(value, assets));
}
return list;
}
List<DataBundleTypedValue> createList(AnnotatedArrayList<T> value, List<Asset> assets) {
List<DataBundleTypedValue> list = new ArrayList<DataBundleTypedValue>();
for (T val : value) {
list.add(createTyped(val, assets));
}
return list;
}
void readAndStore(DataMap dataMap, String key, List<DataBundleTypedValue> values, List<Asset> assets) {
storeList(dataMap, key, readList(values, assets));
}
DataBundleTypedValue createTyped(T value, List<Asset> assets) {
return new DataBundleTypedValue(type, create(value, assets));
}
DataBundleValue loadAndCreate(DataMap dataMap, String key, List<Asset> assets) {
return create(load(dataMap, key), assets);
}
DataBundleTypedValue loadAndCreateTyped(DataMap dataMap, String key, List<Asset> assets) {
return createTyped(load(dataMap, key), assets);
}
DataBundleEntry loadAndCreateEntry(DataMap dataMap, String key, List<Asset> assets) {
return new DataBundleEntry(key, loadAndCreateTyped(dataMap, key, assets));
}
}
}