blob: 3d763c76fb283cbe78969f4a37cd3f10da29c8ca [file] [log] [blame]
Kenny Root10362ab2010-03-12 11:13:50 -08001/*
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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080017package android.test;
18
19import com.google.android.collect.Sets;
20
21import android.content.Context;
22import android.content.ContextWrapper;
23import android.content.ContentProvider;
Makoto Onukif6b979a2010-06-04 16:12:15 -070024import android.database.DatabaseErrorHandler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.database.sqlite.SQLiteDatabase;
Andrew Stadler54a16f02009-07-23 20:00:08 -070026import android.os.FileUtils;
27import android.util.Log;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028
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 */
40public class RenamingDelegatingContext extends ContextWrapper {
41
42 private Context mFileContext;
43 private String mFilePrefix = null;
Andrew Stadler54a16f02009-07-23 20:00:08 -070044 private File mCacheDir;
45 private final Object mSync = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046
47 private Set<String> mDatabaseNames = Sets.newHashSet();
48 private Set<String> mFileNames = Sets.newHashSet();
49
50 public static <T extends ContentProvider> T providerWithRenamedContext(
51 Class<T> contentProvider, Context c, String filePrefix)
52 throws IllegalAccessException, InstantiationException {
53 return providerWithRenamedContext(contentProvider, c, filePrefix, false);
54 }
55
56 public static <T extends ContentProvider> T providerWithRenamedContext(
57 Class<T> contentProvider, Context c, String filePrefix,
58 boolean allowAccessToExistingFilesAndDbs)
59 throws IllegalAccessException, InstantiationException {
60 Class<T> mProviderClass = contentProvider;
61 T mProvider = mProviderClass.newInstance();
62 RenamingDelegatingContext mContext = new RenamingDelegatingContext(c, filePrefix);
63 if (allowAccessToExistingFilesAndDbs) {
64 mContext.makeExistingFilesAndDbsAccessible();
65 }
Dianne Hackborn334d9ae2013-02-26 15:02:06 -080066 mProvider.attachInfoForTesting(mContext, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067 return mProvider;
68 }
69
70 /**
71 * Makes accessible all files and databases whose names match the filePrefix that was passed to
72 * the constructor. Normally only files and databases that were created through this context are
73 * accessible.
74 */
75 public void makeExistingFilesAndDbsAccessible() {
76 String[] databaseList = mFileContext.databaseList();
77 for (String diskName : databaseList) {
78 if (shouldDiskNameBeVisible(diskName)) {
79 mDatabaseNames.add(publicNameFromDiskName(diskName));
80 }
81 }
82 String[] fileList = mFileContext.fileList();
83 for (String diskName : fileList) {
84 if (shouldDiskNameBeVisible(diskName)) {
85 mFileNames.add(publicNameFromDiskName(diskName));
86 }
87 }
88 }
89
90 /**
91 * Returns if the given diskName starts with the given prefix or not.
92 * @param diskName name of the database/file.
93 */
94 boolean shouldDiskNameBeVisible(String diskName) {
95 return diskName.startsWith(mFilePrefix);
96 }
97
98 /**
99 * Returns the public name (everything following the prefix) of the given diskName.
100 * @param diskName name of the database/file.
101 */
102 String publicNameFromDiskName(String diskName) {
103 if (!shouldDiskNameBeVisible(diskName)) {
104 throw new IllegalArgumentException("disk file should not be visible: " + diskName);
105 }
106 return diskName.substring(mFilePrefix.length(), diskName.length());
107 }
108
109 /**
110 * @param context : the context that will be delagated.
111 * @param filePrefix : a prefix with which database and file names will be
112 * prefixed.
113 */
114 public RenamingDelegatingContext(Context context, String filePrefix) {
115 super(context);
116 mFileContext = context;
117 mFilePrefix = filePrefix;
118 }
119
120 /**
121 * @param context : the context that will be delagated.
122 * @param fileContext : the context that file and db methods will be delgated to
123 * @param filePrefix : a prefix with which database and file names will be
124 * prefixed.
125 */
126 public RenamingDelegatingContext(Context context, Context fileContext, String filePrefix) {
127 super(context);
128 mFileContext = fileContext;
129 mFilePrefix = filePrefix;
130 }
131
132 public String getDatabasePrefix() {
133 return mFilePrefix;
134 }
135
136 private String renamedFileName(String name) {
137 return mFilePrefix + name;
138 }
139
140 @Override
141 public SQLiteDatabase openOrCreateDatabase(String name,
142 int mode, SQLiteDatabase.CursorFactory factory) {
143 final String internalName = renamedFileName(name);
144 if (!mDatabaseNames.contains(name)) {
145 mDatabaseNames.add(name);
146 mFileContext.deleteDatabase(internalName);
147 }
148 return mFileContext.openOrCreateDatabase(internalName, mode, factory);
149 }
150
151 @Override
Makoto Onukif6b979a2010-06-04 16:12:15 -0700152 public SQLiteDatabase openOrCreateDatabase(String name,
153 int mode, SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler) {
154 final String internalName = renamedFileName(name);
155 if (!mDatabaseNames.contains(name)) {
156 mDatabaseNames.add(name);
157 mFileContext.deleteDatabase(internalName);
158 }
159 return mFileContext.openOrCreateDatabase(internalName, mode, factory, errorHandler);
160 }
161
162 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163 public boolean deleteDatabase(String name) {
164 if (mDatabaseNames.contains(name)) {
165 mDatabaseNames.remove(name);
166 return mFileContext.deleteDatabase(renamedFileName(name));
167 } else {
168 return false;
169 }
170 }
Andrew Stadlerb09296d2009-06-24 22:32:40 -0700171
172 @Override
173 public File getDatabasePath(String name) {
174 return mFileContext.getDatabasePath(renamedFileName(name));
175 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176
177 @Override
178 public String[] databaseList() {
179 return mDatabaseNames.toArray(new String[]{});
180 }
181
182 @Override
183 public FileInputStream openFileInput(String name)
184 throws FileNotFoundException {
185 final String internalName = renamedFileName(name);
186 if (mFileNames.contains(name)) {
187 return mFileContext.openFileInput(internalName);
188 } else {
189 throw new FileNotFoundException(internalName);
190 }
191 }
192
193 @Override
194 public FileOutputStream openFileOutput(String name, int mode)
195 throws FileNotFoundException {
196 mFileNames.add(name);
197 return mFileContext.openFileOutput(renamedFileName(name), mode);
198 }
199
200 @Override
201 public File getFileStreamPath(String name) {
202 return mFileContext.getFileStreamPath(renamedFileName(name));
203 }
204
205 @Override
206 public boolean deleteFile(String name) {
207 if (mFileNames.contains(name)) {
208 mFileNames.remove(name);
209 return mFileContext.deleteFile(renamedFileName(name));
210 } else {
211 return false;
212 }
213 }
214
215 @Override
216 public String[] fileList() {
217 return mFileNames.toArray(new String[]{});
218 }
Andrew Stadler54a16f02009-07-23 20:00:08 -0700219
220 /**
221 * In order to support calls to getCacheDir(), we create a temp cache dir (inside the real
222 * one) and return it instead. This code is basically getCacheDir(), except it uses the real
223 * cache dir as the parent directory and creates a test cache dir inside that.
224 */
225 @Override
226 public File getCacheDir() {
227 synchronized (mSync) {
228 if (mCacheDir == null) {
229 mCacheDir = new File(mFileContext.getCacheDir(), renamedFileName("cache"));
230 }
231 if (!mCacheDir.exists()) {
232 if(!mCacheDir.mkdirs()) {
233 Log.w("RenamingDelegatingContext", "Unable to create cache directory");
234 return null;
235 }
236 FileUtils.setPermissions(
237 mCacheDir.getPath(),
238 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
239 -1, -1);
240 }
241 }
242 return mCacheDir;
243 }
244
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245
246// /**
247// * Given an array of files returns only those whose names indicate that they belong to this
248// * context.
249// * @param allFiles the original list of files
250// * @return the pruned list of files
251// */
252// private String[] prunedFileList(String[] allFiles) {
253// List<String> files = Lists.newArrayList();
254// for (String file : allFiles) {
255// if (file.startsWith(mFilePrefix)) {
256// files.add(file);
257// }
258// }
259// return files.toArray(new String[]{});
260// }
Kenny Root10362ab2010-03-12 11:13:50 -0800261}