diff --git a/build.gradle b/build.gradle index e3ec86c..a0f1cff 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:1.3.0' + classpath 'com.android.tools.build:gradle:2.1.2' } } diff --git a/files/devbytes.mp4 b/files/devbytes.mp4 deleted file mode 100644 index 5f44b30..0000000 Binary files a/files/devbytes.mp4 and /dev/null differ diff --git a/files/orange1.mp4 b/files/orange1.mp4 deleted file mode 100644 index d141369..0000000 Binary files a/files/orange1.mp4 and /dev/null differ diff --git a/files/orange2.mp4 b/files/orange2.mp4 deleted file mode 100644 index d36110b..0000000 Binary files a/files/orange2.mp4 and /dev/null differ diff --git a/files/orange3.mp4 b/files/orange3.mp4 deleted file mode 100644 index 92f773f..0000000 Binary files a/files/orange3.mp4 and /dev/null differ diff --git a/files/orange4.mp4 b/files/orange4.mp4 deleted file mode 100644 index d5afbb0..0000000 Binary files a/files/orange4.mp4 and /dev/null differ diff --git a/files/orange5.mp4 b/files/orange5.mp4 deleted file mode 100644 index 9722d8c..0000000 Binary files a/files/orange5.mp4 and /dev/null differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 07fc193..120eef5 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Wed Apr 10 15:27:10 PDT 2013 +#Sat Apr 30 01:45:38 AWST 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip diff --git a/library/build.gradle b/library/build.gradle index 1d619e8..43fbbe2 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -2,16 +2,18 @@ buildscript { repositories { jcenter() } - dependencies { - classpath 'com.novoda:bintray-release:0.2.10' - } } apply plugin: 'idea' apply plugin: 'java' -apply plugin: 'bintray-release' + +sourceCompatibility = 1.7 +targetCompatibility = 1.7 idea { + sourceCompatibility = JavaVersion.VERSION_1_7 + targetCompatibility = JavaVersion.VERSION_1_7 + module { downloadJavadoc = true downloadSources = true @@ -21,12 +23,3 @@ idea { dependencies { compile 'com.google.android:android:1.6_r2' } - -publish { - userOrg = 'alexeydanilov' - groupId = 'com.danikula' - artifactId = 'videocache' - publishVersion = '2.3.4' - description = 'Cache support for android VideoView' - website = 'https://github.com/danikula/AndroidVideoCache' -} diff --git a/library/src/main/java/com/danikula/videocache/Config.java b/library/src/main/java/com/danikula/videocache/Config.java index bcf4e77..151dfd3 100644 --- a/library/src/main/java/com/danikula/videocache/Config.java +++ b/library/src/main/java/com/danikula/videocache/Config.java @@ -1,5 +1,7 @@ package com.danikula.videocache; +import android.database.sqlite.SQLiteDatabase; + import com.danikula.videocache.file.DiskUsage; import com.danikula.videocache.file.FileNameGenerator; @@ -15,11 +17,13 @@ class Config { public final File cacheRoot; public final FileNameGenerator fileNameGenerator; public final DiskUsage diskUsage; + public final SQLiteDatabase contentInfoDb; - Config(File cacheRoot, FileNameGenerator fileNameGenerator, DiskUsage diskUsage) { + Config(File cacheRoot, FileNameGenerator fileNameGenerator, DiskUsage diskUsage, SQLiteDatabase contentInfoDb) { this.cacheRoot = cacheRoot; this.fileNameGenerator = fileNameGenerator; this.diskUsage = diskUsage; + this.contentInfoDb = contentInfoDb; } File generateCacheFile(String url) { diff --git a/library/src/main/java/com/danikula/videocache/ContentInfoContract.java b/library/src/main/java/com/danikula/videocache/ContentInfoContract.java new file mode 100644 index 0000000..2d52150 --- /dev/null +++ b/library/src/main/java/com/danikula/videocache/ContentInfoContract.java @@ -0,0 +1,20 @@ +package com.danikula.videocache; + +import android.provider.BaseColumns; + +/** + * Defines the constants used by the {@link ContentInfoDbHelper). + * + * @author Gareth Blake Hall (gbhall.com). + */ +public final class ContentInfoContract { + + public ContentInfoContract() {} + + public static abstract class ContentInfoEntry implements BaseColumns { + public static final String TABLE_NAME = "ContentInfo"; + public static final String COLUMN_NAME_URL= "url"; + public static final String COLUMN_NAME_MIME = "mime"; + public static final String COLUMN_NAME_LENGTH = "length"; + } +} diff --git a/library/src/main/java/com/danikula/videocache/ContentInfoDbHelper.java b/library/src/main/java/com/danikula/videocache/ContentInfoDbHelper.java new file mode 100644 index 0000000..095126e --- /dev/null +++ b/library/src/main/java/com/danikula/videocache/ContentInfoDbHelper.java @@ -0,0 +1,46 @@ +package com.danikula.videocache; + +import com.danikula.videocache.ContentInfoContract.ContentInfoEntry; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +/** + * A {@link SQLiteOpenHelper) for managing the databases and tables related to caching content info + * into a {@link SQLiteDatabase). + * + * @author Gareth Blake Hall (gbhall.com). + */ +public class ContentInfoDbHelper extends SQLiteOpenHelper { + public static final int DATABASE_VERSION = 1; + public static final String DATABASE_NAME = "ContentInfo.db"; + + private static final String TEXT_TYPE = " TEXT"; + private static final String COMMA_SEP = ","; + private static final String SQL_CREATE_ENTRIES = + "CREATE TABLE " + ContentInfoEntry.TABLE_NAME + " (" + + ContentInfoEntry._ID + " INTEGER PRIMARY KEY," + + ContentInfoEntry.COLUMN_NAME_URL + TEXT_TYPE + COMMA_SEP + + ContentInfoEntry.COLUMN_NAME_MIME + TEXT_TYPE + COMMA_SEP + + ContentInfoEntry.COLUMN_NAME_LENGTH + TEXT_TYPE + + " )"; + + private static final String SQL_DELETE_ENTRIES = + "DROP TABLE IF EXISTS " + ContentInfoEntry.TABLE_NAME; + + public ContentInfoDbHelper(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + public void onCreate(SQLiteDatabase db) { + db.execSQL(SQL_CREATE_ENTRIES); + } + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + db.execSQL(SQL_DELETE_ENTRIES); + onCreate(db); + } + public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { + onUpgrade(db, oldVersion, newVersion); + } +} diff --git a/library/src/main/java/com/danikula/videocache/HttpProxyCache.java b/library/src/main/java/com/danikula/videocache/HttpProxyCache.java index 395fb06..dd8f20a 100644 --- a/library/src/main/java/com/danikula/videocache/HttpProxyCache.java +++ b/library/src/main/java/com/danikula/videocache/HttpProxyCache.java @@ -48,6 +48,10 @@ public void processRequest(GetRequest request, Socket socket) throws IOException } private boolean isUseCache(GetRequest request) throws ProxyCacheException { + if(cache.isCompleted()) { + return true; + } + int sourceLength = source.length(); boolean sourceLengthKnown = sourceLength > 0; int cacheAvailable = cache.available(); diff --git a/library/src/main/java/com/danikula/videocache/HttpProxyCacheServer.java b/library/src/main/java/com/danikula/videocache/HttpProxyCacheServer.java old mode 100644 new mode 100755 index c6027c1..049044a --- a/library/src/main/java/com/danikula/videocache/HttpProxyCacheServer.java +++ b/library/src/main/java/com/danikula/videocache/HttpProxyCacheServer.java @@ -1,22 +1,27 @@ package com.danikula.videocache; import android.content.Context; +import android.database.sqlite.SQLiteDatabase; import android.os.SystemClock; import android.util.Log; import com.danikula.videocache.file.DiskUsage; +import com.danikula.videocache.file.FileDeleteListener; import com.danikula.videocache.file.FileNameGenerator; import com.danikula.videocache.file.Md5FileNameGenerator; import com.danikula.videocache.file.TotalCountLruDiskUsage; import com.danikula.videocache.file.TotalSizeLruDiskUsage; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; +import java.net.URL; import java.util.Arrays; import java.util.Map; import java.util.concurrent.Callable; @@ -52,6 +57,7 @@ * * @author Alexey Danilov (danikula@gmail.com). */ +@SuppressWarnings("UnusedDeclaration") public class HttpProxyCacheServer { private static final String PROXY_HOST = "127.0.0.1"; @@ -142,6 +148,32 @@ private String appendToProxyUrl(String url) { return String.format("http://%s:%d/%s", PROXY_HOST, port, ProxyCacheUtils.encode(url)); } + /** + * Pre fetch the url into the cache. + * @param url The url to fetch + * @throws IOException + */ + public void fetch(String url) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + InputStream is = null; + try { + URL fetchUrl = new URL(getProxyUrl(url)); + is = fetchUrl.openStream(); + byte[] byteChunk = new byte[4096]; // Or whatever size you want to read in at a time. + int n; + + while ((n = is.read(byteChunk)) > 0) { + baos.write(byteChunk, 0, n); + } + } catch (Exception e) { + Log.d(LOG_TAG, String.format("Failed while reading bytes from %s: %s", url, e.getMessage())); + } finally { + if (is != null) { + is.close(); + } + } + } + public void registerCacheListener(CacheListener cacheListener, String url) { checkAllNotNull(cacheListener, url); synchronized (clientsLock) { @@ -345,16 +377,19 @@ public Boolean call() throws Exception { */ public static final class Builder { - private static final long DEFAULT_MAX_SIZE = 512 * 104 * 1024; + private static final long DEFAULT_MAX_SIZE = 512 * 1024 * 1024; private File cacheRoot; private FileNameGenerator fileNameGenerator; private DiskUsage diskUsage; + private FileDeleteListener fileDeleteListener; + private SQLiteDatabase contentInfoDb; public Builder(Context context) { this.cacheRoot = StorageUtils.getIndividualCacheDirectory(context); this.diskUsage = new TotalSizeLruDiskUsage(DEFAULT_MAX_SIZE); this.fileNameGenerator = new Md5FileNameGenerator(); + this.contentInfoDb = new ContentInfoDbHelper(context).getWritableDatabase(); } /** @@ -414,18 +449,32 @@ public Builder maxCacheFilesCount(int count) { return this; } + /** + * Listens to the files that being deleted from the cache by the LRU + * + * @param fileDeleteListener a listener for files that are deleted from cache + * @return a builder + */ + public Builder setFileDeleteListener(FileDeleteListener fileDeleteListener) { + this.fileDeleteListener = fileDeleteListener; + return this; + } + /** * Builds new instance of {@link HttpProxyCacheServer}. * * @return proxy cache. Only single instance should be used across whole app. */ public HttpProxyCacheServer build() { + if (fileDeleteListener != null) { + this.diskUsage.setFileDeleteListener(fileDeleteListener); + } Config config = buildConfig(); return new HttpProxyCacheServer(config); } private Config buildConfig() { - return new Config(cacheRoot, fileNameGenerator, diskUsage); + return new Config(cacheRoot, fileNameGenerator, diskUsage, contentInfoDb); } } diff --git a/library/src/main/java/com/danikula/videocache/HttpProxyCacheServerClients.java b/library/src/main/java/com/danikula/videocache/HttpProxyCacheServerClients.java index 8296d2a..9340edb 100644 --- a/library/src/main/java/com/danikula/videocache/HttpProxyCacheServerClients.java +++ b/library/src/main/java/com/danikula/videocache/HttpProxyCacheServerClients.java @@ -79,7 +79,7 @@ public int getClientsCount() { } private HttpProxyCache newHttpProxyCache() throws ProxyCacheException { - HttpUrlSource source = new HttpUrlSource(url); + HttpUrlSource source = new HttpUrlSource(url, config.contentInfoDb); FileCache cache = new FileCache(config.generateCacheFile(url), config.diskUsage); HttpProxyCache httpProxyCache = new HttpProxyCache(source, cache); httpProxyCache.registerCacheListener(uiCacheListener); diff --git a/library/src/main/java/com/danikula/videocache/HttpUrlSource.java b/library/src/main/java/com/danikula/videocache/HttpUrlSource.java old mode 100644 new mode 100755 index 60cf31f..5339db0 --- a/library/src/main/java/com/danikula/videocache/HttpUrlSource.java +++ b/library/src/main/java/com/danikula/videocache/HttpUrlSource.java @@ -1,8 +1,13 @@ package com.danikula.videocache; +import android.content.ContentValues; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; import android.text.TextUtils; import android.util.Log; +import com.danikula.videocache.ContentInfoContract.ContentInfoEntry; + import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; @@ -31,20 +36,27 @@ public class HttpUrlSource implements Source { private InputStream inputStream; private volatile int length = Integer.MIN_VALUE; private volatile String mime; + private SQLiteDatabase contentInfoDb; public HttpUrlSource(String url) { - this(url, ProxyCacheUtils.getSupposablyMime(url)); + this(url, ProxyCacheUtils.getSupposablyMime(url), null); + } + + public HttpUrlSource(String url, SQLiteDatabase contentInfoDb) { + this(url, ProxyCacheUtils.getSupposablyMime(url), contentInfoDb); } - public HttpUrlSource(String url, String mime) { + public HttpUrlSource(String url, String mime, SQLiteDatabase contentInfoDb) { this.url = Preconditions.checkNotNull(url); this.mime = mime; + this.contentInfoDb = contentInfoDb; } public HttpUrlSource(HttpUrlSource source) { this.url = source.url; this.mime = source.mime; this.length = source.length; + this.contentInfoDb = source.contentInfoDb; } @Override @@ -67,7 +79,8 @@ public void open(int offset) throws ProxyCacheException { } } - private int readSourceAvailableBytes(HttpURLConnection connection, int offset, int responseCode) throws IOException { + private int readSourceAvailableBytes(HttpURLConnection connection, + int offset, int responseCode) throws IOException { int contentLength = connection.getContentLength(); return responseCode == HTTP_OK ? contentLength : responseCode == HTTP_PARTIAL ? contentLength + offset : length; @@ -78,9 +91,11 @@ public void close() throws ProxyCacheException { if (connection != null) { try { connection.disconnect(); - } catch (NullPointerException e) { - // https://github.com/danikula/AndroidVideoCache/issues/32 + } catch (NullPointerException | ArrayIndexOutOfBoundsException + | IllegalArgumentException | IllegalStateException e) { // https://github.com/danikula/AndroidVideoCache/issues/29 + // https://github.com/danikula/AndroidVideoCache/issues/32 + // https://github.com/danikula/AndroidVideoCache/issues/50 throw new ProxyCacheException("Error disconnecting HttpUrlConnection", e); } } @@ -102,20 +117,55 @@ public int read(byte[] buffer) throws ProxyCacheException { private void fetchContentInfo() throws ProxyCacheException { Log.d(LOG_TAG, "Read content info from " + url); - HttpURLConnection urlConnection = null; - InputStream inputStream = null; - try { - urlConnection = openConnection(0, 10000); - length = urlConnection.getContentLength(); - mime = urlConnection.getContentType(); - inputStream = urlConnection.getInputStream(); - Log.i(LOG_TAG, "Content info for `" + url + "`: mime: " + mime + ", content-length: " + length); - } catch (IOException e) { - Log.e(LOG_TAG, "Error fetching info from " + url, e); - } finally { - ProxyCacheUtils.close(inputStream); - if (urlConnection != null) { - urlConnection.disconnect(); + + boolean fetchedViaSQLite = false; + + // Check via SQLite + if (contentInfoDb != null) { + // Query SQLite to see if it contains the content info locally + String selectQuery = "SELECT * FROM " + ContentInfoEntry.TABLE_NAME + " WHERE " + + ContentInfoEntry.COLUMN_NAME_URL + " = '" + url + "'"; + Cursor cursor = contentInfoDb.rawQuery(selectQuery, null); + + // SQLite contained the content info + if (cursor != null && cursor.getCount() > 0) { + cursor.moveToFirst(); + mime = cursor.getString(cursor.getColumnIndex(ContentInfoEntry.COLUMN_NAME_MIME)); + length = cursor.getInt(cursor.getColumnIndex(ContentInfoEntry.COLUMN_NAME_LENGTH)); + fetchedViaSQLite = true; + Log.i(LOG_TAG, "Read from SQLite: mime=" + mime + ", content-length=" + length); + cursor.close(); + } + } + + // Check via HttpURLConnection + if (!fetchedViaSQLite) { + HttpURLConnection urlConnection = null; + InputStream inputStream = null; + try { + urlConnection = openConnection(0, 10000); + length = urlConnection.getContentLength(); + mime = urlConnection.getContentType(); + inputStream = urlConnection.getInputStream(); + + // Write to SQLite + if (contentInfoDb != null) { + ContentValues values = new ContentValues(); + values.put(ContentInfoEntry.COLUMN_NAME_URL, url); + values.put(ContentInfoEntry.COLUMN_NAME_MIME, mime); + values.put(ContentInfoEntry.COLUMN_NAME_LENGTH, length); + contentInfoDb.insert(ContentInfoEntry.TABLE_NAME, null, values); + Log.i(LOG_TAG, "Wrote to SQLite: url=`" + url + "`, mime=" + mime + ", content-length=" + length); + } + + Log.i(LOG_TAG, "Content info for `" + url + "`: mime: " + mime + ", content-length: " + length); + } catch (IOException e) { + Log.e(LOG_TAG, "Error fetching info from " + url, e); + } finally { + ProxyCacheUtils.close(inputStream); + if (urlConnection != null) { + urlConnection.disconnect(); + } } } } diff --git a/library/src/main/java/com/danikula/videocache/Logger.java b/library/src/main/java/com/danikula/videocache/Logger.java new file mode 100644 index 0000000..07806c9 --- /dev/null +++ b/library/src/main/java/com/danikula/videocache/Logger.java @@ -0,0 +1,69 @@ +package com.danikula.videocache; + +import android.util.Log; + +/** + * Created by Dev1 on 30.03.2016. + */ +public final class Logger { + + private String mTag; + + private boolean mEnabled = false; + + public Logger(String tag) { + mTag = tag; + } + + public void d(String msg, Throwable e) { + log(Log.DEBUG, 'D', msg, e); + } + + public void v(String msg, Throwable e) { + log(Log.VERBOSE, 'V', msg, e); + } + + public void i(String msg, Throwable e) { + log(Log.INFO, 'I', msg, e); + } + + public void w(String msg, Throwable e) { + log(Log.WARN, 'W', msg, e); + } + + public void e(String msg, Throwable e) { + log(Log.ERROR, 'E', msg, e); + } + + public void d(String msg) { + log(Log.DEBUG, 'D', msg); + } + + public void v(String msg) { + log(Log.VERBOSE, 'V', msg); + } + + public void i(String msg) { + log(Log.INFO, 'I', msg); + } + + public void w(String msg) { + log(Log.WARN, 'W', msg); + } + + public void e(String msg) { + log(Log.ERROR, 'E', msg); + } + + private void log(int level, char levelShort, String msg, Throwable e) { + if (mEnabled || level > Log.INFO) { + Log.println(level, mTag, msg); + } + } + + private void log(int level, char levelShort, String msg) { + if (mEnabled || level > Log.INFO) { + Log.println(level, mTag, msg); + } + } +} diff --git a/library/src/main/java/com/danikula/videocache/ProxyCache.java b/library/src/main/java/com/danikula/videocache/ProxyCache.java old mode 100644 new mode 100755 index 8335b46..f824e2f --- a/library/src/main/java/com/danikula/videocache/ProxyCache.java +++ b/library/src/main/java/com/danikula/videocache/ProxyCache.java @@ -1,11 +1,8 @@ package com.danikula.videocache; -import android.util.Log; - import java.util.concurrent.atomic.AtomicInteger; import static com.danikula.videocache.Preconditions.checkNotNull; -import static com.danikula.videocache.ProxyCacheUtils.LOG_TAG; /** * Proxy for {@link Source} with caching support ({@link Cache}). @@ -20,6 +17,8 @@ class ProxyCache { private static final int MAX_READ_SOURCE_ATTEMPTS = 1; + private Logger mLogger = new Logger("ProxyCache"); + private final Source source; private final Cache cache; private final Object wc = new Object(); @@ -61,7 +60,7 @@ private void checkReadSourceErrorsCount() throws ProxyCacheException { public void shutdown() { synchronized (stopLock) { - Log.d(LOG_TAG, "Shutdown proxy for " + source); + mLogger.d("Shutdown proxy for " + source); try { stopped = true; if (sourceReaderThread != null) { @@ -75,7 +74,8 @@ public void shutdown() { } private synchronized void readSourceAsync() throws ProxyCacheException { - boolean readingInProgress = sourceReaderThread != null && sourceReaderThread.getState() != Thread.State.TERMINATED; + boolean readingInProgress = sourceReaderThread != null + && sourceReaderThread.getState() != Thread.State.TERMINATED; if (!stopped && !cache.isCompleted() && !readingInProgress) { sourceReaderThread = new Thread(new SourceReaderRunnable(), "Source reader for " + source); sourceReaderThread.start(); @@ -166,9 +166,9 @@ private void closeSource() { protected final void onError(final Throwable e) { boolean interruption = e instanceof InterruptedProxyCacheException; if (interruption) { - Log.d(LOG_TAG, "ProxyCache is interrupted"); + mLogger.d("ProxyCache is interrupted"); } else { - Log.e(LOG_TAG, "ProxyCache error", e); + mLogger.e("ProxyCache error", e); } } diff --git a/library/src/main/java/com/danikula/videocache/ProxyCacheUtils.java b/library/src/main/java/com/danikula/videocache/ProxyCacheUtils.java old mode 100644 new mode 100755 index 226fa79..9537608 --- a/library/src/main/java/com/danikula/videocache/ProxyCacheUtils.java +++ b/library/src/main/java/com/danikula/videocache/ProxyCacheUtils.java @@ -27,6 +27,8 @@ public class ProxyCacheUtils { static final int DEFAULT_BUFFER_SIZE = 8 * 1024; static final int MAX_ARRAY_PREVIEW = 16; + private static Logger sLogger = new Logger("ProxyCacheUtils"); + static String getSupposablyMime(String url) { MimeTypeMap mimes = MimeTypeMap.getSingleton(); String extension = MimeTypeMap.getFileExtensionFromUrl(url); @@ -70,7 +72,7 @@ static void close(Closeable closeable) { try { closeable.close(); } catch (IOException e) { - Log.e(LOG_TAG, "Error closing resource", e); + sLogger.e("Error closing resource", e); } } } diff --git a/library/src/main/java/com/danikula/videocache/StorageUtils.java b/library/src/main/java/com/danikula/videocache/StorageUtils.java old mode 100644 new mode 100755 index 3772f29..77e82f6 --- a/library/src/main/java/com/danikula/videocache/StorageUtils.java +++ b/library/src/main/java/com/danikula/videocache/StorageUtils.java @@ -2,7 +2,6 @@ import android.content.Context; import android.os.Environment; -import android.util.Log; import java.io.File; @@ -19,6 +18,8 @@ */ final class StorageUtils { + private static Logger sLogger = new Logger("StorageUtils"); + private static final String INDIVIDUAL_DIR_NAME = "video-cache"; /** @@ -61,7 +62,7 @@ private static File getCacheDirectory(Context context, boolean preferExternal) { } if (appCacheDir == null) { String cacheDirPath = "/data/data/" + context.getPackageName() + "/cache/"; - Log.w(LOG_TAG, "Can't define system cache directory! '" + cacheDirPath + "%s' will be used."); + sLogger.w("Can't define system cache directory! '" + cacheDirPath + "%s' will be used."); appCacheDir = new File(cacheDirPath); } return appCacheDir; @@ -72,7 +73,7 @@ private static File getExternalCacheDir(Context context) { File appCacheDir = new File(new File(dataDir, context.getPackageName()), "cache"); if (!appCacheDir.exists()) { if (!appCacheDir.mkdirs()) { - Log.w(LOG_TAG, "Unable to create external cache directory"); + sLogger.w("Unable to create external cache directory"); return null; } } diff --git a/library/src/main/java/com/danikula/videocache/file/DiskUsage.java b/library/src/main/java/com/danikula/videocache/file/DiskUsage.java index 1a43694..222f9f6 100644 --- a/library/src/main/java/com/danikula/videocache/file/DiskUsage.java +++ b/library/src/main/java/com/danikula/videocache/file/DiskUsage.java @@ -12,4 +12,6 @@ public interface DiskUsage { void touch(File file) throws IOException; + void setFileDeleteListener(FileDeleteListener fileDeleteListener); + } diff --git a/library/src/main/java/com/danikula/videocache/file/FileDeleteListener.java b/library/src/main/java/com/danikula/videocache/file/FileDeleteListener.java new file mode 100644 index 0000000..851bc70 --- /dev/null +++ b/library/src/main/java/com/danikula/videocache/file/FileDeleteListener.java @@ -0,0 +1,10 @@ +package com.danikula.videocache.file; + +/** + * Created by Bogdan Stanga on 2/12/2016. + */ +public interface FileDeleteListener { + + void onFileDeleted(String fileName); + +} diff --git a/library/src/main/java/com/danikula/videocache/file/LruDiskUsage.java b/library/src/main/java/com/danikula/videocache/file/LruDiskUsage.java index f8925f2..c048879 100644 --- a/library/src/main/java/com/danikula/videocache/file/LruDiskUsage.java +++ b/library/src/main/java/com/danikula/videocache/file/LruDiskUsage.java @@ -18,12 +18,18 @@ abstract class LruDiskUsage implements DiskUsage { private static final String LOG_TAG = "ProxyCache"; private final ExecutorService workerThread = Executors.newSingleThreadExecutor(); + private FileDeleteListener fileDeleteListener; @Override public void touch(File file) throws IOException { workerThread.submit(new TouchCallable(file)); } + @Override + public void setFileDeleteListener(FileDeleteListener fileDeleteListener) { + this.fileDeleteListener = fileDeleteListener; + } + private void touchInBackground(File file) throws IOException { Files.setLastModifiedNow(file); List files = Files.getLruListFiles(file.getParentFile()); @@ -43,6 +49,9 @@ private void trim(List files) { if (deleted) { totalCount--; totalSize -= fileSize; + if(fileDeleteListener != null){ + fileDeleteListener.onFileDeleted(file.getName()); + } Log.i(LOG_TAG, "Cache file " + file + " is deleted because it exceeds cache limit"); } else { Log.e(LOG_TAG, "Error deleting file " + file + " for trimming cache"); diff --git a/library/src/main/java/com/danikula/videocache/file/UnlimitedDiskUsage.java b/library/src/main/java/com/danikula/videocache/file/UnlimitedDiskUsage.java index 85ae66c..750228b 100644 --- a/library/src/main/java/com/danikula/videocache/file/UnlimitedDiskUsage.java +++ b/library/src/main/java/com/danikula/videocache/file/UnlimitedDiskUsage.java @@ -14,4 +14,9 @@ public class UnlimitedDiskUsage implements DiskUsage { public void touch(File file) throws IOException { // do nothing } + + @Override + public void setFileDeleteListener(FileDeleteListener fileDeleteListener) { + // do nothing + } } diff --git a/sample/build.gradle b/sample/build.gradle index e15fbad..3b61f48 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -35,7 +35,7 @@ apt { } dependencies { -// compile project(':library') + //compile project(':library') compile 'com.android.support:support-v4:23.1.0' compile 'org.androidannotations:androidannotations-api:3.3.2' compile 'com.danikula:videocache:2.3.3' diff --git a/sample/src/main/java/com/danikula/videocache/sample/MenuActivity.java b/sample/src/main/java/com/danikula/videocache/sample/MenuActivity.java old mode 100644 new mode 100755 index c269f0e..b5aae49 --- a/sample/src/main/java/com/danikula/videocache/sample/MenuActivity.java +++ b/sample/src/main/java/com/danikula/videocache/sample/MenuActivity.java @@ -51,7 +51,7 @@ void onClearCacheButtonClick() { try { Utils.cleanDirectory(getExternalCacheDir()); } catch (IOException e) { - Log.e(null, "Error cleaning cache", e); + mLogger.e(null, "Error cleaning cache", e); Toast.makeText(this, "Error cleaning cache", Toast.LENGTH_LONG).show(); } } diff --git a/sample/src/main/java/com/danikula/videocache/sample/VideoFragment.java b/sample/src/main/java/com/danikula/videocache/sample/VideoFragment.java old mode 100644 new mode 100755 index b11707a..df4a697 --- a/sample/src/main/java/com/danikula/videocache/sample/VideoFragment.java +++ b/sample/src/main/java/com/danikula/videocache/sample/VideoFragment.java @@ -78,7 +78,7 @@ public void onDestroy() { @Override public void onCacheAvailable(File file, String url, int percentsAvailable) { progressBar.setSecondaryProgress(percentsAvailable); - Log.d(LOG_TAG, String.format("onCacheAvailable. percents: %d, file: %s, url: %s", percentsAvailable, file, url)); + mLogger.d(LOG_TAG, String.format("onCacheAvailable. percents: %d, file: %s, url: %s", percentsAvailable, file, url)); } private void updateVideoProgress() { diff --git a/test/build.gradle b/test/build.gradle index f5a4aa3..bebf983 100644 --- a/test/build.gradle +++ b/test/build.gradle @@ -5,13 +5,13 @@ repositories { apply plugin: 'com.android.application' android { - compileSdkVersion 22 - buildToolsVersion '22.0.1' + compileSdkVersion 23 + buildToolsVersion '23.0.2' defaultConfig { applicationId 'com.danikula.proxycache.test' minSdkVersion 16 - targetSdkVersion 22 + targetSdkVersion 23 versionCode 1 versionName '0.1' }