/** * Funf: Open Sensing Framework * Copyright (C) 2010-2011 Nadav Aharony, Wei Pan, Alex Pentland. * Acknowledgments: Alan Gardner * Contact: nadav@media.mit.edu * * This file is part of Funf. * * Funf is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. * * Funf is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with Funf. If not, see <http://www.gnu.org/licenses/>. */ package edu.mit.media.funf; import static edu.mit.media.funf.AsyncSharedPrefs.async; import java.io.Closeable; import java.io.File; import java.io.IOException; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.UUID; import android.content.Context; import android.content.SharedPreferences; import android.database.Cursor; import android.os.Bundle; import android.os.Environment; import android.os.Parcelable; import android.os.PowerManager; import android.util.Log; import edu.mit.media.funf.probe.ProbeExceptions.UnstorableTypeException; public final class Utils { public static final String TAG = "Funf"; /** * Should not be instantiated. Used only as a namespace for static Utils functions */ private Utils() { } private static String getStoredBundleParamKey(final String key, final String paramKey) { return key + "__" + paramKey; } private static boolean isStoredBundleParamKey(final String key, final String storedParamKey) { final String prefix = key + "__"; return key.startsWith(prefix); } private static String getBundleParamKey(final String key, final String storedParamKey) { final String prefix = key + "__"; assert key.startsWith(prefix); return storedParamKey.substring(prefix.length()); } /** * Convenience function for adding the object form of primitives to a SharedPreferences * @param editor * @param key * @param value Must be Boolean, Float, Integer, Long, String, or Bundle (bundles must only contain the same) * @return * @throws UnstorableTypeException */ public static SharedPreferences.Editor putInPrefs(SharedPreferences.Editor editor, String key, Object value) throws UnstorableTypeException { if (value == null) { editor.putString(key, null); return editor; } Class<?> valueClass = value.getClass(); if (Boolean.class.isAssignableFrom(valueClass)) { editor.putBoolean(key, ((Boolean)value).booleanValue()); } else if (Integer.class.isAssignableFrom(valueClass)) { editor.putInt(key, ((Integer) value).intValue()); } else if (Float.class.isAssignableFrom(valueClass)) { editor.putFloat(key, ((Float) value).floatValue()); } else if (Long.class.isAssignableFrom(valueClass)) { editor.putLong(key, ((Long) value).longValue()); } else if (String.class.isAssignableFrom(valueClass)) { editor.putString(key, ((String) value)); } else if (Bundle.class.isAssignableFrom(valueClass)) { // Serialize the bundle using the key as a prefix Bundle bundle = ((Bundle) value); for (String bundleKey : bundle.keySet()) { Object bundleValue = bundle.get(bundleKey); putInPrefs(editor, getStoredBundleParamKey(key, bundleKey), bundleValue); } } else { throw new UnstorableTypeException(valueClass); } return editor; } /** * Parse a bundle from data stored in a SharedPreferences * @param prefs * @param key * @return */ public static Bundle getBundleFromPrefs(SharedPreferences prefs, String key) { Bundle bundle = new Bundle(); Map<String,?> prefsMap = prefs.getAll(); for (String prefsKey : prefsMap.keySet()) { if (isStoredBundleParamKey(key, prefsKey)) { try { putInBundle(bundle, getBundleParamKey(key, prefsKey), prefsMap.get(prefsKey)); } catch (UnstorableTypeException e) { Log.e(TAG, "Should never happen, since SharedPrefs stores only types Bundle can store: ", e); } } } return bundle; } /** * Convenience function for putting the object form of primitives into a Bundle * @param bundle * @param key * @param value Must be Boolean, Float, Integer, Long, or String * @throws UnstorableTypeException */ public static void putInBundle(Bundle bundle, String key, Object value) throws UnstorableTypeException { Class<?> valueClass = value.getClass(); if (Boolean.class.isAssignableFrom(valueClass)) { bundle.putBoolean(key, ((Boolean)value).booleanValue()); } else if (Short.class.isAssignableFrom(valueClass)) { bundle.putShort(key, ((Short) value).shortValue()); } else if (Integer.class.isAssignableFrom(valueClass)) { bundle.putInt(key, ((Integer) value).intValue()); } else if (Long.class.isAssignableFrom(valueClass)) { bundle.putLong(key, ((Long) value).longValue()); } else if (Float.class.isAssignableFrom(valueClass)) { bundle.putFloat(key, ((Float) value).floatValue()); } else if (Double.class.isAssignableFrom(valueClass)) { bundle.putDouble(key, ((Double) value).doubleValue()); } else if (String.class.isAssignableFrom(valueClass)) { bundle.putString(key, ((String) value)); } else { throw new UnstorableTypeException(valueClass); } } /** * Convenience function for joining strings using a delimeter * @param strings * @param delimeter * @return */ public static String join(final Collection<?> strings, String delimeter) { if (delimeter == null) { delimeter = ","; } if (strings.isEmpty()) { return ""; } StringBuffer joined = new StringBuffer(); Iterator<?> stringIter = strings.iterator(); joined.append(stringIter.next().toString()); while (stringIter.hasNext()) { joined.append(delimeter); joined.append(stringIter.next().toString()); } return joined.toString(); } /** * Convenience function for concatenating two arrays * @param <T> * @param first * @param second * @return */ @SuppressWarnings("unchecked") public static <T> T[] concat(T[] first, T[] second) { T[] result = (T[])new Object[first.length + second.length]; System.arraycopy(first, 0, result, 0, first.length); System.arraycopy(second, 0, result, first.length, second.length); return result; } public static Bundle[] copyBundleArray(Parcelable[] parcelables) { if (parcelables == null) { return new Bundle[0]; } Bundle[] bundles = new Bundle[parcelables.length]; System.arraycopy(parcelables, 0, bundles, 0, parcelables.length); return bundles; } public static Map<String,Object> getValues(final Bundle bundle) { HashMap<String, Object> values = new HashMap<String, Object>(); if (bundle == null) { return values; } for (String key : bundle.keySet()) { values.put(key, bundle.get(key)); } return values; } public static <T extends Parcelable> ArrayList<T> getArrayList(Bundle bundle, String key) { if (bundle == null) { return null; } Object o = bundle.get(key); try { return (ArrayList<T>) o; } catch (ClassCastException e) { try { return new ArrayList<T>(Arrays.asList((T[])o)); } catch (ClassCastException e2) { Log.w(TAG, "Unable to succesfully parse ArrayList from '" + key + "'"); return null; } } } /** * Convenience function for returning an empty string array if null is returned * @param array * @return */ public static String[] nonNullStrings(String[] array) { return (array == null) ? new String[] {} : array; } public static PowerManager.WakeLock getWakeLock(Context context) { PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); PowerManager.WakeLock lock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, context.getClass().getName()); lock.acquire(); return lock; } /** * Useful function to coerce value to a long, no matter what type of object is in the bundle * @param bundle * @param key * @param defaultValue * @return */ public static long getLong(Bundle bundle, String key, long defaultValue) { Object value = bundle.get(key); if (value instanceof Long) { return (Long)value; } else if (value instanceof Integer) { return ((Integer)value).longValue(); } else if (value instanceof String) { try { return Long.valueOf((String)value); } catch (NumberFormatException e) { // We did our best, value is not a long } } return defaultValue; } @SuppressWarnings("unchecked") public static <T> T getCursorData(Cursor cursor, int columnIndex, Class<T> dataType) { if (dataType.equals(String.class)) { return (T)cursor.getString(columnIndex); } else if (dataType.equals(Short.class)) { return (T) Short.valueOf(cursor.getShort(columnIndex)); } else if (dataType.equals(Integer.class)) { return (T) Integer.valueOf(cursor.getInt(columnIndex)); } else if (dataType.equals(Long.class)) { return (T) Long.valueOf(cursor.getLong(columnIndex)); } else if (dataType.equals(Float.class)) { return (T) Float.valueOf(cursor.getFloat(columnIndex)); } else if (dataType.equals(Double.class)) { return (T) Double.valueOf(cursor.getDouble(columnIndex)); } else { return null; } } public static final String FUNF_UTILS_PREFS = "edu.mit.media.funf.Utils"; public static final String INSTALLATION_UUID_KEY = "INSTALLATION_UUID"; public static String uuid = null; public static String getInstallationId(Context context) { if (uuid == null) { SharedPreferences prefs = async(context.getSharedPreferences(FUNF_UTILS_PREFS, Context.MODE_PRIVATE)); uuid = prefs.getString(INSTALLATION_UUID_KEY, null); if (uuid == null) { uuid = UUID.randomUUID().toString(); prefs.edit().putString(INSTALLATION_UUID_KEY, uuid).commit(); } } return uuid; } public static String getSdCardPath(Context context) { return new File(Environment.getExternalStorageDirectory(), context.getPackageName()) + "/"; } /** * Closes a stream, and swallows null cases our IOExceptions. * @param stream */ public static boolean close(Closeable stream) { if(stream != null) { try { stream.close(); return true; } catch (IOException e) { Log.e(TAG, "Error closing stream", e); } } return false; } public static long getTimestamp() { return millisToSeconds(System.currentTimeMillis()); } public static long getTimestampMillis() { return System.currentTimeMillis(); } public static long millisToSeconds(long millis) { return millis/1000L; } public static long secondsToMillis(long seconds) { return seconds*1000L; } }