| /* | |
| * Copyright (C) 2007 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| package android.test; | |
| import android.content.Context; | |
| import android.content.ContextWrapper; | |
| import android.content.ContentProvider; | |
| import android.database.DatabaseErrorHandler; | |
| import android.database.sqlite.SQLiteDatabase; | |
| import android.test.mock.MockContentProvider; | |
| import android.util.Log; | |
| import java.io.File; | |
| import java.io.FileInputStream; | |
| import java.io.FileNotFoundException; | |
| import java.io.FileOutputStream; | |
| import java.io.IOException; | |
| import java.nio.file.Files; | |
| import java.nio.file.Paths; | |
| import java.nio.file.attribute.PosixFilePermission; | |
| import java.nio.file.attribute.PosixFilePermissions; | |
| import java.util.EnumSet; | |
| import java.util.HashSet; | |
| import java.util.Set; | |
| /** | |
| * This is a class which delegates to the given context, but performs database | |
| * and file operations with a renamed database/file name (prefixes default | |
| * names with a given prefix). | |
| * | |
| * @deprecated New tests should be written using the | |
| * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. | |
| */ | |
| @Deprecated | |
| public class RenamingDelegatingContext extends ContextWrapper { | |
| private Context mFileContext; | |
| private String mFilePrefix = null; | |
| private File mCacheDir; | |
| private final Object mSync = new Object(); | |
| private Set<String> mDatabaseNames = new HashSet<>(); | |
| private Set<String> mFileNames = new HashSet<>(); | |
| public static <T extends ContentProvider> T providerWithRenamedContext( | |
| Class<T> contentProvider, Context c, String filePrefix) | |
| throws IllegalAccessException, InstantiationException { | |
| return providerWithRenamedContext(contentProvider, c, filePrefix, false); | |
| } | |
| public static <T extends ContentProvider> T providerWithRenamedContext( | |
| Class<T> contentProvider, Context c, String filePrefix, | |
| boolean allowAccessToExistingFilesAndDbs) | |
| throws IllegalAccessException, InstantiationException { | |
| Class<T> mProviderClass = contentProvider; | |
| T mProvider = mProviderClass.newInstance(); | |
| RenamingDelegatingContext mContext = new RenamingDelegatingContext(c, filePrefix); | |
| if (allowAccessToExistingFilesAndDbs) { | |
| mContext.makeExistingFilesAndDbsAccessible(); | |
| } | |
| MockContentProvider.attachInfoForTesting(mProvider, mContext, null); | |
| return mProvider; | |
| } | |
| /** | |
| * Makes accessible all files and databases whose names match the filePrefix that was passed to | |
| * the constructor. Normally only files and databases that were created through this context are | |
| * accessible. | |
| */ | |
| public void makeExistingFilesAndDbsAccessible() { | |
| String[] databaseList = mFileContext.databaseList(); | |
| for (String diskName : databaseList) { | |
| if (shouldDiskNameBeVisible(diskName)) { | |
| mDatabaseNames.add(publicNameFromDiskName(diskName)); | |
| } | |
| } | |
| String[] fileList = mFileContext.fileList(); | |
| for (String diskName : fileList) { | |
| if (shouldDiskNameBeVisible(diskName)) { | |
| mFileNames.add(publicNameFromDiskName(diskName)); | |
| } | |
| } | |
| } | |
| /** | |
| * Returns if the given diskName starts with the given prefix or not. | |
| * @param diskName name of the database/file. | |
| */ | |
| boolean shouldDiskNameBeVisible(String diskName) { | |
| return diskName.startsWith(mFilePrefix); | |
| } | |
| /** | |
| * Returns the public name (everything following the prefix) of the given diskName. | |
| * @param diskName name of the database/file. | |
| */ | |
| String publicNameFromDiskName(String diskName) { | |
| if (!shouldDiskNameBeVisible(diskName)) { | |
| throw new IllegalArgumentException("disk file should not be visible: " + diskName); | |
| } | |
| return diskName.substring(mFilePrefix.length(), diskName.length()); | |
| } | |
| /** | |
| * @param context : the context that will be delegated. | |
| * @param filePrefix : a prefix with which database and file names will be | |
| * prefixed. | |
| */ | |
| public RenamingDelegatingContext(Context context, String filePrefix) { | |
| super(context); | |
| mFileContext = context; | |
| mFilePrefix = filePrefix; | |
| } | |
| /** | |
| * @param context : the context that will be delegated. | |
| * @param fileContext : the context that file and db methods will be delegated to | |
| * @param filePrefix : a prefix with which database and file names will be | |
| * prefixed. | |
| */ | |
| public RenamingDelegatingContext(Context context, Context fileContext, String filePrefix) { | |
| super(context); | |
| mFileContext = fileContext; | |
| mFilePrefix = filePrefix; | |
| } | |
| public String getDatabasePrefix() { | |
| return mFilePrefix; | |
| } | |
| private String renamedFileName(String name) { | |
| return mFilePrefix + name; | |
| } | |
| @Override | |
| public SQLiteDatabase openOrCreateDatabase(String name, | |
| int mode, SQLiteDatabase.CursorFactory factory) { | |
| final String internalName = renamedFileName(name); | |
| if (!mDatabaseNames.contains(name)) { | |
| mDatabaseNames.add(name); | |
| mFileContext.deleteDatabase(internalName); | |
| } | |
| return mFileContext.openOrCreateDatabase(internalName, mode, factory); | |
| } | |
| @Override | |
| public SQLiteDatabase openOrCreateDatabase(String name, | |
| int mode, SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler) { | |
| final String internalName = renamedFileName(name); | |
| if (!mDatabaseNames.contains(name)) { | |
| mDatabaseNames.add(name); | |
| mFileContext.deleteDatabase(internalName); | |
| } | |
| return mFileContext.openOrCreateDatabase(internalName, mode, factory, errorHandler); | |
| } | |
| @Override | |
| public boolean deleteDatabase(String name) { | |
| if (mDatabaseNames.contains(name)) { | |
| mDatabaseNames.remove(name); | |
| return mFileContext.deleteDatabase(renamedFileName(name)); | |
| } else { | |
| return false; | |
| } | |
| } | |
| @Override | |
| public File getDatabasePath(String name) { | |
| return mFileContext.getDatabasePath(renamedFileName(name)); | |
| } | |
| @Override | |
| public String[] databaseList() { | |
| return mDatabaseNames.toArray(new String[]{}); | |
| } | |
| @Override | |
| public FileInputStream openFileInput(String name) | |
| throws FileNotFoundException { | |
| final String internalName = renamedFileName(name); | |
| if (mFileNames.contains(name)) { | |
| return mFileContext.openFileInput(internalName); | |
| } else { | |
| throw new FileNotFoundException(internalName); | |
| } | |
| } | |
| @Override | |
| public FileOutputStream openFileOutput(String name, int mode) | |
| throws FileNotFoundException { | |
| mFileNames.add(name); | |
| return mFileContext.openFileOutput(renamedFileName(name), mode); | |
| } | |
| @Override | |
| public File getFileStreamPath(String name) { | |
| return mFileContext.getFileStreamPath(renamedFileName(name)); | |
| } | |
| @Override | |
| public boolean deleteFile(String name) { | |
| if (mFileNames.contains(name)) { | |
| mFileNames.remove(name); | |
| return mFileContext.deleteFile(renamedFileName(name)); | |
| } else { | |
| return false; | |
| } | |
| } | |
| @Override | |
| public String[] fileList() { | |
| return mFileNames.toArray(new String[]{}); | |
| } | |
| /** | |
| * In order to support calls to getCacheDir(), we create a temp cache dir (inside the real | |
| * one) and return it instead. This code is basically getCacheDir(), except it uses the real | |
| * cache dir as the parent directory and creates a test cache dir inside that. | |
| */ | |
| @Override | |
| public File getCacheDir() { | |
| synchronized (mSync) { | |
| if (mCacheDir == null) { | |
| mCacheDir = new File(mFileContext.getCacheDir(), renamedFileName("cache")); | |
| } | |
| if (!mCacheDir.exists()) { | |
| if(!mCacheDir.mkdirs()) { | |
| Log.w("RenamingDelegatingContext", "Unable to create cache directory"); | |
| return null; | |
| } | |
| try { | |
| // Give the directory all possible permissions. | |
| Files.setPosixFilePermissions(mCacheDir.toPath(), | |
| EnumSet.allOf(PosixFilePermission.class)); | |
| } catch (IOException e) { | |
| Log.e("RenamingDelegatingContext", | |
| "Could not set permissions of test cacheDir", e); | |
| } | |
| } | |
| } | |
| return mCacheDir; | |
| } | |
| } |