package com.fsck.k9droidtn.preferences; import java.io.File; import java.text.SimpleDateFormat; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import java.util.TreeMap; import android.content.SharedPreferences; import android.os.Environment; import com.fsck.k9droidtn.FontSizes; import com.fsck.k9droidtn.K9; import com.fsck.k9droidtn.R; import com.fsck.k9droidtn.helper.DateFormatter; import com.fsck.k9droidtn.preferences.Settings.*; public class GlobalSettings { public static final Map<String, TreeMap<Integer, SettingsDescription>> SETTINGS; public static final Map<Integer, SettingsUpgrader> UPGRADERS; static { Map<String, TreeMap<Integer, SettingsDescription>> s = new LinkedHashMap<String, TreeMap<Integer, SettingsDescription>>(); /** * When adding new settings here, be sure to increment {@link Settings.VERSION} * and use that for whatever you add here. */ s.put("animations", Settings.versions( new V(1, new BooleanSetting(false)) )); s.put("attachmentdefaultpath", Settings.versions( new V(1, new DirectorySetting(Environment.getExternalStorageDirectory().toString())) )); s.put("backgroundOperations", Settings.versions( new V(1, new EnumSetting(K9.BACKGROUND_OPS.class, K9.BACKGROUND_OPS.WHEN_CHECKED)) )); s.put("changeRegisteredNameColor", Settings.versions( new V(1, new BooleanSetting(false)) )); s.put("compactLayouts", Settings.versions( new V(1, new BooleanSetting(false)) )); s.put("confirmDelete", Settings.versions( new V(1, new BooleanSetting(false)) )); s.put("confirmDeleteStarred", Settings.versions( new V(2, new BooleanSetting(false)) )); s.put("confirmMarkAllAsRead", Settings.versions( new V(1, new BooleanSetting(false)) )); s.put("confirmSpam", Settings.versions( new V(1, new BooleanSetting(false)) )); s.put("countSearchMessages", Settings.versions( new V(1, new BooleanSetting(false)) )); s.put("dateFormat", Settings.versions( new V(1, new DateFormatSetting(DateFormatter.DEFAULT_FORMAT)) )); s.put("enableDebugLogging", Settings.versions( new V(1, new BooleanSetting(false)) )); s.put("enableSensitiveLogging", Settings.versions( new V(1, new BooleanSetting(false)) )); s.put("fontSizeAccountDescription", Settings.versions( new V(1, new FontSizeSetting(FontSizes.SMALL)) )); s.put("fontSizeAccountName", Settings.versions( new V(1, new FontSizeSetting(FontSizes.MEDIUM)) )); s.put("fontSizeFolderName", Settings.versions( new V(1, new FontSizeSetting(FontSizes.LARGE)) )); s.put("fontSizeFolderStatus", Settings.versions( new V(1, new FontSizeSetting(FontSizes.SMALL)) )); s.put("fontSizeMessageComposeInput", Settings.versions( new V(5, new FontSizeSetting(FontSizes.MEDIUM)) )); s.put("fontSizeMessageListDate", Settings.versions( new V(1, new FontSizeSetting(FontSizes.SMALL)) )); s.put("fontSizeMessageListPreview", Settings.versions( new V(1, new FontSizeSetting(FontSizes.SMALL)) )); s.put("fontSizeMessageListSender", Settings.versions( new V(1, new FontSizeSetting(FontSizes.SMALL)) )); s.put("fontSizeMessageListSubject", Settings.versions( new V(1, new FontSizeSetting(FontSizes.FONT_16SP)) )); s.put("fontSizeMessageViewAdditionalHeaders", Settings.versions( new V(1, new FontSizeSetting(FontSizes.FONT_12SP)) )); s.put("fontSizeMessageViewCC", Settings.versions( new V(1, new FontSizeSetting(FontSizes.FONT_12SP)) )); s.put("fontSizeMessageViewContent", Settings.versions( new V(1, new WebFontSizeSetting(3)) )); s.put("fontSizeMessageViewDate", Settings.versions( new V(1, new FontSizeSetting(FontSizes.FONT_10SP)) )); s.put("fontSizeMessageViewSender", Settings.versions( new V(1, new FontSizeSetting(FontSizes.SMALL)) )); s.put("fontSizeMessageViewSubject", Settings.versions( new V(1, new FontSizeSetting(FontSizes.FONT_12SP)) )); s.put("fontSizeMessageViewTime", Settings.versions( new V(1, new FontSizeSetting(FontSizes.FONT_10SP)) )); s.put("fontSizeMessageViewTo", Settings.versions( new V(1, new FontSizeSetting(FontSizes.FONT_12SP)) )); s.put("gesturesEnabled", Settings.versions( new V(1, new BooleanSetting(true)), new V(4, new BooleanSetting(false)) )); s.put("hideSpecialAccounts", Settings.versions( new V(1, new BooleanSetting(false)) )); s.put("keyguardPrivacy", Settings.versions( new V(1, new BooleanSetting(false)) )); s.put("language", Settings.versions( new V(1, new LanguageSetting()) )); s.put("manageBack", Settings.versions( new V(1, new BooleanSetting(false)) )); s.put("measureAccounts", Settings.versions( new V(1, new BooleanSetting(true)) )); s.put("messageListCheckboxes", Settings.versions( new V(1, new BooleanSetting(false)) )); s.put("messageListPreviewLines", Settings.versions( new V(1, new IntegerRangeSetting(1, 100, 2)) )); s.put("messageListStars", Settings.versions( new V(1, new BooleanSetting(true)) )); s.put("messageListTouchable", Settings.versions( new V(1, new BooleanSetting(false)) )); s.put("messageViewFixedWidthFont", Settings.versions( new V(1, new BooleanSetting(false)) )); s.put("messageViewReturnToList", Settings.versions( new V(1, new BooleanSetting(false)) )); s.put("messageViewShowNext", Settings.versions( new V(1, new BooleanSetting(false)) )); s.put("mobileOptimizedLayout", Settings.versions( new V(1, new BooleanSetting(false)) )); s.put("quietTimeEnabled", Settings.versions( new V(1, new BooleanSetting(false)) )); s.put("quietTimeEnds", Settings.versions( new V(1, new TimeSetting("7:00")) )); s.put("quietTimeStarts", Settings.versions( new V(1, new TimeSetting("21:00")) )); s.put("registeredNameColor", Settings.versions( new V(1, new ColorSetting(0xFF00008F)) )); s.put("showContactName", Settings.versions( new V(1, new BooleanSetting(false)) )); s.put("showCorrespondentNames", Settings.versions( new V(1, new BooleanSetting(true)) )); s.put("startIntegratedInbox", Settings.versions( new V(1, new BooleanSetting(false)) )); s.put("theme", Settings.versions( new V(1, new ThemeSetting(K9.THEME_LIGHT)) )); s.put("useGalleryBugWorkaround", Settings.versions( new V(1, new GalleryBugWorkaroundSetting()) )); s.put("useVolumeKeysForListNavigation", Settings.versions( new V(1, new BooleanSetting(false)) )); s.put("useVolumeKeysForNavigation", Settings.versions( new V(1, new BooleanSetting(false)) )); s.put("zoomControlsEnabled", Settings.versions( new V(1, new BooleanSetting(false)), new V(4, new BooleanSetting(true)) )); s.put("batchButtonsMarkRead", Settings.versions( new V(8, new BooleanSetting(true)) )); s.put("batchButtonsDelete", Settings.versions( new V(8, new BooleanSetting(true)) )); s.put("batchButtonsArchive", Settings.versions( new V(8, new BooleanSetting(false)) )); s.put("batchButtonsMove", Settings.versions( new V(8, new BooleanSetting(false)) )); s.put("batchButtonsFlag", Settings.versions( new V(8, new BooleanSetting(true)) )); s.put("batchButtonsUnselect", Settings.versions( new V(8, new BooleanSetting(true)) )); s.put("delayTolerance", Settings.versions( new V(10, new IntegerRangeSetting(0, 600, 120)) )); SETTINGS = Collections.unmodifiableMap(s); Map<Integer, SettingsUpgrader> u = new HashMap<Integer, SettingsUpgrader>(); UPGRADERS = Collections.unmodifiableMap(u); } public static Map<String, Object> validate(int version, Map<String, String> importedSettings) { return Settings.validate(version, SETTINGS, importedSettings, false); } public static Set<String> upgrade(int version, Map<String, Object> validatedSettings) { return Settings.upgrade(version, UPGRADERS, SETTINGS, validatedSettings); } public static Map<String, String> convert(Map<String, Object> settings) { return Settings.convert(settings, SETTINGS); } public static Map<String, String> getGlobalSettings(SharedPreferences storage) { Map<String, String> result = new HashMap<String, String>(); for (String key : SETTINGS.keySet()) { String value = storage.getString(key, null); if (value != null) { result.put(key, value); } } return result; } /** * The gallery bug work-around setting. * * <p> * The default value varies depending on whether you have a version of Gallery 3D installed * that contains the bug we work around. * </p> * * @see K9#isGalleryBuggy() */ public static class GalleryBugWorkaroundSetting extends BooleanSetting { public GalleryBugWorkaroundSetting() { super(false); } @Override public Object getDefaultValue() { return K9.isGalleryBuggy(); } } /** * The language setting. * * <p> * Valid values are read from {@code settings_language_values} in * {@code res/values/arrays.xml}. * </p> */ public static class LanguageSetting extends PseudoEnumSetting<String> { private final Map<String, String> mMapping; public LanguageSetting() { super(""); Map<String, String> mapping = new HashMap<String, String>(); String[] values = K9.app.getResources().getStringArray(R.array.settings_language_values); for (String value : values) { if (value.length() == 0) { mapping.put("", "default"); } else { mapping.put(value, value); } } mMapping = Collections.unmodifiableMap(mapping); } @Override protected Map<String, String> getMapping() { return mMapping; } @Override public Object fromString(String value) throws InvalidSettingValueException { if (mMapping.containsKey(value)) { return value; } throw new InvalidSettingValueException(); } } /** * The theme setting. */ public static class ThemeSetting extends SettingsDescription { private static final String THEME_LIGHT = "light"; private static final String THEME_DARK = "dark"; public ThemeSetting(int defaultValue) { super(defaultValue); } @Override public Object fromString(String value) throws InvalidSettingValueException { try { Integer theme = Integer.parseInt(value); if (theme == K9.THEME_LIGHT || // We used to store the resource ID of the theme in the preference storage, // but don't use the database upgrade mechanism to update the values. So // we have to deal with the old format here. theme == android.R.style.Theme_Light) { return K9.THEME_LIGHT; } else if (theme == K9.THEME_DARK || theme == android.R.style.Theme) { return K9.THEME_DARK; } } catch (NumberFormatException e) { /* do nothing */ } throw new InvalidSettingValueException(); } @Override public Object fromPrettyString(String value) throws InvalidSettingValueException { if (THEME_LIGHT.equals(value)) { return K9.THEME_LIGHT; } else if (THEME_DARK.equals(value)) { return K9.THEME_DARK; } throw new InvalidSettingValueException(); } @Override public String toPrettyString(Object value) { return (((Integer)value).intValue() == K9.THEME_LIGHT) ? THEME_LIGHT : THEME_DARK; } } /** * A date format setting. */ public static class DateFormatSetting extends SettingsDescription { public DateFormatSetting(String defaultValue) { super(defaultValue); } @Override public Object fromString(String value) throws InvalidSettingValueException { try { // The placeholders "SHORT" and "MEDIUM" are fine. if (DateFormatter.SHORT_FORMAT.equals(value) || DateFormatter.MEDIUM_FORMAT.equals(value)) { return value; } // If the SimpleDateFormat constructor doesn't throw an exception, we're good. new SimpleDateFormat(value); return value; } catch (Exception e) { throw new InvalidSettingValueException(); } } } /** * A time setting. */ public static class TimeSetting extends SettingsDescription { public TimeSetting(String defaultValue) { super(defaultValue); } @Override public Object fromString(String value) throws InvalidSettingValueException { if (!value.matches(TimePickerPreference.VALIDATION_EXPRESSION)) { throw new InvalidSettingValueException(); } return value; } } /** * A directory on the file system. */ public static class DirectorySetting extends SettingsDescription { public DirectorySetting(String defaultValue) { super(defaultValue); } @Override public Object fromString(String value) throws InvalidSettingValueException { try { if (new File(value).isDirectory()) { return value; } } catch (Exception e) { /* do nothing */ } throw new InvalidSettingValueException(); } } }