Home | History | Annotate | Download | only in shadow
      1 package com.google.android.libraries.backup.shadow;
      2 
      3 import android.app.backup.FileBackupHelper;
      4 import android.content.Context;
      5 import android.util.Log;
      6 import com.google.common.annotations.VisibleForTesting;
      7 import com.google.common.base.Preconditions;
      8 import com.google.common.collect.ImmutableMap;
      9 import com.google.common.collect.ImmutableSet;
     10 import com.google.common.io.Files;
     11 import java.io.File;
     12 import java.io.IOException;
     13 import java.lang.reflect.Field;
     14 import java.util.Arrays;
     15 import java.util.Map;
     16 import java.util.Set;
     17 
     18 /**
     19  * Representation of {@link FileBackupHelper} configuration used for testing. This class simulates
     20  * backing up and restoring files by storing their contents in memory.
     21  *
     22  * <p>{@see BackupAgentHelperShadow}
     23  */
     24 public class FileBackupHelperSimulator extends BackupHelperSimulator {
     25   private static final String TAG = "FileBackupHelperSimulat";
     26 
     27   /** Filenames which should be backed up/restored. */
     28   private final Set<String> fileNames;
     29 
     30   private FileBackupHelperSimulator(String keyPrefix, Set<String> fileNames) {
     31     super(keyPrefix);
     32     this.fileNames = Preconditions.checkNotNull(fileNames);
     33   }
     34 
     35   public static FileBackupHelperSimulator fromFileNames(String keyPrefix, Set<String> fileNames) {
     36     return new FileBackupHelperSimulator(keyPrefix, fileNames);
     37   }
     38 
     39   public static FileBackupHelperSimulator fromHelper(String keyPrefix, FileBackupHelper helper) {
     40     return new FileBackupHelperSimulator(keyPrefix, extractFileNamesFromHelper(helper));
     41   }
     42 
     43   @VisibleForTesting
     44   static Set<String> extractFileNamesFromHelper(FileBackupHelper helper) {
     45     try {
     46       Field filesField = FileBackupHelper.class.getDeclaredField("mFiles");
     47       filesField.setAccessible(true);
     48       return ImmutableSet.copyOf((String[]) filesField.get(helper));
     49     } catch (ReflectiveOperationException e) {
     50       throw new IllegalStateException(e);
     51     }
     52   }
     53 
     54   /** Collection of backed up files. */
     55   public static class FilesBackupData {
     56     /** Map from file names to their backed up contents. */
     57     private final Map<String, FileBackupContents> files;
     58 
     59     public FilesBackupData(Map<String, FileBackupContents> files) {
     60       this.files = Preconditions.checkNotNull(files);
     61     }
     62 
     63     @Override
     64     public boolean equals(Object obj) {
     65       return obj instanceof FilesBackupData && files.equals(((FilesBackupData) obj).files);
     66     }
     67 
     68     @Override
     69     public int hashCode() {
     70       return files.hashCode();
     71     }
     72 
     73     public Map<String, FileBackupContents> getFiles() {
     74       return files;
     75     }
     76   }
     77 
     78   /** Single backed up file. */
     79   public static class FileBackupContents {
     80     private final byte[] bytes;
     81 
     82     public FileBackupContents(byte[] bytes) {
     83       this.bytes = Preconditions.checkNotNull(bytes);
     84     }
     85 
     86     @Override
     87     public boolean equals(Object obj) {
     88       return obj instanceof FileBackupContents
     89           && Arrays.equals(bytes, ((FileBackupContents) obj).bytes);
     90     }
     91 
     92     @Override
     93     public int hashCode() {
     94       return Arrays.hashCode(bytes);
     95     }
     96 
     97     public static FileBackupContents readFromFile(File file) {
     98       return new FileBackupContents(readBytesFromFile(file));
     99     }
    100 
    101     public void writeToFile(File file) {
    102       writeBytesToFile(file, bytes);
    103     }
    104 
    105     public static byte[] readBytesFromFile(File file) {
    106       try {
    107         return Files.toByteArray(file);
    108       } catch (IOException e) {
    109         throw new IllegalStateException(e);
    110       }
    111     }
    112 
    113     public static void writeBytesToFile(File file, byte[] bytes) {
    114       try {
    115         Files.write(bytes, file);
    116       } catch (IOException e) {
    117         throw new IllegalStateException(e);
    118       }
    119     }
    120   }
    121 
    122   @Override
    123   public Object backup(Context context) {
    124     File base = context.getFilesDir();
    125     ImmutableMap.Builder<String, FileBackupContents> dataToBackupBuilder = ImmutableMap.builder();
    126     for (String fileName : fileNames) {
    127       File file = new File(base, fileName);
    128       if (!file.exists()) {
    129         Log.w(TAG, "File \"" + fileName + "\" not found by helper \"" + keyPrefix + "\".");
    130         continue;
    131       }
    132       dataToBackupBuilder.put(fileName, FileBackupContents.readFromFile(file));
    133     }
    134     return new FilesBackupData(dataToBackupBuilder.build());
    135   }
    136 
    137   @Override
    138   public void restore(Context context, Object data) {
    139     if (!(data instanceof FilesBackupData)) {
    140       throw new IllegalArgumentException("Invalid type of files to restore in helper \""
    141           + keyPrefix + "\": " + data.getClass());
    142     }
    143 
    144     File base = context.getFilesDir();
    145     Map<String, FileBackupContents> dataToRestore = ((FilesBackupData) data).getFiles();
    146     for (Map.Entry<String, FileBackupContents> restoreEntry : dataToRestore.entrySet()) {
    147       String fileName = restoreEntry.getKey();
    148       if (!fileNames.contains(fileName)) {
    149         Log.w(TAG, "File \"" + fileName + "\" ignored by helper \"" + keyPrefix + "\".");
    150         continue;
    151       }
    152       FileBackupContents contents = restoreEntry.getValue();
    153       File file = new File(base, fileName);
    154       contents.writeToFile(file);
    155     }
    156   }
    157 }
    158