Android Open Source - AndroidLapTimer Default Preferences






From Project

Back to project page AndroidLapTimer.

License

The source code is released under:

MIT License

If you think the Android project AndroidLapTimer listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.pimentoso.android.laptimer;
/*  w w w  .ja  va 2 s.  c o  m*/
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Build;
import android.preference.PreferenceManager;

/**
 * Wrapper around SharedPreferences. See <a
 * href="http://stackoverflow.com/questions/19610569/">here</a> for a discussion
 * of some points.
 */
public final class DefaultPreferences {

  private static final List<Class<?>> CLASSES = new ArrayList<Class<?>>();
  private static SharedPreferences prefs; // cache
  static {
    CLASSES.add(String.class);
    CLASSES.add(Boolean.class);
    CLASSES.add(Integer.class);
    CLASSES.add(Long.class);
    CLASSES.add(Float.class);
    CLASSES.add(Set.class);
  }

  private DefaultPreferences() {}

  private static SharedPreferences getPrefs(Context ctx) {
    // synchronized is really needed or volatile is all I need (visibility)
    // the same instance of SharedPreferences will be returned AFAIC
    SharedPreferences result = prefs;
    if (result == null)
      synchronized (DefaultPreferences.class) {
        result = prefs;
        if (result == null) {
          result = prefs = PreferenceManager
            .getDefaultSharedPreferences(ctx);
        }
      }
    return result;
  }

