diff options
Diffstat (limited to 'src/com/google/android/libraries/backup/shadow/SharedPreferencesBackupHelperSimulator.java')
-rw-r--r-- | src/com/google/android/libraries/backup/shadow/SharedPreferencesBackupHelperSimulator.java | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/src/com/google/android/libraries/backup/shadow/SharedPreferencesBackupHelperSimulator.java b/src/com/google/android/libraries/backup/shadow/SharedPreferencesBackupHelperSimulator.java new file mode 100644 index 0000000..407f3f0 --- /dev/null +++ b/src/com/google/android/libraries/backup/shadow/SharedPreferencesBackupHelperSimulator.java @@ -0,0 +1,147 @@ +package com.google.android.libraries.backup.shadow; + +import static android.content.Context.MODE_PRIVATE; + +import android.app.backup.SharedPreferencesBackupHelper; +import android.content.Context; +import android.content.SharedPreferences.Editor; +import android.util.Log; +import com.google.android.libraries.backup.PersistentBackupAgentHelper; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import java.lang.reflect.Field; +import java.util.Map; +import java.util.Set; + +/** + * Representation of {@link SharedPreferencesBackupHelper} configuration used for testing. This + * class simulates backing up and restoring shared preferences by storing them in memory. + * + * <p>{@see BackupAgentHelperShadow} + */ +public class SharedPreferencesBackupHelperSimulator extends BackupHelperSimulator { + private static final String TAG = "SharedPreferencesBackup"; + + /** Shared preferences file names which should be backed up/restored. */ + private final Set<String> prefGroups; + + private SharedPreferencesBackupHelperSimulator(String keyPrefix, Set<String> prefGroups) { + super(keyPrefix); + this.prefGroups = Preconditions.checkNotNull(prefGroups); + } + + public static SharedPreferencesBackupHelperSimulator fromPreferenceGroups( + String keyPrefix, Set<String> prefGroups) { + return new SharedPreferencesBackupHelperSimulator(keyPrefix, prefGroups); + } + + public static SharedPreferencesBackupHelperSimulator fromHelper( + String keyPrefix, SharedPreferencesBackupHelper helper) { + return new SharedPreferencesBackupHelperSimulator( + keyPrefix, extractPreferenceGroupsFromHelper(helper)); + } + + @VisibleForTesting + static Set<String> extractPreferenceGroupsFromHelper(SharedPreferencesBackupHelper helper) { + try { + Field prefGroupsField = SharedPreferencesBackupHelper.class.getDeclaredField("mPrefGroups"); + prefGroupsField.setAccessible(true); + return ImmutableSet.copyOf((String[]) prefGroupsField.get(helper)); + } catch (ReflectiveOperationException e) { + throw new IllegalStateException( + "Failed to construct SharedPreferencesBackupHelperSimulator", e); + } + } + + /** Collection of backed up shared preferences. */ + public static class SharedPreferencesBackupData { + /** Map from shared preferences file names to key-value preference maps. */ + private final Map<String, Map<String, ?>> preferences; + + public SharedPreferencesBackupData(Map<String, Map<String, ?>> data) { + this.preferences = Preconditions.checkNotNull(data); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof SharedPreferencesBackupData + && preferences.equals(((SharedPreferencesBackupData) obj).preferences); + } + + @Override + public int hashCode() { + return preferences.hashCode(); + } + + public Map<String, Map<String, ?>> getPreferences() { + return preferences; + } + } + + @Override + public Object backup(Context context) { + ImmutableMap.Builder<String, Map<String, ?>> dataToBackupBuilder = ImmutableMap.builder(); + for (String prefGroup : prefGroups) { + Map<String, ?> prefs = context.getSharedPreferences(prefGroup, MODE_PRIVATE).getAll(); + if (prefs.isEmpty()) { + Log.w(TAG, "Shared prefs \"" + prefGroup + "\" are empty. The helper \"" + keyPrefix + + "\" assumes this is due to a missing (rather than empty) shared preferences file."); + continue; + } + ImmutableMap.Builder<String, Object> prefsData = ImmutableMap.builder(); + for (Map.Entry<String, ?> prefEntry : prefs.entrySet()) { + String key = prefEntry.getKey(); + Object value = prefEntry.getValue(); + if (value instanceof Set) { + value = ImmutableSet.copyOf((Set<?>) value); + } + prefsData.put(key, value); + } + dataToBackupBuilder.put(prefGroup, prefsData.build()); + } + return new SharedPreferencesBackupData(dataToBackupBuilder.build()); + } + + @Override + public void restore(Context context, Object data) { + if (!(data instanceof SharedPreferencesBackupData)) { + throw new IllegalArgumentException("Invalid type of files to restore in helper \"" + + keyPrefix + "\": " + data.getClass()); + } + + Map<String, Map<String, ?>> prefsToRestore = + ((SharedPreferencesBackupData) data).getPreferences(); + + // Display a warning when missing/empty preferences are restored onto non-empty preferences. + for (String prefGroup : prefGroups) { + if (context.getSharedPreferences(prefGroup, MODE_PRIVATE).getAll().isEmpty()) { + continue; + } + Map<String, ?> prefsData = prefsToRestore.get(prefGroup); + if (prefsData == null) { + Log.w(TAG, "Non-empty shared prefs \"" + prefGroup + "\" will NOT be cleared by helper \"" + + keyPrefix + "\" because the corresponding file is missing in the restored data."); + } else if (prefsData.isEmpty()) { + Log.w(TAG, "Non-empty shared prefs \"" + prefGroup + "\" will be cleared by helper \"" + + keyPrefix + "\" because the corresponding file is empty in the restored data."); + } + } + + for (Map.Entry<String, Map<String, ?>> restoreEntry : prefsToRestore.entrySet()) { + String prefGroup = restoreEntry.getKey(); + if (!prefGroups.contains(prefGroup)) { + Log.w(TAG, "Shared prefs \"" + prefGroup + "\" ignored by helper \"" + keyPrefix + "\"."); + continue; + } + Map<String, ?> prefsData = restoreEntry.getValue(); + Editor editor = context.getSharedPreferences(prefGroup, MODE_PRIVATE).edit().clear(); + for (Map.Entry<String, ?> prefEntry : prefsData.entrySet()) { + PersistentBackupAgentHelper.putSharedPreference( + editor, prefEntry.getKey(), prefEntry.getValue()); + } + editor.apply(); + } + } +} |