/**
* Copyright 2009 Joe LaPenna
*/
package com.joelapenna.foursquared.util;
import com.joelapenna.foursquared.FoursquaredSettings;
import android.os.Environment;
import android.util.Log;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* @author Joe LaPenna (joe@joelapenna.com)
*/
public class BaseDiskCache implements DiskCache {
private static final String TAG = "BaseDiskCache";
private static final boolean DEBUG = FoursquaredSettings.DEBUG;
private static final String NOMEDIA = ".nomedia";
private static final int MIN_FILE_SIZE_IN_BYTES = 100;
private File mStorageDirectory;
BaseDiskCache(String dirPath, String name) {
// Lets make sure we can actually cache things!
File baseDirectory = new File(Environment.getExternalStorageDirectory(), dirPath);
File storageDirectory = new File(baseDirectory, name);
createDirectory(storageDirectory);
mStorageDirectory = storageDirectory;
// cleanup(); // Remove invalid files that may have shown up.
cleanupSimple();
}
/*
* (non-Javadoc)
* @see com.joelapenna.foursquared.util.DiskCache#exists(java.lang.String)
*/
@Override
public boolean exists(String key) {
return getFile(key).exists();
}
/**
* This is silly, but our content provider *has* to serve content: URIs as File/FileDescriptors
* using ContentProvider.openAssetFile, this is a limitation of the StreamLoader that is used by
* the WebView. So, we handle this by writing the file to disk, and returning a File pointer to
* it.
*
* @param guid
* @return
*/
public File getFile(String hash) {
return new File(mStorageDirectory.toString() + File.separator + hash);
}
public InputStream getInputStream(String hash) throws IOException {
return (InputStream)new FileInputStream(getFile(hash));
}
/*
* (non-Javadoc)
* @see com.joelapenna.everdroid.evernote.NoteResourceDataBodyCache#storeResource (com
* .evernote.edam.type.Resource)
*/
public void store(String key, InputStream is) {
if (DEBUG) Log.d(TAG, "store: " + key);
is = new BufferedInputStream(is);
try {
OutputStream os = new BufferedOutputStream(new FileOutputStream(getFile(key)));
byte[] b = new byte[2048];
int count;
int total = 0;
while ((count = is.read(b)) > 0) {
os.write(b, 0, count);
total += count;
}
os.close();
if (DEBUG) Log.d(TAG, "store complete: " + key);
} catch (IOException e) {
if (DEBUG) Log.d(TAG, "store failed to store: " + key, e);
return;
}
}
public void invalidate(String key) {
getFile(key).delete();
}
public void cleanup() {
// removes files that are too small to be valid. Cheap and cheater way to remove files that
// were corrupted during download.
String[] children = mStorageDirectory.list();
if (children != null) { // children will be null if hte directyr does not exist.
for (int i = 0; i < children.length; i++) {
File child = new File(mStorageDirectory, children[i]);
if (!child.equals(new File(mStorageDirectory, NOMEDIA))
&& child.length() <= MIN_FILE_SIZE_IN_BYTES) {
if (DEBUG) Log.d(TAG, "Deleting: " + child);
child.delete();
}
}
}
}
/**
* Temporary fix until we rework this disk cache. We delete the first 50 youngest files
* if we find the cache has more than 1000 images in it.
*/
public void cleanupSimple() {
final int maxNumFiles = 1000;
final int numFilesToDelete = 50;
String[] children = mStorageDirectory.list();
if (children != null) {
if (DEBUG) Log.d(TAG, "Found disk cache length to be: " + children.length);
if (children.length > maxNumFiles) {
if (DEBUG) Log.d(TAG, "Disk cache found to : " + children);
for (int i = children.length - 1, m = i - numFilesToDelete; i > m; i--) {
File child = new File(mStorageDirectory, children[i]);
if (DEBUG) Log.d(TAG, " deleting: " + child.getName());
child.delete();
}
}
}
}
public void clear() {
// Clear the whole cache. Coolness.
String[] children = mStorageDirectory.list();
if (children != null) { // children will be null if hte directyr does not exist.
for (int i = 0; i < children.length; i++) {
File child = new File(mStorageDirectory, children[i]);
if (!child.equals(new File(mStorageDirectory, NOMEDIA))) {
if (DEBUG) Log.d(TAG, "Deleting: " + child);
child.delete();
}
}
}
mStorageDirectory.delete();
}
private static final void createDirectory(File storageDirectory) {
if (!storageDirectory.exists()) {
Log.d(TAG, "Trying to create storageDirectory: "
+ String.valueOf(storageDirectory.mkdirs()));
Log.d(TAG, "Exists: " + storageDirectory + " "
+ String.valueOf(storageDirectory.exists()));
Log.d(TAG, "State: " + Environment.getExternalStorageState());
Log.d(TAG, "Isdir: " + storageDirectory + " "
+ String.valueOf(storageDirectory.isDirectory()));
Log.d(TAG, "Readable: " + storageDirectory + " "
+ String.valueOf(storageDirectory.canRead()));
Log.d(TAG, "Writable: " + storageDirectory + " "
+ String.valueOf(storageDirectory.canWrite()));
File tmp = storageDirectory.getParentFile();
Log.d(TAG, "Exists: " + tmp + " " + String.valueOf(tmp.exists()));
Log.d(TAG, "Isdir: " + tmp + " " + String.valueOf(tmp.isDirectory()));
Log.d(TAG, "Readable: " + tmp + " " + String.valueOf(tmp.canRead()));
Log.d(TAG, "Writable: " + tmp + " " + String.valueOf(tmp.canWrite()));
tmp = tmp.getParentFile();
Log.d(TAG, "Exists: " + tmp + " " + String.valueOf(tmp.exists()));
Log.d(TAG, "Isdir: " + tmp + " " + String.valueOf(tmp.isDirectory()));
Log.d(TAG, "Readable: " + tmp + " " + String.valueOf(tmp.canRead()));
Log.d(TAG, "Writable: " + tmp + " " + String.valueOf(tmp.canWrite()));
}
File nomediaFile = new File(storageDirectory, NOMEDIA);
if (!nomediaFile.exists()) {
try {
Log.d(TAG, "Created file: " + nomediaFile + " "
+ String.valueOf(nomediaFile.createNewFile()));
} catch (IOException e) {
Log.d(TAG, "Unable to create .nomedia file for some reason.", e);
throw new IllegalStateException("Unable to create nomedia file.");
}
}
// After we best-effort try to create the file-structure we need,
// lets make sure it worked.
if (!(storageDirectory.isDirectory() && nomediaFile.exists())) {
throw new RuntimeException("Unable to create storage directory and nomedia file.");
}
}
}