summaryrefslogtreecommitdiffstats
path: root/src/com/google/android/libraries/backup/shadow/SharedPreferencesBackupHelperSimulator.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/google/android/libraries/backup/shadow/SharedPreferencesBackupHelperSimulator.java')
-rw-r--r--src/com/google/android/libraries/backup/shadow/SharedPreferencesBackupHelperSimulator.java147
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();
+ }
+ }
+}