  /**
   * Wrapper around {@link android.content.SharedPreferences.Editor}
   * {@code put()} methods. Null keys are not permitted. Attempts to insert a
   * null key will throw NullPointerException. Will call
   * {@link android.content.SharedPreferences.Editor#apply()} in Gingerbread
   * and above instead of commit. If you want to check the return value call
   * {@link #commit(Context, String, Object)}. When you call this method from
   * different threads the order of the operations is unspecified - you have
   * to synchronize externally if the order concerns you (especially for the
   * same key). If you want to put a long you must explicitly declare it
   * otherwise Java will interpret it as an Integer resulting in a
   * {@link ClassCastException} when you try to retrieve it (on get()
   * invocation). So :
   *
   * <pre>
   * put(ctx, LONG_KEY, 0); // you just persisted an Integer
   * get(ctx, LONG_KEY, 0L); // CCE here
   * put(ctx, LONG_KEY, 0L); // Correct, always specify you want a Long
   * get(ctx, LONG_KEY, 0L); // OK
   * </pre>
   *
   * You will get an {@link IllegalArgumentException} if the value is not an
   * instance of String, Boolean, Integer, Long, Float or Set<String> (see
   * below). This includes specifying a Double mistakenly thinking you
   * specified a Float. So :
   *
   * <pre>
   * put(ctx, FLOAT_KEY, 0.0); // IllegalArgumentException, 0.0 it's a Double
   * put(ctx, FLOAT_KEY, 0.0F); // Correct, always specify you want a Float
   * </pre>
   *
   * You will also get an IllegalArgumentException if you are trying to add a
   * Set<String> before API 11 (HONEYCOMB). You **can** persist a {@link Set}
   * that does not contain Strings using this method, but you are recommended
   * not to do so. It is untested and the Android API expects a Set<String>.
   * You can actually do so in the framework also but you will have raw and
   * unchecked warnings. Here you get no warnings - you've been warned. TODO :
   * clarify/test this behavior
   *
   * Finally, adding null values is supported - but keep in mind that:
   * <ol>
   * <li>you will get a NullPointerException if you put a null Boolean, Long,
   * Float or Integer and you then get() it and assign it to a primitive
   * (boolean, long, float or int). This is *not* how the prefs framework
   * works - it will immediately throw NullPointerException (which is better).
   * TODO : simulate this behavior</li>
   *
   * <li>you can put a null String or Set - but you will not get() null back
   * unless you specify a null default. For non null default you will get this
   * default back. This is in tune with the prefs framework</li>
   * </ol>
   *
   * @param ctx
   *            the context the Shared preferences belong to
   * @param key
   *            the preference's key, must not be {@code null}
   * @param value
   *            an instance of String, Boolean, Integer, Long, Float or
   *            Set<String> (for API >= HONEYCOMB)
   * @throws IllegalArgumentException
   *             if the value is not an instance of String, Boolean, Integer,
   *             Long, Float or Set<String> (including the case when you
   *             specify a double thinking you specified a float, see above)
   *             OR if you try to add a Set<String> _before_ HONEYCOMB API
   * @throws NullPointerException
   *             if key is {@code null}
   */
  @TargetApi(Build.VERSION_CODES.GINGERBREAD)
  public static <T> void put(final Context ctx, final String key,
      final T value) {
    final Editor ed = _put(ctx, key, value);
    if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD)
      ed.apply();
    else ed.commit();
  }

  /**
   * As {@link #put(Context, String, Object)} but will call
   * {@link android.content.SharedPreferences.Editor#commit()} in all API
   * versions. See {@link #put(Context, String, Object)} for detailed usage
   * notes.
   *
   * @param ctx
   *            the context the Shared preferences belong to
   * @param key
   *            the preference's key, must not be {@code null}
   * @param value
   *            an instance of String, Boolean, Integer, Long, Float or
   *            Set<String> (for API >= HONEYCOMB)
   * @return true if the commit succeeded, false if not
   * @throws IllegalArgumentException
   *             if the value is not an instance of String, Boolean, Integer,
   *             Long, Float or Set<String> (including the case when you
   *             specify a double thinking you specified a float, see put())
   *             OR if you try to add a Set<String> _before_ HONEYCOMB API
   * @throws NullPointerException
   *             if key is {@code null}
   */
  public static <T> boolean commit(final Context ctx, final String key,
      final T value) {
    return _put(ctx, key, value).commit();
  }

  @SuppressLint("CommitPrefEdits")
  @TargetApi(Build.VERSION_CODES.HONEYCOMB)
  private static <T> Editor _put(final Context ctx, final String key,
      final T value) {
    if (key == null)
      throw new NullPointerException("Null keys are not permitted");
    final Editor ed = getPrefs(ctx).edit();
    if (value == null) {
      // commit it as that is exactly what the API does (but not for boxed
      // primitives) - can be retrieved as anything but if you give get()
      // a default non null value it will give this default value back
      ed.putString(key, null);
      // btw the signature is given by the compiler as :
      // <Object> void
      // gr.uoa.di.android.helpers.AccessPreferences.put(Context ctx,
      // String key, Object value)
      // if I write AccessPreferences.put(ctx, "some_key", null);
    } else if (value instanceof String) ed.putString(key, (String) value);
    else if (value instanceof Boolean) ed.putBoolean(key, (Boolean) value);
    // while int "is-a" long (will be converted to long) Integer IS NOT a
    // Long (CCE) - so the order of "instanceof" checks does not matter -
    // except for frequency I use the values (so I put String, Boolean and
    // Integer first as I mostly use those preferences)
    else if (value instanceof Integer) ed.putInt(key, (Integer) value);
    else if (value instanceof Long) ed.putLong(key, (Long) value);
    else if (value instanceof Float) ed.putFloat(key, (Float) value);
    else if (value instanceof Set) {
      if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
        throw new IllegalArgumentException(
          "You can add sets in the preferences only after API "
            + Build.VERSION_CODES.HONEYCOMB);
      }
      @SuppressWarnings({ "unchecked", "unused" })
      // this set can contain whatever it wants - don't be fooled by the
      // Set<String> cast
      Editor dummyVariable = ed.putStringSet(key, (Set<String>) value);
    } else throw new IllegalArgumentException("The given value : " + value
      + " cannot be persisted");
    return ed;
  }

  /**
   * Wrapper around {@link android.content.SharedPreferences.Editor}
   * {@code get()} methods. Null keys are not permitted. Attempts to retrieve
   * a preference with a null key will throw NullPointerException. As far as
   * the type system is concerned T is of the type the variable that is to
   * receive the default value is. You will get a {@link ClassCastException}
   * if you put() in a value of type T and try to get() a value of different
   * type Y - except if you specify a null default *where you will get the CCE
   * only if you try to assign the get() return value to a variable of type Y,
   * _in the assignment_ after get() returns*. So don't do this :
   *
   * <pre>
   * AccessPreferences.put(ctx, BOOLEAN_KEY, DEFAULT_BOOLEAN);
   * AccessPreferences.get(ctx, BOOLEAN_KEY, DEFAULT_STRING); // CCE !
   * AccessPreferences.get(ctx, BOOLEAN_KEY, null); // NO CCE !!! (***)
   * String dummy = AccessPreferences.get(ctx, BOOLEAN_KEY, null); // CCE
   * </pre>
   *
   * This is unlike the Preferences framework where you will get a
   * ClassCastException even if you specify a default null value:
   *
   * <pre>
   * ed.putBoolean(BOOLEAN_KEY, DEFAULT_BOOLEAN);
   * ed.commit();
   * prefs.getString(BOOLEAN_KEY, null); // CCE - unlike AccessPreferences!
   * prefs.getString(BOOLEAN_KEY, &quot;a string&quot;); // CCE
   * </pre>
   *
   * TODO : correct this (***)
   *
   * If you put a Set<?> you will get it out as a set of strings - I am not
   * entirely clear on this
   *
   * @param ctx
   *            the context the Shared preferences belong to
   * @param key
   *            the preference's key, must not be {@code null}
   * @param defaultValue
   * @return
   * @throws ClassCastException
   *             If you try to get a different type than the one you put in -
   *             except if you specify a null default (***). For other CCEs
   *             see the {@link #put(Context, String, Object)} docs
   * @throws IllegalArgumentException
   *             if a given default value's type is not among the accepted
   *             classes for preferences or if a Set is given as default or
   *             asked for before HONEYCOMB API
   * @throws IllegalStateException
   *             if I can't figure out the class of a value retrieved from
   *             preferences (when default is null)
   * @throws NullPointerException
   *             if key is {@code null}
   */
  @SuppressWarnings("unchecked")
  @TargetApi(Build.VERSION_CODES.HONEYCOMB)
  public static <T> T get(final Context ctx, final String key,
      final T defaultValue) {
    if (key == null)
      throw new NullPointerException("Null keys are not permitted");
    // if the value provided as defaultValue is null I can't get its class
    if (defaultValue == null) {
      // if the key !exist I return null which is both the default value
      // provided and what Android would do (as in return the default
      // value - except if boxed primitive..)
      if (!getPrefs(ctx).contains(key)) return null;
      // if the key does exist I get the value and..
      final Object value = getPrefs(ctx).getAll().get(key);
      // ..if null I return null - here I differ from framework - I return
      // null for boxed primitives
      if (value == null) return null;
      // ..if not null I get the class of the non null value. Here I
      // differ from framework - I do not throw if the (non null) value is
      // not of the type the variable to receive it is - cause I have no
      // way to guess the return value expected ! (***)
      final Class<?> valueClass = value.getClass();
      // the order of "instanceof" checks does not matter - still if I
      // have a long autoboxed as Integer ? - tested in
      // testAPNullDefaultUnboxingLong() and works OK (long 0L is
      // autoboxed as long)
      for (Class<?> cls : CLASSES) {
        if (valueClass.isAssignableFrom(cls)) {
          // try {
          // I can't directly cast to T as value may be boolean
          // for instance
          return (T) valueClass.cast(value);
          // } catch (ClassCastException e) { // won't work see :
          // //
          // http://stackoverflow.com/questions/186917/
          // (how-do-i-catch-classcastexception)
          // // basically the (T) valueClass.cast(value); line is
          // // translated to (Object) valueClass.cast(value); which
          // // won't fail ever - the CCE is thrown in the assignment
          // // (T t =) String s = AccessPreferences.get(this, "key",
          // // null); which is compiled as
          // // (String) AccessPreferences.get(this, "key",
          // // null); and get returns an Integer for instance
          // String msg = "Value : " + value + " stored for key : "
          // + key
          // + " is not assignable to variable of given type.";
          // throw new IllegalStateException(msg, e);
          // }
        }
      }
      // that's really Illegal State I guess
      throw new IllegalStateException("Unknown class for value :\n\t"
        + value + "\nstored in preferences");
    } else if (defaultValue instanceof String) return (T) getPrefs(ctx)
      .getString(key, (String) defaultValue);
    else if (defaultValue instanceof Boolean) return (T) (Boolean) getPrefs(
      ctx).getBoolean(key, (Boolean) defaultValue);
    // the order should not matter
    else if (defaultValue instanceof Integer) return (T) (Integer) getPrefs(
      ctx).getInt(key, (Integer) defaultValue);
    else if (defaultValue instanceof Long) return (T) (Long) getPrefs(ctx)
      .getLong(key, (Long) defaultValue);
    else if (defaultValue instanceof Float) return (T) (Float) getPrefs(ctx)
      .getFloat(key, (Float) defaultValue);
    else if (defaultValue instanceof Set) {
      if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
        throw new IllegalArgumentException(
          "You can add sets in the preferences only after API "
            + Build.VERSION_CODES.HONEYCOMB);
      }
      // this set can contain whatever it wants - don't be fooled by the
      // Set<String> cast
      return (T) getPrefs(ctx).getStringSet(key,
        (Set<String>) defaultValue);
    } else throw new IllegalArgumentException(defaultValue
      + " cannot be persisted in SharedPreferences");
  }

  /**
   * Wraps {@link android.content.SharedPreferences#contains(String)}.
   *
   * @param ctx
   *            the context the SharedPreferences belong to
   * @param key
   *            the preference's key, must not be {@code null}
   * @return true if the preferences contain the given key, false otherwise
   * @throws NullPointerException
   *             if key is {@code null}
   */
  public static boolean contains(Context ctx, String key) {
    if (key == null)
      throw new NullPointerException("Null keys are not permitted");
    return getPrefs(ctx).contains(key);
  }

  /**
   * Wraps {@link android.content.SharedPreferences#getAll()}. Since you must
   * not modify the collection returned by this method, or alter any of its
   * contents, this method returns an <em>unmodifiableMap</em> representing
   * the preferences.
   *
   * @param ctx
   *            the context the SharedPreferences belong to
   * @return an <em>unmodifiableMap</em> containing a list of key/value pairs
   *         representing the preferences
   * @throws NullPointerException
   *             as per the docs of getAll() - does not say when
   */
  public static Map<String, ?> getAll(Context ctx) {
    return Collections.unmodifiableMap(getPrefs(ctx).getAll());
  }

  /**
   * Wraps {@link android.content.SharedPreferences.Editor#clear()}. See its
   * docs for clarifications. Calls
   * {@link android.content.SharedPreferences.Editor#commit()}
   *
   * @param ctx
   *            the context the SharedPreferences belong to
   * @return true if the preferences were successfully cleared, false
   *         otherwise
   */
  public static boolean clear(Context ctx) {
    return getPrefs(ctx).edit().clear().commit();
  }

  /**
   * Wraps {@link android.content.SharedPreferences.Editor#remove(String)}.
   * See its docs for clarifications. Calls
   * {@link android.content.SharedPreferences.Editor#commit()}.
   *
   * @param ctx
   *            the context the SharedPreferences belong to
   * @param key
   *            the preference's key, must not be {@code null}
   * @return true if the key was successfully removed, false otherwise
   * @throws NullPointerException
   *             if key is {@code null}
   */
  public static boolean remove(Context ctx, String key) {
    if (key == null)
      throw new NullPointerException("Null keys are not permitted");
    return getPrefs(ctx).edit().remove(key).commit();
  }

  /**
   * Wraps
   * {@link android.content.SharedPreferences#registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener)}
   * .
   *
   * @param ctx
   *            the context the SharedPreferences belong to
   * @param lis
   *            the listener, must not be null
   * @throws NullPointerException
   *             if lis is {@code null}
   */
  public static void registerListener(Context ctx,
      OnSharedPreferenceChangeListener lis) {
    if (lis == null) throw new NullPointerException("Null listener");
    getPrefs(ctx).registerOnSharedPreferenceChangeListener(lis);
  }

  /**
   * Wraps
   * {@link android.content.SharedPreferences#unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener)}
   * .
   *
   * @param ctx
   *            the context the SharedPreferences belong to
   * @param lis
   *            the listener, must not be null
   * @throws NullPointerException
   *             if lis is {@code null}
   */
  public static void unregisterListener(Context ctx,
      OnSharedPreferenceChangeListener lis) {
    if (lis == null) throw new NullPointerException("Null listener");
    getPrefs(ctx).unregisterOnSharedPreferenceChangeListener(lis);
  }

  /**
   * Wraps
   * {@link android.content.SharedPreferences.OnSharedPreferenceChangeListener#onSharedPreferenceChanged(SharedPreferences, String)}
   * .
   *
   * @param ctx
   *            the context the SharedPreferences belong to
   * @param lis
   *            the listener, must not be null
   * @param key
   *            the key we want to run onSharedPreferenceChanged on, must not
   *            be null
   * @throws NullPointerException
   *             if lis or key is {@code null}
   */
  public static void callListener(Context ctx,
      OnSharedPreferenceChangeListener lis, String key) {
    if (lis == null) throw new NullPointerException("Null listener");
    if (key == null)
      throw new NullPointerException("Null keys are not permitted");
    lis.onSharedPreferenceChanged(getPrefs(ctx), key);
  }

  /**
   * Check that the given set contains strings only.
   *
   * @param set
   * @return the set cast to Set<String>
   */
  @SuppressWarnings("unused")
  private static Set<String> checkSetContainsStrings(Set<?> set) {
    if (!set.isEmpty()) {
      for (Object object : set) {
        if (!(object instanceof String))
          throw new IllegalArgumentException(
            "The given set does not contain strings only");
      }
    }
    @SuppressWarnings("unchecked")
    final Set<String> stringSet = (Set<String>) set;
    return stringSet;
  }
}




Java Source Code List

com.pimentoso.android.laptimer.DefaultPreferences.java
com.pimentoso.android.laptimer.FPSCounter.java
com.pimentoso.android.laptimer.LapListAdapter.java
com.pimentoso.android.laptimer.SensitivityDialogActivity.java
com.pimentoso.android.laptimer.TimerActivity.java
com.pimentoso.android.laptimer.Utils.java