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 17package android.test; 18 19import com.google.android.collect.Sets; 20 21import android.content.Context; 22import android.content.ContextWrapper; 23import android.content.ContentProvider; 24import android.database.DatabaseErrorHandler; 25import android.database.sqlite.SQLiteDatabase; 26import android.os.FileUtils; 27import android.util.Log; 28 29import java.io.File; 30import java.io.FileInputStream; 31import java.io.FileNotFoundException; 32import java.io.FileOutputStream; 33import java.util.Set; 34 35/** 36 * This is a class which delegates to the given context, but performs database 37 * and file operations with a renamed database/file name (prefixes default 38 * names with a given prefix). 39 * 40 * @deprecated New tests should be written using the 41 * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. 42 */ 43@Deprecated 44public class RenamingDelegatingContext extends ContextWrapper { 45 46 private Context mFileContext; 47 private String mFilePrefix = null; 48 private File mCacheDir; 49 private final Object mSync = new Object(); 50 51 private Set<String> mDatabaseNames = Sets.newHashSet(); 52 private Set<String> mFileNames = Sets.newHashSet(); 53 54 public static <T extends ContentProvider> T providerWithRenamedContext( 55 Class<T> contentProvider, Context c, String filePrefix) 56 throws IllegalAccessException, InstantiationException { 57 return providerWithRenamedContext(contentProvider, c, filePrefix, false); 58 } 59 60 public static <T extends ContentProvider> T providerWithRenamedContext( 61 Class<T> contentProvider, Context c, String filePrefix, 62 boolean allowAccessToExistingFilesAndDbs) 63 throws IllegalAccessException, InstantiationException { 64 Class<T> mProviderClass = contentProvider; 65 T mProvider = mProviderClass.newInstance(); 66 RenamingDelegatingContext mContext = new RenamingDelegatingContext(c, filePrefix); 67 if (allowAccessToExistingFilesAndDbs) { 68 mContext.makeExistingFilesAndDbsAccessible(); 69 } 70 mProvider.attachInfoForTesting(mContext, null); 71 return mProvider; 72 } 73 74 /** 75 * Makes accessible all files and databases whose names match the filePrefix that was passed to 76 * the constructor. Normally only files and databases that were created through this context are 77 * accessible. 78 */ 79 public void makeExistingFilesAndDbsAccessible() { 80 String[] databaseList = mFileContext.databaseList(); 81 for (String diskName : databaseList) { 82 if (shouldDiskNameBeVisible(diskName)) { 83 mDatabaseNames.add(publicNameFromDiskName(diskName)); 84 } 85 } 86 String[] fileList = mFileContext.fileList(); 87 for (String diskName : fileList) { 88 if (shouldDiskNameBeVisible(diskName)) { 89 mFileNames.add(publicNameFromDiskName(diskName)); 90 } 91 } 92 } 93 94 /** 95 * Returns if the given diskName starts with the given prefix or not. 96 * @param diskName name of the database/file. 97 */ 98 boolean shouldDiskNameBeVisible(String diskName) { 99 return diskName.startsWith(mFilePrefix); 100 } 101 102 /** 103 * Returns the public name (everything following the prefix) of the given diskName. 104 * @param diskName name of the database/file. 105 */ 106 String publicNameFromDiskName(String diskName) { 107 if (!shouldDiskNameBeVisible(diskName)) { 108 throw new IllegalArgumentException("disk file should not be visible: " + diskName); 109 } 110 return diskName.substring(mFilePrefix.length(), diskName.length()); 111 } 112 113 /** 114 * @param context : the context that will be delegated. 115 * @param filePrefix : a prefix with which database and file names will be 116 * prefixed. 117 */ 118 public RenamingDelegatingContext(Context context, String filePrefix) { 119 super(context); 120 mFileContext = context; 121 mFilePrefix = filePrefix; 122 } 123 124 /** 125 * @param context : the context that will be delegated. 126 * @param fileContext : the context that file and db methods will be delegated to 127 * @param filePrefix : a prefix with which database and file names will be 128 * prefixed. 129 */ 130 public RenamingDelegatingContext(Context context, Context fileContext, String filePrefix) { 131 super(context); 132 mFileContext = fileContext; 133 mFilePrefix = filePrefix; 134 } 135 136 public String getDatabasePrefix() { 137 return mFilePrefix; 138 } 139 140 private String renamedFileName(String name) { 141 return mFilePrefix + name; 142 } 143 144 @Override 145 public SQLiteDatabase openOrCreateDatabase(String name, 146 int mode, SQLiteDatabase.CursorFactory factory) { 147 final String internalName = renamedFileName(name); 148 if (!mDatabaseNames.contains(name)) { 149 mDatabaseNames.add(name); 150 mFileContext.deleteDatabase(internalName); 151 } 152 return mFileContext.openOrCreateDatabase(internalName, mode, factory); 153 } 154 155 @Override 156 public SQLiteDatabase openOrCreateDatabase(String name, 157 int mode, SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler) { 158 final String internalName = renamedFileName(name); 159 if (!mDatabaseNames.contains(name)) { 160 mDatabaseNames.add(name); 161 mFileContext.deleteDatabase(internalName); 162 } 163 return mFileContext.openOrCreateDatabase(internalName, mode, factory, errorHandler); 164 } 165 166 @Override 167 public boolean deleteDatabase(String name) { 168 if (mDatabaseNames.contains(name)) { 169 mDatabaseNames.remove(name); 170 return mFileContext.deleteDatabase(renamedFileName(name)); 171 } else { 172 return false; 173 } 174 } 175 176 @Override 177 public File getDatabasePath(String name) { 178 return mFileContext.getDatabasePath(renamedFileName(name)); 179 } 180 181 @Override 182 public String[] databaseList() { 183 return mDatabaseNames.toArray(new String[]{}); 184 } 185 186 @Override 187 public FileInputStream openFileInput(String name) 188 throws FileNotFoundException { 189 final String internalName = renamedFileName(name); 190 if (mFileNames.contains(name)) { 191 return mFileContext.openFileInput(internalName); 192 } else { 193 throw new FileNotFoundException(internalName); 194 } 195 } 196 197 @Override 198 public FileOutputStream openFileOutput(String name, int mode) 199 throws FileNotFoundException { 200 mFileNames.add(name); 201 return mFileContext.openFileOutput(renamedFileName(name), mode); 202 } 203 204 @Override 205 public File getFileStreamPath(String name) { 206 return mFileContext.getFileStreamPath(renamedFileName(name)); 207 } 208 209 @Override 210 public boolean deleteFile(String name) { 211 if (mFileNames.contains(name)) { 212 mFileNames.remove(name); 213 return mFileContext.deleteFile(renamedFileName(name)); 214 } else { 215 return false; 216 } 217 } 218 219 @Override 220 public String[] fileList() { 221 return mFileNames.toArray(new String[]{}); 222 } 223 224 /** 225 * In order to support calls to getCacheDir(), we create a temp cache dir (inside the real 226 * one) and return it instead. This code is basically getCacheDir(), except it uses the real 227 * cache dir as the parent directory and creates a test cache dir inside that. 228 */ 229 @Override 230 public File getCacheDir() { 231 synchronized (mSync) { 232 if (mCacheDir == null) { 233 mCacheDir = new File(mFileContext.getCacheDir(), renamedFileName("cache")); 234 } 235 if (!mCacheDir.exists()) { 236 if(!mCacheDir.mkdirs()) { 237 Log.w("RenamingDelegatingContext", "Unable to create cache directory"); 238 return null; 239 } 240 FileUtils.setPermissions( 241 mCacheDir.getPath(), 242 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH, 243 -1, -1); 244 } 245 } 246 return mCacheDir; 247 } 248} 249