preferences object

This commit is contained in:
Sergey Solovyev
2011-12-25 15:00:09 +04:00
parent 422fd8f693
commit 1dbec40d12
28 changed files with 410 additions and 106 deletions

View File

@@ -0,0 +1,66 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.view.prefs;
import android.content.SharedPreferences;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* User: serso
* Date: 12/25/11
* Time: 12:23 PM
*/
public abstract class AbstractPreference<T> implements Preference<T> {
@NotNull
private final String key;
private final T defaultValue;
protected AbstractPreference(@NotNull String key, @Nullable T defaultValue) {
this.key = key;
this.defaultValue = defaultValue;
}
@NotNull
public String getKey() {
return key;
}
public T getDefaultValue() {
return defaultValue;
}
@Override
public final T getPreference(@NotNull SharedPreferences preferences) {
if ( preferences.contains(this.key) ) {
return getPersistedValue(preferences);
} else {
return this.defaultValue;
}
}
@Nullable
protected abstract T getPersistedValue(@NotNull SharedPreferences preferences);
@Override
public void putDefault(@NotNull SharedPreferences preferences) {
putPreference(preferences, this.defaultValue);
}
@Override
public void putPreference(@NotNull SharedPreferences preferences, @Nullable T value) {
if (value != null) {
final SharedPreferences.Editor editor = preferences.edit();
putPersistedValue(editor, value);
editor.commit();
}
}
protected abstract void putPersistedValue(@NotNull SharedPreferences.Editor editor, @NotNull T value);
}

View File

