package com.orgzly.android; import android.content.Context; import android.os.Build; import android.os.Environment; import android.util.Log; import com.orgzly.BuildConfig; import com.orgzly.android.util.LogUtils; import java.io.File; import java.io.IOException; /** * Provides directories for various different types of files that needs to be stored locally. * Prefers cache directories for temporary files, external storage for large files etc. */ public class LocalStorage { private static final String TAG = LocalStorage.class.getName(); private Context mContext; public LocalStorage(Context context) { mContext = context; } /** * Get file to which {@link Book} will be exported. * @param format book's format * @throws IOException if external directory is not available */ public File getExportFile(Book book, BookName.Format format) throws IOException { return new File(exportedBookDirectory(), BookName.fileName(book.getName(), format)); } /** * Get temporary {@code File} for storing {@link Book}'s content. * @throws IOException */ public File getTempBookFile() throws IOException { File baseDir; if (isExternalStorageWritable()) { baseDir = externalCacheDir("tmp"); } else { baseDir = internalCacheDir("tmp"); } try { return File.createTempFile("notebook.", ".tmp", baseDir); } catch (IOException e) { throw new IOException("Failed creating temporary file in " + baseDir + ": " + e.getMessage()); } } public File getLocalRepoDirectory(String dir) throws IOException { File baseDir; if (isExternalStorageWritable()) { baseDir = externalCacheDir(dir); } else { baseDir = internalCacheDir(dir); } return baseDir; } /** * Export directory. */ private File exportedBookDirectory() throws IOException { if (!isExternalStorageWritable()) { throw new IOException("External storage directory not available for writing"); } File file = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); // File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), APP_NAME); if (! file.isDirectory()) { if (! file.mkdirs()) { throw new IOException("Failed creating directory " + file); } } return file; } private File externalCacheDir(String dir) throws IOException { File file = new File(mContext.getExternalCacheDir(), dir); if (! file.isDirectory()) { if (! file.mkdirs()) { throw new IOException("Failed creating directory " + file); } } return file; } private File internalCacheDir(String dir) throws IOException { File file = new File(mContext.getCacheDir(), dir); if (! file.isDirectory()) { if (! file.mkdirs()) { throw new IOException("Failed creating directory " + file); } } return file; } /* Checks if external storage is available for read and write */ // TODO: What is there is no external storage? // Must use internal but remember that by saving to // preferences or something when initializing for the first time? private boolean isExternalStorageWritable() { String state = Environment.getExternalStorageState(); return Environment.MEDIA_MOUNTED.equals(state); } /** * Removes all temporary and cache files. */ public void cleanup() { deleteRecursive(mContext.getCacheDir()); if (isExternalStorageWritable()) { deleteRecursive(mContext.getExternalCacheDir()); } } public static void deleteRecursive(File file) { if (file.isDirectory()) { String[] children = file.list(); for (String aChildren : children) { deleteRecursive(new File(file, aChildren)); } } if (BuildConfig.LOG_DEBUG) LogUtils.d(TAG, "Deleting " + file + " ..."); if (! file.delete()) { Log.e(TAG, "Failed deleting " + file); } } /** * Assume accessible secondary storage only if new API can be used. */ public static boolean isSecondaryStorageAccessible(Context context) { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && context.getExternalCacheDirs().length > 1 && // Internal and at least one more context.getExternalCacheDirs()[1] != null; // Can be null if ejected } }