package com.gettingmobile.android.app.settings; import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.util.Log; import org.json.JSONArray; import org.json.JSONException; import java.util.*; import java.util.regex.Pattern; public abstract class AbstractSettings implements OnSharedPreferenceChangeListener { public static final String PREFERENCES_SUFFIX = "_preferences"; protected static final String LOG_TAG = "goodnews.Settings"; protected final Context context; protected final SharedPreferences prefs; private final Map<String, Set<OnSettingChangeListener>> listeners = new HashMap<String, Set<OnSettingChangeListener>>(); private final Set<OnSharedPreferenceChangeListener> allChangesListeners = new HashSet<OnSharedPreferenceChangeListener>(); public static String getPreferencesName(Context context, String suffix) { return context.getPackageName() + suffix; } public static SharedPreferences getPreferences(Context context, String suffix) { return context.getSharedPreferences(getPreferencesName(context, suffix), Context.MODE_PRIVATE); } public static SharedPreferences getDefaultPreferences(Context context) { return getPreferences(context, PREFERENCES_SUFFIX); } public AbstractSettings(Context context) { this.context = context; prefs = getDefaultPreferences(context); prefs.registerOnSharedPreferenceChangeListener(this); /* * register internal listeners */ } public SharedPreferences getSharedPreferences() { return prefs; } public void registerChangeListener(String key, OnSettingChangeListener listener) { Set<OnSettingChangeListener> keyListeners = listeners.get(key); if (keyListeners == null) { keyListeners = new HashSet<OnSettingChangeListener>(); listeners.put(key, keyListeners); } keyListeners.add(listener); } public void unregisterChangeListener(String key, OnSettingChangeListener listener) { final Set<OnSettingChangeListener> keyListeners = listeners.get(key); if (keyListeners != null) { keyListeners.remove(listener); if (keyListeners.isEmpty()) { listeners.remove(key); } } } public void registerChangeListener(OnSharedPreferenceChangeListener listener) { allChangesListeners.add(listener); } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { /* * call preference specific listeners listeners */ final Set<OnSettingChangeListener> keyListeners = listeners.get(key); if (keyListeners != null) { for (OnSettingChangeListener l : keyListeners) { l.onSettingChanged(this, sharedPreferences, key); } } /* * call unspecific listeners */ for (OnSharedPreferenceChangeListener l : allChangesListeners) { l.onSharedPreferenceChanged(sharedPreferences, key); } } /* * dynamic initialization of settings */ public <T extends Enum<T>> void setDefaultValue(String key, T value) { if (getString(key) == null) { setString(key, value.name()); } } /* * helper */ public boolean getBoolean(String key, boolean defaultValue) { return prefs.getBoolean(key, defaultValue); } public boolean getBoolean(String key) { return getBoolean(key, false); } public boolean getBooleanOverride(String overrideKey, String key, boolean compatibilityMode) { BooleanOverride override; try { override = getValue(BooleanOverride.class, overrideKey, BooleanOverride.GLOBAL); } catch (ClassCastException ex) { if (!compatibilityMode) throw ex; final boolean oldBooleanValue = getBoolean(overrideKey); final SharedPreferences.Editor editor = prefs.edit(); editor.remove(overrideKey); override = oldBooleanValue ? BooleanOverride.TRUE : BooleanOverride.GLOBAL; editor.putString(overrideKey, override.toString()); editor.commit(); } return override != BooleanOverride.GLOBAL ? override == BooleanOverride.TRUE : getBoolean(key); } public boolean getBooleanOverride(String overrideKey, String key) { return getBooleanOverride(overrideKey, key, false); } public void setBoolean(String key, boolean value) { final SharedPreferences.Editor editor = prefs.edit(); editor.putBoolean(key, value); editor.commit(); } public int getInt(String key) { return prefs.getInt(key, 0); } public void setInt(String key, int value) { final SharedPreferences.Editor editor = prefs.edit(); editor.putInt(key, value); editor.commit(); } public long getLong(String key) { return prefs.getLong(key, 0); } public void setLong(String key, long value) { final SharedPreferences.Editor editor = prefs.edit(); editor.putLong(key, value); editor.commit(); } public int getIntFromString(String key, int defValue) { final String str = prefs.getString(key, null); return str == null || str.length() == 0 ? defValue : Integer.parseInt(str); } public int getIntFromString(String key) { return getIntFromString(key, 0); } public String getString(String key) { return prefs.getString(key, null); } public void setString(String key, String value) { final SharedPreferences.Editor editor = prefs.edit(); editor.putString(key, value); editor.commit(); } public Calendar getTimestamp(String key) { final long timestamp = getLong(key); if (timestamp == 0) return null; final Calendar c = Calendar.getInstance(); c.setTimeInMillis(timestamp); return c; } public void setTimestamp(String key, Calendar timestamp) { setLong(key, timestamp.getTimeInMillis()); } public void setTimestamp(String key, long timestamp) { setLong(key, timestamp); } public void setTimestampToNow(String key) { setTimestamp(key, Calendar.getInstance()); } public void setTimestampFromNow(String key, int field, int amount) { final Calendar c = Calendar.getInstance(); c.add(field, amount); setTimestamp(key, c); } public Set<String> getStringSet(String key) { final String json = getString(key); if (json == null) return null; try { final JSONArray jsonArray = new JSONArray(json); final Set<String> strings = new HashSet<String>(jsonArray.length()); for (int i = 0; i < jsonArray.length(); ++i) { strings.add(jsonArray.getString(i)); } return strings; } catch (JSONException ex) { Log.e(LOG_TAG, "Failed to deserialize string set as JSON object", ex); return null; } } public void setStringSet(String key, Set<String> strings) { if (strings != null) { final JSONArray jsonArray = new JSONArray(); for (String s : strings) { jsonArray.put(s); } setString(key, jsonArray.toString()); } else { setString(key, null); } } public void extendStringSet(String key, Set<String> strings) { final Set<String> prevStrings = getStringSet(key); if (prevStrings != null) { prevStrings.addAll(strings); setStringSet(key, prevStrings); } else { setStringSet(key, strings); } } public <T extends Enum<T>> T getValue(Class<T> type, String key) { final String value = getString(key); try { return value != null ? T.valueOf(type, value) : null; } catch (IllegalArgumentException ex) { return null; } } public <T extends Enum<T>> T getValue(Class<T> type, String key, T defaultValue) { final T value = getValue(type, key); return value != null ? value : defaultValue; } public <T extends Enum<T>> T getValueOverride(Class<T> type, String overrideKey, String key, T defaultValue) { final T override = getValue(type, overrideKey); return override != null ? override : getValue(type, key, defaultValue); } public <T extends Enum<T>> void setValue(String key, T value) { setString(key, value.name()); } private Set<String> findMatchingEntryKeys(Pattern keyPattern, Pattern valuePattern) { final Set<String> matchingKeyEntries = new HashSet<String>(); for (Map.Entry<String, ?> entry : prefs.getAll().entrySet()) { if (entry.getValue() instanceof String) { final String key = entry.getKey(); final String value = (String) entry.getValue(); if (keyPattern.matcher(key).matches() && valuePattern.matcher(value).matches()) { matchingKeyEntries.add(key); } } } return matchingKeyEntries; } private void updateValues(Set<String> keys, String value) { final SharedPreferences.Editor editor = prefs.edit(); for (String key : keys) { Log.i(LOG_TAG, "Updating setting '" + key + "' to " + value); editor.putString(key, value); } editor.commit(); } protected void updateValues(String keyPattern, String valuePattern, String newValue) { final Set<String> matchingKeyEntries = findMatchingEntryKeys( Pattern.compile(keyPattern), Pattern.compile(valuePattern)); updateValues(matchingKeyEntries, newValue); } }