@@ -1,92 +0,0 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.view.prefs;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TabHost;
import android.widget.TextView;
import org.jetbrains.annotations.NotNull;
/**
* User: serso
* Date: 12/21/11
* Time: 11:54 PM
*/
public final class AndroidUtils {
// not intended for instantiation
private AndroidUtils() {
throw new AssertionError();
}
public static void centerAndWrapTabsFor(@NotNull TabHost tabHost) {
int tabCount = tabHost.getTabWidget().getTabCount();
for (int i = 0; i < tabCount; i++) {
final View view = tabHost.getTabWidget().getChildTabViewAt(i);
if ( view != null ) {
if (view.getLayoutParams().height > 0) {
// reduce height of the tab
view.getLayoutParams().height *= 0.8;
}
// get title text view
final View textView = view.findViewById(android.R.id.title);
if ( textView instanceof TextView) {
// just in case check the type
// center text
((TextView) textView).setGravity(Gravity.CENTER);
// wrap text
((TextView) textView).setSingleLine(false);
// explicitly set layout parameters
textView.getLayoutParams().height = ViewGroup.LayoutParams.FILL_PARENT;
textView.getLayoutParams().width = ViewGroup.LayoutParams.WRAP_CONTENT;
}
}
}
}
public static void addTab(@NotNull Context context,
@NotNull TabHost tabHost,
@NotNull String tabId,
int tabCaptionId,
@NotNull Class<? extends Activity> activityClass) {
TabHost.TabSpec spec;
final Intent intent = new Intent().setClass(context, activityClass);
// Initialize a TabSpec for each tab and add it to the TabHost
spec = tabHost.newTabSpec(tabId).setIndicator(context.getString(tabCaptionId)).setContent(intent);
tabHost.addTab(spec);
}
/**
* @param context context
* @param appPackageName - full name of the package of an app, 'com.example.app' for example.
* @return version number we are currently in
*/
public static int getAppVersionCode(@NotNull Context context, @NotNull String appPackageName) {
try {
return context.getPackageManager().getPackageInfo(appPackageName, 0).versionCode;
} catch (PackageManager.NameNotFoundException e) {
// App not installed!
}
return -1;
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.view.prefs;
import android.content.SharedPreferences;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* User: serso
* Date: 12/25/11
* Time: 1:06 PM
*/
public class BooleanPreference extends AbstractPreference<Boolean>{
public BooleanPreference(@NotNull String key, @Nullable Boolean defaultValue) {
super(key, defaultValue);
}
@Override
protected Boolean getPersistedValue(@NotNull SharedPreferences preferences) {
return preferences.getBoolean(getKey(), false);
}
@Override
protected void putPersistedValue(@NotNull SharedPreferences.Editor editor, @NotNull Boolean value) {
editor.putBoolean(getKey(), value);
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.view.prefs;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.common.utils.Mapper;
/**
* User: serso
* Date: 12/25/11
* Time: 1:17 PM
*/
public class EnumMapper<T extends Enum> implements Mapper<T>{
@NotNull
private final Class<T> enumClass;
public EnumMapper(@NotNull Class<T> enumClass) {
this.enumClass = enumClass;
}
public static <T extends Enum> Mapper<T> newInstance(@NotNull Class<T> enumClass) {
return new EnumMapper<T>(enumClass);
}
@Override
public String formatValue(@Nullable T value) throws IllegalArgumentException {
return value == null ? null : value.name();
}
@Override
public T parseValue(@Nullable String value) throws IllegalArgumentException {
return value == null ? null : (T)Enum.valueOf(enumClass, value);
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.view.prefs;
import android.content.SharedPreferences;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* User: serso
* Date: 12/25/11
* Time: 1:08 PM
*/
public class FloatPreference extends AbstractPreference<Float> {
protected FloatPreference(@NotNull String key, @Nullable Float defaultValue) {
super(key, defaultValue);
}
@Override
protected Float getPersistedValue(@NotNull SharedPreferences preferences) {
return preferences.getFloat(getKey(), -1f);
}
@Override
protected void putPersistedValue(@NotNull SharedPreferences.Editor editor, @NotNull Float value) {
editor.putFloat(getKey(), value);
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.view.prefs;
import android.content.SharedPreferences;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* User: serso
* Date: 12/25/11
* Time: 12:47 PM
*/
public class IntegerPreference extends AbstractPreference<Integer> {
public IntegerPreference(@NotNull String key, @Nullable Integer defaultValue) {
super(key, defaultValue);
}
@Override
protected Integer getPersistedValue(@NotNull SharedPreferences preferences) {
return preferences.getInt(getKey(), -1);
}
@Override
protected void putPersistedValue(@NotNull SharedPreferences.Editor editor, @NotNull Integer value) {
editor.putInt(getKey(), value);
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.view.prefs;
import android.content.SharedPreferences;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* User: serso
* Date: 12/25/11
* Time: 1:07 PM
*/
public class LongPreference extends AbstractPreference<Long> {
protected LongPreference(@NotNull String key, @Nullable Long defaultValue) {
super(key, defaultValue);
}
@Override
protected Long getPersistedValue(@NotNull SharedPreferences preferences) {
return preferences.getLong(getKey(), -1);
}
@Override
protected void putPersistedValue(@NotNull SharedPreferences.Editor editor, @NotNull Long value) {
editor.putLong(getKey(), value);
}
}

View File

@@ -1,20 +0,0 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.view.prefs;
import org.jetbrains.annotations.Nullable;
/**
* User: serso
* Date: 9/20/11
* Time: 10:15 PM
*/
public interface PersistenceValueGetter<T> {
@Nullable
T getPersistedValue(@Nullable T defaultValue);
}

View File

@@ -1,19 +0,0 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.view.prefs;
import org.jetbrains.annotations.Nullable;
/**
* User: serso
* Date: 9/20/11
* Time: 10:14 PM
*/
public interface PersistenceValueSetter<T> {
void persist(@Nullable T value);
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.view.prefs;
import android.content.SharedPreferences;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* User: serso
* Date: 12/25/11
* Time: 12:21 PM
*/
public interface Preference<T> {
@NotNull
String getKey();
T getDefaultValue();
T getPreference(@NotNull SharedPreferences preferences);
void putPreference(@NotNull SharedPreferences preferences, @Nullable T value);
void putDefault(@NotNull SharedPreferences preferences);
}

View File

@@ -1,234 +0,0 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.view.prefs;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.CalculatorActivity;
import org.solovyev.android.view.widgets.DragButton;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;
/**
* User: serso
* Date: 11/25/11
* Time: 1:52 PM
*/
public enum ResourceCache {
instance;
@NotNull
private static final Locale DEFAULT_LOCALE = Locale.ENGLISH;
// ids of drag buttons in R.class
private List<Integer> dragButtonIds = null;
// ids of buttons in R.class
private List<Integer> buttonIds = null;
// first map: key: language id, value: map of captions and translations
// second mal: key: caption id, value: translation
private final Map<String, Map<String, String>> captions = new HashMap<String, Map<String, String>>();
private Class<?> resourceClass;
private Context context;
@NotNull
private final NameToIdCache nameToIdCache = new NameToIdCache();
public List<Integer> getDragButtonIds() {
return dragButtonIds;
}
public List<Integer> getButtonIds() {
return buttonIds;
}
/**
* Method load captions for default locale using android R class
*
* @param context STATIC CONTEXT
* @param resourceClass class of captions in android (SUBCLASS of R class)
*/
public void initCaptions(@NotNull Context context, @NotNull Class<?> resourceClass) {
initCaptions(context, resourceClass, Locale.getDefault());
}
/**
* Method load captions for specified locale using android R class
*
* @param context STATIC CONTEXT
* @param resourceClass class of captions in android (SUBCLASS of R class)
* @param locale language to be used for translation
*/
public void initCaptions(@NotNull Context context, @NotNull Class<?> resourceClass, @NotNull Locale locale) {
assert this.resourceClass == null || this.resourceClass.equals(resourceClass);
this.context = context;
this.resourceClass = resourceClass;
if (!initialized(locale)) {
final Map<String, String> captionsByLanguage = new HashMap<String, String>();
final Locale defaultLocale = Locale.getDefault();
try {
if (!defaultLocale.getLanguage().equals(locale.getLanguage())) {
updateConfiguration(context, locale);
}
for (Field field : resourceClass.getDeclaredFields()) {
int modifiers = field.getModifiers();
if (Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers)) {
try {
int captionId = field.getInt(resourceClass);
captionsByLanguage.put(field.getName(), context.getString(captionId));
} catch (IllegalAccessException e) {
Log.e(ResourceCache.class.getName(), e.getMessage());
} catch (Resources.NotFoundException e) {
Log.e(ResourceCache.class.getName(), "Caption with name " + field.getName() + " was not found for " + locale.getLanguage() + " language: " + e.getMessage());
}
}
}
} finally {
if (!defaultLocale.getLanguage().equals(locale.getLanguage())) {
updateConfiguration(context, defaultLocale);
}
}
captions.put(locale.getLanguage(), captionsByLanguage);
}
}
private static void updateConfiguration(@NotNull Context context, @NotNull Locale locale) {
Locale.setDefault(locale);
final Configuration config = new Configuration();
config.locale = locale;
context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics());
}
private boolean initialized(@NotNull Locale locale) {
return captions.containsKey(locale.getLanguage());
}
/**
* @param captionId id of caption to be translated
* @return translation by caption id in default language, null if no translation in default language present
*/
@Nullable
public String getCaption(@NotNull String captionId) {
return getCaption(captionId, Locale.getDefault());
}
/**
* @param captionId id of caption to be translated
* @param locale language to be used for translation
* @return translation by caption id in specified language, null if no translation in specified language present
*/
@Nullable
public String getCaption(@NotNull String captionId, @NotNull final Locale locale) {
Map<String, String> captionsByLanguage = captions.get(locale.getLanguage());
if (captionsByLanguage != null) {
return getCaption(captionsByLanguage, captionId, locale);
} else {
assert resourceClass != null && context != null;
initCaptions(context, resourceClass, locale);
captionsByLanguage = captions.get(locale.getLanguage());
if (captionsByLanguage != null) {
return getCaption(captionsByLanguage, captionId, locale);
}
}
return null;
}
@Nullable
private String getCaption(@NotNull Map<String, String> captionsByLanguage, @NotNull String captionId, @NotNull Locale locale) {
String result = captionsByLanguage.get(captionId);
if (result == null && !locale.getLanguage().equals(DEFAULT_LOCALE.getLanguage())) {
result = getCaption(captionId, DEFAULT_LOCALE);
}
return result;
}
public void init(@NotNull Class<?> resourceClass, @NotNull Activity activity) {
dragButtonIds = new ArrayList<Integer>();
buttonIds = new ArrayList<Integer>();
for (Field field : resourceClass.getDeclaredFields()) {
int modifiers = field.getModifiers();
if (Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers)) {
try {
int viewId = field.getInt(resourceClass);
final View view = activity.findViewById(viewId);
if (view instanceof DragButton) {
dragButtonIds.add(viewId);
}
if (view instanceof Button) {
buttonIds.add(viewId);
}
} catch (IllegalAccessException e) {
Log.e(ResourceCache.class.getName(), e.getMessage());
}
}
}
}
@NotNull
public Map<String, Integer> getNameToIdCache(@NotNull Class<?> clazz) {
return this.nameToIdCache.getCache(clazz);
}
private static class NameToIdCache {
@NotNull
private final Map<Class<?>, Map<String, Integer>> caches = new HashMap<Class<?>, Map<String, Integer>>(3);
// not intended for instantiation
private NameToIdCache() {
}
@NotNull
public Map<String, Integer> getCache(@NotNull Class<?> clazz) {
Map<String, Integer> result = caches.get(clazz);
if (result == null) {
result = new HashMap<String, Integer>();
for (Field field : clazz.getDeclaredFields()) {
int modifiers = field.getModifiers();
if (Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers)) {
try {
result.put(field.getName(), field.getInt(clazz));
} catch (IllegalAccessException e) {
Log.e(CalculatorActivity.class.getName(), e.getMessage());
}
}
}
caches.put(clazz, result);
}
return result;
}
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.view.prefs;
import android.content.SharedPreferences;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.common.utils.Mapper;
import org.solovyev.common.utils.StringMapper;
/**
* User: serso
* Date: 12/25/11
* Time: 12:37 PM
*/
public class StringPreference<T> extends AbstractPreference<T> {
@NotNull
private final Mapper<T> mapper;
public StringPreference(@NotNull String id, @Nullable T defaultValue, @NotNull Mapper<T> mapper) {
super(id, defaultValue);
this.mapper = mapper;
}
@NotNull
public static StringPreference<String> newInstance(@NotNull String id, @Nullable String defaultValue) {
return new StringPreference<String>(id, defaultValue, new StringMapper());
}
@NotNull
public static <T> StringPreference<T> newInstance(@NotNull String id, @Nullable String defaultValue, @NotNull Mapper<T> parser) {
return new StringPreference<T>(id, parser.parseValue(defaultValue), parser);
}
@Override
protected T getPersistedValue(@NotNull SharedPreferences preferences) {
return mapper.parseValue(preferences.getString(getKey(), null));
}
@Override
protected void putPersistedValue(@NotNull SharedPreferences.Editor editor, @NotNull T value) {
editor.putString(getKey(), mapper.formatValue(value));
}
}