1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.test; 18 19 import android.content.Context; 20 import android.content.ContextWrapper; 21 import android.content.ContentProvider; 22 import android.database.DatabaseErrorHandler; 23 import android.database.sqlite.SQLiteDatabase; 24 import android.util.Log; 25 26 import java.io.File; 27 import java.io.FileInputStream; 28 import java.io.FileNotFoundException; 29 import java.io.FileOutputStream; 30 import java.io.IOException; 31 import java.nio.file.Files; 32 import java.nio.file.Paths; 33 import java.nio.file.attribute.PosixFilePermission; 34 import java.nio.file.attribute.PosixFilePermissions; 35 import java.util.EnumSet; 36 import java.util.HashSet; 37 import java.util.Set; 38 39 /** 40 * This is a class which delegates to the given context, but performs database 41 * and file operations with a renamed database/file name (prefixes default 42 * names with a given prefix). 43 * 44 * @deprecated New tests should be written using the 45 * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. 46 */ 47 @Deprecated 48 public class RenamingDelegatingContext extends ContextWrapper { 49 50 private Context mFileContext; 51 private String mFilePrefix = null; 52 private File mCacheDir; 53 private final Object mSync = new Object(); 54 55 private Set<String> mDatabaseNames = new HashSet<>(); 56 private Set<String> mFileNames = new HashSet<>(); 57 58 public static <T extends ContentProvider> T providerWithRenamedContext( 59 Class<T> contentProvider, Context c, String filePrefix) 60 throws IllegalAccessException, InstantiationException { 61 return providerWithRenamedContext(contentProvider, c, filePrefix, false); 62 } 63 64 public static <T extends ContentProvider> T providerWithRenamedContext( 65 Class<T> contentProvider, Context c, String filePrefix, 66 boolean allowAccessToExistingFilesAndDbs) 67 throws IllegalAccessException, InstantiationException { 68 Class<T> mProviderClass = contentProvider; 69 T mProvider = mProviderClass.newInstance(); 70 RenamingDelegatingContext mContext = new RenamingDelegatingContext(c, filePrefix); 71 if (allowAccessToExistingFilesAndDbs) { 72 mContext.makeExistingFilesAndDbsAccessible(); 73 } 74 mProvider.attachInfoForTesting(mContext, null); 75 return mProvider; 76 } 77 78 /** 79 * Makes accessible all files and databases whose names match the filePrefix that was passed to 80 * the constructor. Normally only files and databases that were created through this context are 81 * accessible. 82 */ 83 public void makeExistingFilesAndDbsAccessible() { 84 String[] databaseList = mFileContext.databaseList(); 85 for (String diskName : databaseList) { 86 if (shouldDiskNameBeVisible(diskName)) { 87 mDatabaseNames.add(publicNameFromDiskName(diskName)); 88 } 89 } 90 String[] fileList = mFileContext.fileList(); 91 for (String diskName : fileList) { 92 if (shouldDiskNameBeVisible(diskName)) { 93 mFileNames.add(publicNameFromDiskName(diskName)); 94 } 95 } 96 } 97 98 /** 99 * Returns if the given diskName starts with the given prefix or not. 100 * @param diskName name of the database/file. 101 */ 102 boolean shouldDiskNameBeVisible(String diskName) { 103 return diskName.startsWith(mFilePrefix); 104 } 105 106 /** 107 * Returns the public name (everything following the prefix) of the given diskName. 108 * @param diskName name of the database/file. 109 */ 110 String publicNameFromDiskName(String diskName) { 111 if (!shouldDiskNameBeVisible(diskName)) { 112 throw new IllegalArgumentException("disk file should not be visible: " + diskName); 113 } 114 return diskName.substring(mFilePrefix.length(), diskName.length()); 115 } 116 117 /** 118 * @param context : the context that will be delegated. 119 * @param filePrefix : a prefix with which database and file names will be 120 * prefixed. 121 */ 122 public RenamingDelegatingContext(Context context, String filePrefix) { 123 super(context); 124 mFileContext = context; 125 mFilePrefix = filePrefix; 126 } 127 128 /** 129 * @param context : the context that will be delegated. 130 * @param fileContext : the context that file and db methods will be delegated to 131 * @param filePrefix : a prefix with which database and file names will be 132 * prefixed. 133 */ 134 public RenamingDelegatingContext(Context context, Context fileContext, String filePrefix) { 135 super(context); 136 mFileContext = fileContext; 137 mFilePrefix = filePrefix; 138 } 139 140 public String getDatabasePrefix() { 141 return mFilePrefix; 142 } 143 144 private String renamedFileName(String name) { 145 return mFilePrefix + name; 146 } 147 148 @Override 149 public SQLiteDatabase openOrCreateDatabase(String name, 150 int mode, SQLiteDatabase.CursorFactory factory) { 151 final String internalName = renamedFileName(name); 152 if (!mDatabaseNames.contains(name)) { 153 mDatabaseNames.add(name); 154 mFileContext.deleteDatabase(internalName); 155 } 156 return mFileContext.openOrCreateDatabase(internalName, mode, factory); 157 } 158 159 @Override 160 public SQLiteDatabase openOrCreateDatabase(String name, 161 int mode, SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler) { 162 final String internalName = renamedFileName(name); 163 if (!mDatabaseNames.contains(name)) { 164 mDatabaseNames.add(name); 165 mFileContext.deleteDatabase(internalName); 166 } 167 return mFileContext.openOrCreateDatabase(internalName, mode, factory, errorHandler); 168 } 169 170 @Override 171 public boolean deleteDatabase(String name) { 172 if (mDatabaseNames.contains(name)) { 173 mDatabaseNames.remove(name); 174 return mFileContext.deleteDatabase(renamedFileName(name)); 175 } else { 176 return false; 177 } 178 } 179 180 @Override 181 public File getDatabasePath(String name) { 182 return mFileContext.getDatabasePath(renamedFileName(name)); 183 } 184 185 @Override 186 public String[] databaseList() { 187 return mDatabaseNames.toArray(new String[]{}); 188 } 189 190 @Override 191 public FileInputStream openFileInput(String name) 192 throws FileNotFoundException { 193 final String internalName = renamedFileName(name); 194 if (mFileNames.contains(name)) { 195 return mFileContext.openFileInput(internalName); 196 } else { 197 throw new FileNotFoundException(internalName); 198 } 199 } 200 201 @Override 202 public FileOutputStream openFileOutput(String name, int mode) 203 throws FileNotFoundException { 204 mFileNames.add(name); 205 return mFileContext.openFileOutput(renamedFileName(name), mode); 206 } 207 208 @Override 209 public File getFileStreamPath(String name) { 210 return mFileContext.getFileStreamPath(renamedFileName(name)); 211 } 212 213 @Override 214 public boolean deleteFile(String name) { 215 if (mFileNames.contains(name)) { 216 mFileNames.remove(name); 217 return mFileContext.deleteFile(renamedFileName(name)); 218 } else { 219 return false; 220 } 221 } 222 223 @Override 224 public String[] fileList() { 225 return mFileNames.toArray(new String[]{}); 226 } 227 228 /** 229 * In order to support calls to getCacheDir(), we create a temp cache dir (inside the real 230 * one) and return it instead. This code is basically getCacheDir(), except it uses the real 231 * cache dir as the parent directory and creates a test cache dir inside that. 232 */ 233 @Override 234 public File getCacheDir() { 235 synchronized (mSync) { 236 if (mCacheDir == null) { 237 mCacheDir = new File(mFileContext.getCacheDir(), renamedFileName("cache")); 238 } 239 if (!mCacheDir.exists()) { 240 if(!mCacheDir.mkdirs()) { 241 Log.w("RenamingDelegatingContext", "Unable to create cache directory"); 242 return null; 243 } 244 try { 245 // Give the directory all possible permissions. 246 Files.setPosixFilePermissions(mCacheDir.toPath(), 247 EnumSet.allOf(PosixFilePermission.class)); 248 } catch (IOException e) { 249 Log.e("RenamingDelegatingContext", 250 "Could not set permissions of test cacheDir", e); 251 } 252 } 253 } 254 return mCacheDir; 255 } 256 } 257