/*
* Copyright 2013-2015 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 com.google.android.gms.wearable;
import android.os.Bundle;
import org.microg.gms.common.PublicApi;
import org.microg.gms.wearable.databundle.DataBundleUtil;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import static org.microg.gms.wearable.databundle.DataBundleUtil.ASSET_TYPE_CODE;
import static org.microg.gms.wearable.databundle.DataBundleUtil.BOOLEAN_TYPE_CODE;
import static org.microg.gms.wearable.databundle.DataBundleUtil.BYTE_ARRAY_TYPE_CODE;
import static org.microg.gms.wearable.databundle.DataBundleUtil.BYTE_TYPE_CODE;
import static org.microg.gms.wearable.databundle.DataBundleUtil.DATAMAP_TYPE_CODE;
import static org.microg.gms.wearable.databundle.DataBundleUtil.DOUBLE_TYPE_CODE;
import static org.microg.gms.wearable.databundle.DataBundleUtil.FLOAT_ARRAY_TYPE_CODE;
import static org.microg.gms.wearable.databundle.DataBundleUtil.FLOAT_TYPE_CODE;
import static org.microg.gms.wearable.databundle.DataBundleUtil.INTEGER_TYPE_CODE;
import static org.microg.gms.wearable.databundle.DataBundleUtil.LIST_TYPE_CODE;
import static org.microg.gms.wearable.databundle.DataBundleUtil.LONG_ARRAY_TYPE_CODE;
import static org.microg.gms.wearable.databundle.DataBundleUtil.LONG_TYPE_CODE;
import static org.microg.gms.wearable.databundle.DataBundleUtil.STRING_ARRAY_TYPE_CODE;
import static org.microg.gms.wearable.databundle.DataBundleUtil.STRING_TYPE_CODE;
/**
* A map of data supported by {@link PutDataMapRequest} and {@link DataMapItem}s. DataMap may
* convert to and from Bundles, but will drop any types not explicitly supported by DataMap in the
* conversion process.
*/
@PublicApi
public class DataMap {
public static String TAG = "GmsDataMap";
private Map<String, Object> data = new HashMap<String, Object>();
private Map<String, StoredType> types = new HashMap<String, StoredType>();
public DataMap() {
}
/**
* @return an ArrayList of DataMaps from an ArrayList of Bundles. Any elements in the Bundles not supported by DataMap will be dropped.
*/
public static ArrayList<DataMap> arrayListFromBundleArrayList(ArrayList<Bundle> bundleArrayList) {
ArrayList<DataMap> res = new ArrayList<DataMap>();
for (Bundle bundle : bundleArrayList) {
res.add(fromBundle(bundle));
}
return res;
}
/**
* Removes all elements from the mapping of this DataMap.
*/
public void clear() {
data.clear();
}
/**
* @return true if the given key is contained in the mapping of this DataMap.
*/
public boolean containsKey(String key) {
return data.containsKey(key);
}
/**
* @return true if the given Object is a DataMap equivalent to this one.
*/
@Override
public boolean equals(Object o) {
return o instanceof DataMap && data.equals(((DataMap) o).data);
}
public StoredType getType(String key) {
return types.get(key);
}
@PublicApi(exclude = true)
public enum StoredType {
Asset(ASSET_TYPE_CODE), Boolean(BOOLEAN_TYPE_CODE), Byte(BYTE_TYPE_CODE),
ByteArray(BYTE_ARRAY_TYPE_CODE), DataMap(DATAMAP_TYPE_CODE), DataMapArrayList(DataMap),
Double(DOUBLE_TYPE_CODE), Float(FLOAT_TYPE_CODE), FloatArray(FLOAT_ARRAY_TYPE_CODE),
Integer(INTEGER_TYPE_CODE), IntegerArrayList(Integer), Long(LONG_TYPE_CODE),
LongArray(LONG_ARRAY_TYPE_CODE), String(STRING_TYPE_CODE),
StringArray(STRING_ARRAY_TYPE_CODE), StringArrayList(String);
private int typeCode;
private StoredType listType;
StoredType(int typeCode) {
this.typeCode = typeCode;
}
StoredType(StoredType listType) {
this.typeCode = LIST_TYPE_CODE;
this.listType = listType;
}
public int getTypeCode() {
return typeCode;
}
public StoredType getListType() {
return listType;
}
}
/**
* @return a DataMap from a Bundle. The input Bundle is expected to contain only elements
* supported by DataMap. Any elements in the Bundle not supported by DataMap will be dropped.
*/
public static DataMap fromBundle(Bundle bundle) {
DataMap res = new DataMap();
if (bundle != null) {
for (String key : bundle.keySet()) {
Object val = bundle.get(key);
if (val instanceof Asset) {
res.putAsset(key, (Asset) val);
} else if (val instanceof Boolean) {
res.putBoolean(key, (Boolean) val);
} else if (val instanceof Byte) {
res.putByte(key, (Byte) val);
} else if (val instanceof byte[]) {
res.putByteArray(key, (byte[]) val);
} else if (val instanceof Bundle) {
res.putDataMap(key, DataMap.fromBundle((Bundle) val));
} else if (val instanceof Double) {
res.putDouble(key, (Double) val);
} else if (val instanceof Float) {
res.putFloat(key, (Float) val);
} else if (val instanceof float[]) {
res.putFloatArray(key, (float[]) val);
} else if (val instanceof Integer) {
res.putInt(key, (Integer) val);
} else if (val instanceof Long) {
res.putLong(key, (Long) val);
} else if (val instanceof long[]) {
res.putLongArray(key, (long[]) val);
} else if (val instanceof String) {
res.putString(key, (String) val);
} else if (val instanceof String[]) {
res.putStringArray(key, (String[]) val);
} else if (val instanceof ArrayList) {
if (((ArrayList) val).isEmpty() || ((ArrayList) val).get(0) instanceof String) {
res.putStringArrayList(key, (ArrayList<String>) val);
} else if (((ArrayList) val).get(0) instanceof Bundle) {
ArrayList<DataMap> dataMaps = new ArrayList<DataMap>();
for (Bundle b : ((ArrayList<Bundle>) val)) {
dataMaps.add(DataMap.fromBundle(b));
}
res.putDataMapArrayList(key, dataMaps);
} else if (((ArrayList) val).get(0) instanceof Integer) {
res.putIntegerArrayList(key, (ArrayList<Integer>) val);
}
}
}
}
return res;
}
/**
* @return a DataMap from a byte[].
*/
public static DataMap fromByteArray(byte[] bytes) {
return DataBundleUtil.readDataMap(bytes, Collections.<Asset>emptyList());
}
/**
* @return the entry with the given key as an object, or null
*/
public <T> T get(String key) {
return (T) data.get(key);
}
public Asset getAsset(String key) {
return types.get(key) == StoredType.Asset ? (Asset) data.get(key) : null;
}
public boolean getBoolean(String key) {
return getBoolean(key, false);
}
public boolean getBoolean(String key, boolean defaultValue) {
return types.get(key) == StoredType.Boolean ? (Boolean) data.get(key) : defaultValue;
}
public byte getByte(String key) {
return getByte(key, (byte) 0);
}
public byte getByte(String key, byte defaultValue) {
return types.get(key) == StoredType.Byte ? (Byte) data.get(key) : defaultValue;
}
public byte[] getByteArray(String key) {
return types.get(key) == StoredType.ByteArray ? (byte[]) data.get(key) : null;
}
public DataMap getDataMap(String key) {
return types.get(key) == StoredType.DataMap ? (DataMap) data.get(key) : null;
}
public ArrayList<DataMap> getDataMapArrayList(String key) {
return types.get(key) == StoredType.DataMapArrayList ? (ArrayList<DataMap>) data.get(key) : null;
}
public double getDouble(String key) {
return getDouble(key, 0.0);
}
public double getDouble(String key, double defaultValue) {
return types.get(key) == StoredType.Double ? (Double) data.get(key) : defaultValue;
}
public float getFloat(String key) {
return getFloat(key, 0.0f);
}
public float getFloat(String key, float defaultValue) {
return types.get(key) == StoredType.Float ? (Float) data.get(key) : defaultValue;
}
public float[] getFloatArray(String key) {
return types.get(key) == StoredType.FloatArray ? (float[]) data.get(key) : null;
}
public int getInt(String key) {
return getInt(key, 0);
}
public int getInt(String key, int defaultValue) {
return types.get(key) == StoredType.Integer ? (Integer) data.get(key) : defaultValue;
}
public ArrayList<Integer> getIntegerArrayList(String key) {
return types.get(key) == StoredType.IntegerArrayList ? (ArrayList<Integer>) data.get(key) : null;
}
public long getLong(String key) {
return getLong(key, 0L);
}
public long getLong(String key, long defaultValue) {
return types.get(key) == StoredType.Long ? (Long) data.get(key) : defaultValue;
}
public long[] getLongArray(String key) {
return types.get(key) == StoredType.LongArray ? (long[]) data.get(key) : null;
}
public String getString(String key) {
return getString(key, null);
}
public String getString(String key, String defaultValue) {
return types.get(key) == StoredType.String ? (String) data.get(key) : defaultValue;
}
public String[] getStringArray(String key) {
return types.get(key) == StoredType.StringArray ? (String[]) data.get(key) : null;
}
public ArrayList<String> getStringArrayList(String key) {
return types.get(key) == StoredType.StringArrayList ? (ArrayList<String>) data.get(key) : null;
}
public int hashCode() {
return data.hashCode();
}
public boolean isEmpty() {
return data.isEmpty();
}
public Set<String> keySet() {
return data.keySet();
}
public void putAll(DataMap dataMap) {
for (String key : dataMap.keySet()) {
data.put(key, dataMap.data.get(key));
types.put(key, dataMap.types.get(key));
}
}
public void putAsset(String key, Asset value) {
data.put(key, value);
types.put(key, StoredType.Asset);
}
public void putBoolean(String key, boolean value) {
data.put(key, value);
types.put(key, StoredType.Boolean);
}
public void putByte(String key, byte value) {
data.put(key, value);
types.put(key, StoredType.Byte);
}
public void putByteArray(String key, byte[] value) {
data.put(key, value);
types.put(key, StoredType.ByteArray);
}
public void putDataMap(String key, DataMap value) {
data.put(key, value);
types.put(key, StoredType.DataMap);
}
public void putDataMapArrayList(String key, ArrayList<DataMap> value) {
data.put(key, value);
types.put(key, StoredType.DataMapArrayList);
}
public void putDouble(String key, double value) {
data.put(key, value);
types.put(key, StoredType.Double);
}
public void putFloat(String key, float value) {
data.put(key, value);
types.put(key, StoredType.Float);
}
public void putFloatArray(String key, float[] value) {
data.put(key, value);
types.put(key, StoredType.FloatArray);
}
public void putInt(String key, int value) {
data.put(key, value);
types.put(key, StoredType.Integer);
}
public void putIntegerArrayList(String key, ArrayList<Integer> value) {
data.put(key, value);
types.put(key, StoredType.IntegerArrayList);
}
public void putLong(String key, long value) {
data.put(key, value);
types.put(key, StoredType.Long);
}
public void putLongArray(String key, long[] value) {
data.put(key, value);
types.put(key, StoredType.LongArray);
}
public void putString(String key, String value) {
data.put(key, value);
types.put(key, StoredType.String);
}
public void putStringArray(String key, String[] value) {
data.put(key, value);
types.put(key, StoredType.StringArray);
}
public void putStringArrayList(String key, ArrayList<String> value) {
data.put(key, value);
types.put(key, StoredType.StringArrayList);
}
public Object remove(String key) {
types.remove(key);
return data.remove(key);
}
public int size() {
return data.size();
}
public Bundle toBundle() {
Bundle bundle = new Bundle();
for (String key : data.keySet()) {
switch (types.get(key)) {
case Asset:
bundle.putParcelable(key, (Asset) data.get(key));
break;
case Boolean:
bundle.putBoolean(key, (Boolean) data.get(key));
break;
case Byte:
bundle.putByte(key, (Byte) data.get(key));
break;
case ByteArray:
bundle.putByteArray(key, (byte[]) data.get(key));
break;
case DataMap:
bundle.putBundle(key, ((DataMap) data.get(key)).toBundle());
break;
case DataMapArrayList:
ArrayList<Bundle> bundles = new ArrayList<Bundle>();
for (DataMap dataMap : ((ArrayList<DataMap>) data.get(key))) {
bundles.add(dataMap.toBundle());
}
bundle.putParcelableArrayList(key, bundles);
break;
case Double:
bundle.putDouble(key, (Double) data.get(key));
break;
case Float:
bundle.putFloat(key, (Float) data.get(key));
break;
case FloatArray:
bundle.putFloatArray(key, (float[]) data.get(key));
break;
case Integer:
bundle.putInt(key, (Integer) data.get(key));
break;
case IntegerArrayList:
bundle.putIntegerArrayList(key, (ArrayList<Integer>) data.get(key));
break;
case Long:
bundle.putLong(key, (Long) data.get(key));
break;
case LongArray:
bundle.putLongArray(key, (long[]) data.get(key));
break;
case String:
bundle.putString(key, (String) data.get(key));
break;
case StringArray:
bundle.putStringArray(key, (String[]) data.get(key));
break;
case StringArrayList:
bundle.putStringArrayList(key, (ArrayList<String>) data.get(key));
break;
}
}
return bundle;
}
public byte[] toByteArray() {
return DataBundleUtil.createBytes(this);
}
public String toString() {
return "DataMap{size=" + size() + "}";
}
}