mirror of
https://github.com/moparisthebest/k-9
synced 2024-11-24 02:12:15 -05:00
Added code to upgrade settings on import
This allows us to import files with an outdated content version, then upgrade the settings to the current content version.
This commit is contained in:
parent
d57e684296
commit
18a58e2872
@ -4,6 +4,7 @@ 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;
|
||||
@ -18,6 +19,7 @@ import com.fsck.k9.preferences.Settings.*;
|
||||
|
||||
public class AccountSettings {
|
||||
public static final Map<String, TreeMap<Integer, SettingsDescription>> SETTINGS;
|
||||
public static final Map<Integer, SettingsUpgrader> UPGRADERS;
|
||||
|
||||
static {
|
||||
Map<String, TreeMap<Integer, SettingsDescription>> s =
|
||||
@ -204,6 +206,9 @@ public class AccountSettings {
|
||||
));
|
||||
|
||||
SETTINGS = Collections.unmodifiableMap(s);
|
||||
|
||||
Map<Integer, SettingsUpgrader> u = new HashMap<Integer, SettingsUpgrader>();
|
||||
UPGRADERS = Collections.unmodifiableMap(u);
|
||||
}
|
||||
|
||||
public static Map<String, String> validate(int version, Map<String, String> importedSettings,
|
||||
@ -211,6 +216,10 @@ public class AccountSettings {
|
||||
return Settings.validate(version, SETTINGS, importedSettings, useDefaultValues);
|
||||
}
|
||||
|
||||
public static Set<String> upgrade(int version, Map<String, String> validatedSettings) {
|
||||
return Settings.upgrade(version, UPGRADERS, SETTINGS, validatedSettings);
|
||||
}
|
||||
|
||||
public static Map<String, String> getAccountSettings(SharedPreferences storage, String uuid) {
|
||||
Map<String, String> result = new HashMap<String, String>();
|
||||
String prefix = uuid + ".";
|
||||
|
@ -4,6 +4,7 @@ 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;
|
||||
@ -13,6 +14,7 @@ import com.fsck.k9.preferences.Settings.*;
|
||||
|
||||
public class FolderSettings {
|
||||
public static final Map<String, TreeMap<Integer, SettingsDescription>> SETTINGS;
|
||||
public static final Map<Integer, SettingsUpgrader> UPGRADERS;
|
||||
|
||||
static {
|
||||
Map<String, TreeMap<Integer, SettingsDescription>> s =
|
||||
@ -35,6 +37,9 @@ public class FolderSettings {
|
||||
));
|
||||
|
||||
SETTINGS = Collections.unmodifiableMap(s);
|
||||
|
||||
Map<Integer, SettingsUpgrader> u = new HashMap<Integer, SettingsUpgrader>();
|
||||
UPGRADERS = Collections.unmodifiableMap(u);
|
||||
}
|
||||
|
||||
public static Map<String, String> validate(int version, Map<String, String> importedSettings,
|
||||
@ -42,6 +47,10 @@ public class FolderSettings {
|
||||
return Settings.validate(version, SETTINGS, importedSettings, useDefaultValues);
|
||||
}
|
||||
|
||||
public static Set<String> upgrade(int version, Map<String, String> validatedSettings) {
|
||||
return Settings.upgrade(version, UPGRADERS, SETTINGS, validatedSettings);
|
||||
}
|
||||
|
||||
public static Map<String, String> getFolderSettings(SharedPreferences storage, String uuid,
|
||||
String folderName) {
|
||||
Map<String, String> result = new HashMap<String, String>();
|
||||
|
@ -6,6 +6,7 @@ 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;
|
||||
@ -19,6 +20,7 @@ import com.fsck.k9.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 =
|
||||
@ -191,12 +193,19 @@ public class GlobalSettings {
|
||||
));
|
||||
|
||||
SETTINGS = Collections.unmodifiableMap(s);
|
||||
|
||||
Map<Integer, SettingsUpgrader> u = new HashMap<Integer, SettingsUpgrader>();
|
||||
UPGRADERS = Collections.unmodifiableMap(u);
|
||||
}
|
||||
|
||||
public static Map<String, String> validate(int version, Map<String, String> importedSettings) {
|
||||
return Settings.validate(version, SETTINGS, importedSettings, false);
|
||||
}
|
||||
|
||||
public static Set<String> upgrade(int version, Map<String, String> validatedSettings) {
|
||||
return Settings.upgrade(version, UPGRADERS, SETTINGS, validatedSettings);
|
||||
}
|
||||
|
||||
public static Map<String, String> getGlobalSettings(SharedPreferences storage) {
|
||||
Map<String, String> result = new HashMap<String, String>();
|
||||
for (String key : SETTINGS.keySet()) {
|
||||
|
@ -4,6 +4,7 @@ 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;
|
||||
@ -15,6 +16,7 @@ import com.fsck.k9.preferences.Settings.*;
|
||||
|
||||
public class IdentitySettings {
|
||||
public static final Map<String, TreeMap<Integer, SettingsDescription>> SETTINGS;
|
||||
public static final Map<Integer, SettingsUpgrader> UPGRADERS;
|
||||
|
||||
static {
|
||||
Map<String, TreeMap<Integer, SettingsDescription>> s =
|
||||
@ -31,6 +33,9 @@ public class IdentitySettings {
|
||||
));
|
||||
|
||||
SETTINGS = Collections.unmodifiableMap(s);
|
||||
|
||||
Map<Integer, SettingsUpgrader> u = new HashMap<Integer, SettingsUpgrader>();
|
||||
UPGRADERS = Collections.unmodifiableMap(u);
|
||||
}
|
||||
|
||||
public static Map<String, String> validate(int version, Map<String, String> importedSettings,
|
||||
@ -38,6 +43,10 @@ public class IdentitySettings {
|
||||
return Settings.validate(version, SETTINGS, importedSettings, useDefaultValues);
|
||||
}
|
||||
|
||||
public static Set<String> upgrade(int version, Map<String, String> validatedSettings) {
|
||||
return Settings.upgrade(version, UPGRADERS, SETTINGS, validatedSettings);
|
||||
}
|
||||
|
||||
public static Map<String, String> getIdentitySettings(SharedPreferences storage, String uuid,
|
||||
int identityIndex) {
|
||||
Map<String, String> result = new HashMap<String, String>();
|
||||
|
@ -2,7 +2,9 @@ package com.fsck.k9.preferences;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
@ -13,7 +15,6 @@ import com.fsck.k9.K9;
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* - add support for different settings versions (validate old version and upgrade to new format)
|
||||
* - use the default values defined in GlobalSettings and AccountSettings when creating new
|
||||
* accounts
|
||||
* - think of a better way to validate enums than to use the resource arrays (i.e. get rid of
|
||||
@ -83,6 +84,82 @@ public class Settings {
|
||||
return validatedSettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Upgrade settings using the settings structure and/or special upgrade code.
|
||||
*
|
||||
* @param version
|
||||
* The content version of the settings in {@code validatedSettings}.
|
||||
* @param upgraders
|
||||
* A map of {@link SettingsUpgrader}s for nontrivial settings upgrades.
|
||||
* @param settings
|
||||
* The structure describing the different settings, possibly containing multiple
|
||||
* versions.
|
||||
* @param validatedSettings
|
||||
* The settings as returned by {@link Settings#validate(int, Map, Map, boolean)}.
|
||||
* This map is modified and contains the upgraded settings when this method returns.
|
||||
*
|
||||
* @return A set of setting names that were removed during the upgrade process or {@code null}
|
||||
* if none were removed.
|
||||
*/
|
||||
public static Set<String> upgrade(int version, Map<Integer, SettingsUpgrader> upgraders,
|
||||
Map<String, TreeMap<Integer, SettingsDescription>> settings,
|
||||
Map<String, String> validatedSettings) {
|
||||
|
||||
Map<String, String> upgradedSettings = validatedSettings;
|
||||
Set<String> deletedSettings = null;
|
||||
|
||||
for (int toVersion = version + 1; toVersion <= VERSION; toVersion++) {
|
||||
|
||||
// Check if there's an SettingsUpgrader for that version
|
||||
SettingsUpgrader upgrader = upgraders.get(toVersion);
|
||||
if (upgrader != null) {
|
||||
deletedSettings = upgrader.upgrade(upgradedSettings);
|
||||
}
|
||||
|
||||
// Deal with settings that don't need special upgrade code
|
||||
for (Entry<String, TreeMap<Integer, SettingsDescription>> versions :
|
||||
settings.entrySet()) {
|
||||
|
||||
String settingName = versions.getKey();
|
||||
TreeMap<Integer, SettingsDescription> versionedSettings = versions.getValue();
|
||||
|
||||
// Handle newly added settings
|
||||
if (versionedSettings.firstKey().intValue() == toVersion) {
|
||||
|
||||
// Check if it was already added to upgradedSettings by the SettingsUpgrader
|
||||
if (!upgradedSettings.containsKey(settingName)) {
|
||||
// Insert default value to upgradedSettings
|
||||
SettingsDescription setting = versionedSettings.firstEntry().getValue();
|
||||
Object defaultValue = setting.getDefaultValue();
|
||||
upgradedSettings.put(settingName, setting.toString(defaultValue));
|
||||
|
||||
if (K9.DEBUG) {
|
||||
String prettyValue = setting.toPrettyString(defaultValue);
|
||||
Log.v(K9.LOG_TAG, "Added new setting \"" + settingName +
|
||||
"\" with default value \"" + prettyValue + "\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle removed settings
|
||||
Entry<Integer, SettingsDescription> lastEntry = versionedSettings.lastEntry();
|
||||
if (lastEntry.getKey().intValue() == toVersion && lastEntry.getValue() == null) {
|
||||
upgradedSettings.remove(settingName);
|
||||
if (deletedSettings == null) {
|
||||
deletedSettings = new HashSet<String>();
|
||||
}
|
||||
deletedSettings.add(settingName);
|
||||
|
||||
if (K9.DEBUG) {
|
||||
Log.v(K9.LOG_TAG, "Removed setting \"" + settingName + "\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return deletedSettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link TreeMap} linking version numbers to {@link SettingsDescription} instances.
|
||||
*
|
||||
@ -234,6 +311,25 @@ public class Settings {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for a nontrivial settings upgrade.
|
||||
*
|
||||
* @see Settings#upgrade(int, Map, Map, Map)
|
||||
*/
|
||||
public interface SettingsUpgrader {
|
||||
/**
|
||||
* Upgrade the provided settings.
|
||||
*
|
||||
* @param settings
|
||||
* The settings to upgrade. This map is modified and contains the upgraded
|
||||
* settings when this method returns.
|
||||
*
|
||||
* @return A set of setting names that were removed during the upgrade process or
|
||||
* {@code null} if none were removed.
|
||||
*/
|
||||
public Set<String> upgrade(Map<String, String> settings);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A string setting.
|
||||
|
@ -173,6 +173,11 @@ public class SettingsExporter {
|
||||
String key = versionedSetting.getKey();
|
||||
String valueString = (String) prefs.get(key);
|
||||
SettingsDescription setting = versionedSetting.getValue().lastEntry().getValue();
|
||||
if (setting == null) {
|
||||
// Setting was removed.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (valueString != null) {
|
||||
try {
|
||||
Object value = setting.fromString(valueString);
|
||||
@ -319,15 +324,17 @@ public class SettingsExporter {
|
||||
if (versionedSetting != null) {
|
||||
SettingsDescription setting = versionedSetting.lastEntry().getValue();
|
||||
|
||||
// Only export account settings that can be found in AccountSettings.SETTINGS
|
||||
try {
|
||||
Object value = setting.fromString(valueString);
|
||||
String pretty = setting.toPrettyString(value);
|
||||
writeKeyValue(serializer, keyPart, pretty);
|
||||
} catch (InvalidSettingValueException e) {
|
||||
Log.w(K9.LOG_TAG, "Account setting \"" + keyPart + "\" (" +
|
||||
account.getDescription() + ") has invalid value \"" + valueString +
|
||||
"\" in preference storage. This shouldn't happen!");
|
||||
if (setting != null) {
|
||||
// Only export account settings that can be found in AccountSettings.SETTINGS
|
||||
try {
|
||||
Object value = setting.fromString(valueString);
|
||||
String pretty = setting.toPrettyString(value);
|
||||
writeKeyValue(serializer, keyPart, pretty);
|
||||
} catch (InvalidSettingValueException e) {
|
||||
Log.w(K9.LOG_TAG, "Account setting \"" + keyPart + "\" (" +
|
||||
account.getDescription() + ") has invalid value \"" + valueString +
|
||||
"\" in preference storage. This shouldn't happen!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -411,15 +418,17 @@ public class SettingsExporter {
|
||||
if (versionedSetting != null) {
|
||||
SettingsDescription setting = versionedSetting.lastEntry().getValue();
|
||||
|
||||
// Only write settings that have an entry in IdentitySettings.SETTINGS
|
||||
try {
|
||||
Object value = setting.fromString(valueString);
|
||||
String outputValue = setting.toPrettyString(value);
|
||||
writeKeyValue(serializer, identityKey, outputValue);
|
||||
} catch (InvalidSettingValueException e) {
|
||||
Log.w(K9.LOG_TAG, "Identity setting \"" + identityKey +
|
||||
"\" has invalid value \"" + valueString +
|
||||
"\" in preference storage. This shouldn't happen!");
|
||||
if (setting != null) {
|
||||
// Only write settings that have an entry in IdentitySettings.SETTINGS
|
||||
try {
|
||||
Object value = setting.fromString(valueString);
|
||||
String outputValue = setting.toPrettyString(value);
|
||||
writeKeyValue(serializer, identityKey, outputValue);
|
||||
} catch (InvalidSettingValueException e) {
|
||||
Log.w(K9.LOG_TAG, "Identity setting \"" + identityKey +
|
||||
"\" has invalid value \"" + valueString +
|
||||
"\" in preference storage. This shouldn't happen!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -460,15 +469,17 @@ public class SettingsExporter {
|
||||
if (versionedSetting != null) {
|
||||
SettingsDescription setting = versionedSetting.lastEntry().getValue();
|
||||
|
||||
// Only write settings that have an entry in FolderSettings.SETTINGS
|
||||
try {
|
||||
Object value = setting.fromString(valueString);
|
||||
String outputValue = setting.toPrettyString(value);
|
||||
writeKeyValue(serializer, folderKey, outputValue);
|
||||
} catch (InvalidSettingValueException e) {
|
||||
Log.w(K9.LOG_TAG, "Folder setting \"" + folderKey +
|
||||
"\" has invalid value \"" + valueString +
|
||||
"\" in preference storage. This shouldn't happen!");
|
||||
if (setting != null) {
|
||||
// Only write settings that have an entry in FolderSettings.SETTINGS
|
||||
try {
|
||||
Object value = setting.fromString(valueString);
|
||||
String outputValue = setting.toPrettyString(value);
|
||||
writeKeyValue(serializer, folderKey, outputValue);
|
||||
} catch (InvalidSettingValueException e) {
|
||||
Log.w(K9.LOG_TAG, "Folder setting \"" + folderKey +
|
||||
"\" has invalid value \"" + valueString +
|
||||
"\" in preference storage. This shouldn't happen!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -303,9 +303,15 @@ public class SettingsImporter {
|
||||
private static void importGlobalSettings(SharedPreferences storage,
|
||||
SharedPreferences.Editor editor, int contentVersion, ImportedSettings settings) {
|
||||
|
||||
// Validate global settings
|
||||
Map<String, String> validatedSettings = GlobalSettings.validate(contentVersion,
|
||||
settings.settings);
|
||||
|
||||
// Upgrade global settings to current content version
|
||||
if (contentVersion != Settings.VERSION) {
|
||||
GlobalSettings.upgrade(contentVersion, validatedSettings);
|
||||
}
|
||||
|
||||
// Use current global settings as base and overwrite with validated settings read from the
|
||||
// import file.
|
||||
Map<String, String> mergedSettings =
|
||||
@ -396,6 +402,11 @@ public class SettingsImporter {
|
||||
AccountSettings.validate(contentVersion, account.settings.settings,
|
||||
!mergeImportedAccount);
|
||||
|
||||
// Upgrade account settings to current content version
|
||||
if (contentVersion != Settings.VERSION) {
|
||||
AccountSettings.upgrade(contentVersion, validatedSettings);
|
||||
}
|
||||
|
||||
// Merge account settings if necessary
|
||||
Map<String, String> writeSettings;
|
||||
if (mergeImportedAccount) {
|
||||
@ -448,6 +459,11 @@ public class SettingsImporter {
|
||||
Map<String, String> validatedSettings =
|
||||
FolderSettings.validate(contentVersion, folder.settings.settings, !overwrite);
|
||||
|
||||
// Upgrade folder settings to current content version
|
||||
if (contentVersion != Settings.VERSION) {
|
||||
FolderSettings.upgrade(contentVersion, validatedSettings);
|
||||
}
|
||||
|
||||
// Merge folder settings if necessary
|
||||
Map<String, String> writeSettings;
|
||||
if (overwrite) {
|
||||
@ -537,6 +553,11 @@ public class SettingsImporter {
|
||||
Map<String, String> validatedSettings = IdentitySettings.validate(
|
||||
contentVersion, identity.settings.settings, !mergeSettings);
|
||||
|
||||
// Upgrade identity settings to current content version
|
||||
if (contentVersion != Settings.VERSION) {
|
||||
IdentitySettings.upgrade(contentVersion, validatedSettings);
|
||||
}
|
||||
|
||||
// Merge identity settings if necessary
|
||||
Map<String, String> writeSettings;
|
||||
if (mergeSettings) {
|
||||
|
Loading…
Reference in New Issue
Block a user