All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.getpebble.android.kit.util.PebbleDictionary Maven / Gradle / Ivy

There is a newer version: 4.0.1
Show newest version
package com.getpebble.android.kit.util;

import android.util.Base64;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * A collection of key-value pairs of heterogeneous types. PebbleDictionaries are the primary structure used to exchange
 * data between the phone and watch.
 * 

* To accommodate the mixed-types contained within a PebbleDictionary, an internal JSON representation is used when * exchanging the dictionary between Android processes. * * @author [email protected] */ public class PebbleDictionary implements Iterable { private static final String KEY = "key"; private static final String TYPE = "type"; private static final String LENGTH = "length"; private static final String VALUE = "value"; protected final Map tuples = new HashMap(); /** * {@inheritDoc} */ @Override public Iterator iterator() { return tuples.values().iterator(); } /** * Returns the number of key-value pairs in this dictionary. * * @return the number of key-value pairs in this dictionary */ public int size() { return tuples.size(); } /** * Returns true if this dictionary contains a mapping for the specified key. * * @param key * key whose presence in this dictionary is to be tested * * @return true if this dictionary contains a mapping for the specified key */ public boolean contains(final int key) { return tuples.containsKey(key); } /** * Removes the mapping for a key from this map if it is present. * * @param key * key to be removed from the dictionary */ public void remove(final int key) { tuples.remove(key); } /** * Associate the specified byte array with the provided key in the dictionary. If another key-value pair with the * same key is already present in the dictionary, it will be replaced. * * @param key * key with which the specified value is associated * @param bytes * value to be associated with the specified key */ public void addBytes(int key, byte[] bytes) { PebbleTuple t = PebbleTuple.create(key, PebbleTuple.TupleType.BYTES, PebbleTuple.Width.NONE, bytes); addTuple(t); } /** * Associate the specified String with the provided key in the dictionary. If another key-value pair with the same * key is already present in the dictionary, it will be replaced. * * @param key * key with which the specified value is associated * @param value * value to be associated with the specified key */ public void addString(int key, String value) { PebbleTuple t = PebbleTuple.create(key, PebbleTuple.TupleType.STRING, PebbleTuple.Width.NONE, value); addTuple(t); } /** * Associate the specified signed byte with the provided key in the dictionary. If another key-value pair with the * same key is already present in the dictionary, it will be replaced. * * @param key * key with which the specified value is associated * @param b * value to be associated with the specified key */ public void addInt8(final int key, final byte b) { PebbleTuple t = PebbleTuple.create(key, PebbleTuple.TupleType.INT, PebbleTuple.Width.BYTE, b); addTuple(t); } /** * Associate the specified unsigned byte with the provided key in the dictionary. If another key-value pair with the * same key is already present in the dictionary, it will be replaced. * * @param key * key with which the specified value is associated * @param b * value to be associated with the specified key */ public void addUint8(final int key, final byte b) { PebbleTuple t = PebbleTuple.create(key, PebbleTuple.TupleType.UINT, PebbleTuple.Width.BYTE, b); addTuple(t); } /** * Associate the specified signed short with the provided key in the dictionary. If another key-value pair with the * same key is already present in the dictionary, it will be replaced. * * @param key * key with which the specified value is associated * @param s * value to be associated with the specified key */ public void addInt16(final int key, final short s) { PebbleTuple t = PebbleTuple.create(key, PebbleTuple.TupleType.INT, PebbleTuple.Width.SHORT, s); addTuple(t); } /** * Associate the specified unsigned short with the provided key in the dictionary. If another key-value pair with * the same key is already present in the dictionary, it will be replaced. * * @param key * key with which the specified value is associated * @param s * value to be associated with the specified key */ public void addUint16(final int key, final short s) { PebbleTuple t = PebbleTuple.create(key, PebbleTuple.TupleType.UINT, PebbleTuple.Width.SHORT, s); addTuple(t); } /** * Associate the specified signed int with the provided key in the dictionary. If another key-value pair with the * same key is already present in the dictionary, it will be replaced. * * @param key * key with which the specified value is associated * @param i * value to be associated with the specified key */ public void addInt32(final int key, final int i) { PebbleTuple t = PebbleTuple.create(key, PebbleTuple.TupleType.INT, PebbleTuple.Width.WORD, i); addTuple(t); } /** * Associate the specified unsigned int with the provided key in the dictionary. If another key-value pair with the * same key is already present in the dictionary, it will be replaced. * * @param key * key with which the specified value is associated * @param i * value to be associated with the specified key */ public void addUint32(final int key, final int i) { PebbleTuple t = PebbleTuple.create(key, PebbleTuple.TupleType.UINT, PebbleTuple.Width.WORD, i); addTuple(t); } private PebbleTuple getTuple(int key, PebbleTuple.TupleType type) { if (!tuples.containsKey(key) || tuples.get(key) == null) { return null; } PebbleTuple t = tuples.get(key); if (t.type != type) { throw new PebbleDictTypeException(key, type, t.type); } return t; } /** * Returns the signed integer to which the specified key is mapped, or null if the key does not exist in this * dictionary. * * @param key * key whose associated value is to be returned * * @return value to which the specified key is mapped */ public Long getInteger(int key) { PebbleTuple tuple = getTuple(key, PebbleTuple.TupleType.INT); if (tuple == null) { return null; } return (Long) tuple.value; } /** * Returns the unsigned integer to which the specified key is mapped, or null if the key does not exist in this * dictionary. * * @param key * key whose associated value is to be returned * * @return value to which the specified key is mapped */ public Long getUnsignedInteger(int key) { PebbleTuple tuple = getTuple(key, PebbleTuple.TupleType.UINT); if (tuple == null) { return null; } return (Long) tuple.value; } /** * Returns the byte array to which the specified key is mapped, or null if the key does not exist in this * dictionary. * * @param key * key whose associated value is to be returned * * @return value to which the specified key is mapped */ public byte[] getBytes(int key) { PebbleTuple tuple = getTuple(key, PebbleTuple.TupleType.BYTES); if (tuple == null) { return null; } return (byte[]) tuple.value; } /** * Returns the string to which the specified key is mapped, or null if the key does not exist in this dictionary. * * @param key * key whose associated value is to be returned * * @return value to which the specified key is mapped */ public String getString(int key) { PebbleTuple tuple = getTuple(key, PebbleTuple.TupleType.STRING); if (tuple == null) { return null; } return (String) tuple.value; } protected void addTuple(PebbleTuple tuple) { if (tuples.size() > 0xff) { throw new TupleOverflowException(); } tuples.put(tuple.key, tuple); } public static class PebbleDictTypeException extends RuntimeException { public PebbleDictTypeException(long key, PebbleTuple.TupleType expected, PebbleTuple.TupleType actual) { super(String.format( "Expected type '%s', but got '%s' for key 0x%08x", expected.name(), actual.name(), key)); } } public static class TupleOverflowException extends RuntimeException { public TupleOverflowException() { super("Too many tuples in dict"); } } /** * Returns a JSON representation of this dictionary. * * @return a JSON representation of this dictionary */ public String toJsonString() { try { JSONArray array = new JSONArray(); for (PebbleTuple t : tuples.values()) { array.put(serializeTuple(t)); } return array.toString(); } catch (JSONException je) { je.printStackTrace(); } return null; } /** * Deserializes a JSON representation of a PebbleDictionary. * * @param jsonString * the JSON representation to be deserialized * * @throws JSONException * thrown if the specified JSON representation cannot be parsed */ public static PebbleDictionary fromJson(String jsonString) throws JSONException { PebbleDictionary d = new PebbleDictionary(); JSONArray elements = new JSONArray(jsonString); for (int idx = 0; idx < elements.length(); ++idx) { JSONObject o = elements.getJSONObject(idx); final int key = o.getInt(KEY); final PebbleTuple.TupleType type = PebbleTuple.TYPE_NAMES.get(o.getString(TYPE)); final PebbleTuple.Width width = PebbleTuple.WIDTH_MAP.get(o.getInt(LENGTH)); switch (type) { case BYTES: byte[] bytes = Base64.decode(o.getString(VALUE), Base64.NO_WRAP); d.addBytes(key, bytes); break; case STRING: d.addString(key, o.getString(VALUE)); break; case INT: if (width == PebbleTuple.Width.BYTE) { d.addInt8(key, (byte) o.getInt(VALUE)); } else if (width == PebbleTuple.Width.SHORT) { d.addInt16(key, (short) o.getInt(VALUE)); } else if (width == PebbleTuple.Width.WORD) { d.addInt32(key, o.getInt(VALUE)); } break; case UINT: if (width == PebbleTuple.Width.BYTE) { d.addUint8(key, (byte) o.getInt(VALUE)); } else if (width == PebbleTuple.Width.SHORT) { d.addUint16(key, (short) o.getInt(VALUE)); } else if (width == PebbleTuple.Width.WORD) { d.addUint32(key, o.getInt(VALUE)); } break; } } return d; } private static JSONObject serializeTuple(PebbleTuple t) throws JSONException { JSONObject j = new JSONObject(); j.put(KEY, t.key); j.put(TYPE, t.type.getName()); j.put(LENGTH, t.width.value); switch (t.type) { case BYTES: j.put(VALUE, Base64.encodeToString((byte[]) t.value, Base64.NO_WRAP)); break; case STRING: case INT: case UINT: j.put(VALUE, t.value); break; } return j; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy