ability to check was content fully cached to file or not
19
README.md
@@ -14,14 +14,14 @@ Because there is no sense to download video a lot of times while streaming!
|
||||
|
||||
Note `AndroidVideoCache` works only with **direct urls** to media file, it [**doesn't support**](https://github.com/danikula/AndroidVideoCache/issues/19) any streaming technology like DASH, SmoothStreaming, HLS.
|
||||
|
||||
## How to use?
|
||||
## Get started
|
||||
Just add dependency (`AndroidVideoCache` is available in jcenter):
|
||||
```
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
compile 'com.danikula:videocache:2.3.4'
|
||||
compile 'com.danikula:videocache:2.4.0'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -64,7 +64,8 @@ public class App extends Application {
|
||||
or use [simple factory](http://pastebin.com/s2fafSYS).
|
||||
More preferable way is use some dependency injector like [Dagger](http://square.github.io/dagger/).
|
||||
|
||||
## Configuration
|
||||
## Recipes
|
||||
### Disk cache limit
|
||||
By default `HttpProxyCacheServer` uses 512Mb for caching files. You can change this value:
|
||||
|
||||
```java
|
||||
@@ -83,9 +84,17 @@ private HttpProxyCacheServer newProxy() {
|
||||
.maxCacheFilesCount(20)
|
||||
.build();
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
See `sample` app for details.
|
||||
### Listen caching progress
|
||||
Use `HttpProxyCacheServer.registerCacheListener(CacheListener listener)` method to set listener with callback `onCacheAvailable(File cacheFile, String url, int percentsAvailable)` to be aware of caching progress. Do not forget to to unsubscribe listener with help of `HttpProxyCacheServer.unregisterCacheListener(CacheListener listener)` method to avoid memory leaks.
|
||||
|
||||
Use `HttpProxyCacheServer.isCached(String url)` method to check was url's content fully cached to file or not.
|
||||
|
||||
See `sample` app for more details.
|
||||
|
||||
### Sample
|
||||
See `sample` app.
|
||||
|
||||
## Whats new
|
||||
See Release Notes [here](https://github.com/danikula/AndroidVideoCache/releases)
|
||||
|
||||
@@ -29,7 +29,7 @@ publish {
|
||||
userOrg = 'alexeydanilov'
|
||||
groupId = 'com.danikula'
|
||||
artifactId = 'videocache'
|
||||
publishVersion = '2.3.4'
|
||||
publishVersion = '2.4.0'
|
||||
description = 'Cache support for android VideoView'
|
||||
website = 'https://github.com/danikula/AndroidVideoCache'
|
||||
}
|
||||
|
||||
@@ -173,6 +173,20 @@ public class HttpProxyCacheServer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks is cache contains fully cached file for particular url.
|
||||
*
|
||||
* @param url an url cache file will be checked for.
|
||||
* @return {@code true} if cache contains fully cached file for passed in parameters url.
|
||||
*/
|
||||
public boolean isCached(String url) {
|
||||
checkNotNull(url, "Url can't be null!");
|
||||
File cacheDir = config.cacheRoot;
|
||||
String fileName = config.fileNameGenerator.generate(url);
|
||||
File cacheFile = new File(cacheDir, fileName);
|
||||
return cacheFile.exists();
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
Log.i(LOG_TAG, "Shutdown proxy server");
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ android {
|
||||
buildToolsVersion '24'
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.danikula.videocache.sample"
|
||||
applicationId 'com.danikula.videocache.sample'
|
||||
minSdkVersion 15
|
||||
targetSdkVersion 23
|
||||
versionCode 1
|
||||
@@ -38,7 +38,7 @@ dependencies {
|
||||
// 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'
|
||||
compile 'com.danikula:videocache:2.4.0'
|
||||
compile 'com.viewpagerindicator:library:2.4.2-SNAPSHOT@aar'
|
||||
apt 'org.androidannotations:androidannotations:3.3.2'
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.util.Log;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.VideoView;
|
||||
|
||||
@@ -27,6 +28,7 @@ public class VideoFragment extends Fragment implements CacheListener {
|
||||
@FragmentArg String url;
|
||||
@FragmentArg String cachePath;
|
||||
|
||||
@ViewById ImageView cacheStatusImageView;
|
||||
@ViewById VideoView videoView;
|
||||
@ViewById ProgressBar progressBar;
|
||||
|
||||
@@ -45,9 +47,16 @@ public class VideoFragment extends Fragment implements CacheListener {
|
||||
|
||||
@AfterViews
|
||||
void afterViewInjected() {
|
||||
checkCachedState();
|
||||
startVideo();
|
||||
}
|
||||
|
||||
private void checkCachedState() {
|
||||
HttpProxyCacheServer proxy = App.getProxy(getActivity());
|
||||
boolean fullyCached = proxy.isCached(url);
|
||||
setCachedState(fullyCached);
|
||||
}
|
||||
|
||||
private void startVideo() {
|
||||
HttpProxyCacheServer proxy = App.getProxy(getActivity());
|
||||
proxy.registerCacheListener(this, url);
|
||||
@@ -78,6 +87,7 @@ public class VideoFragment extends Fragment implements CacheListener {
|
||||
@Override
|
||||
public void onCacheAvailable(File file, String url, int percentsAvailable) {
|
||||
progressBar.setSecondaryProgress(percentsAvailable);
|
||||
setCachedState(percentsAvailable == 100);
|
||||
Log.d(LOG_TAG, String.format("onCacheAvailable. percents: %d, file: %s, url: %s", percentsAvailable, file, url));
|
||||
}
|
||||
|
||||
@@ -92,6 +102,11 @@ public class VideoFragment extends Fragment implements CacheListener {
|
||||
videoView.seekTo(videoPosition);
|
||||
}
|
||||
|
||||
private void setCachedState(boolean cached) {
|
||||
int statusIconId = cached ? R.drawable.ic_cloud_done : R.drawable.ic_cloud_download;
|
||||
cacheStatusImageView.setImageResource(statusIconId);
|
||||
}
|
||||
|
||||
private final class VideoProgressUpdater extends Handler {
|
||||
|
||||
public void start() {
|
||||
|
||||
BIN
sample/src/main/res/drawable-hdpi/ic_cloud_done.png
Normal file
|
After Width: | Height: | Size: 379 B |
BIN
sample/src/main/res/drawable-hdpi/ic_cloud_download.png
Normal file
|
After Width: | Height: | Size: 353 B |
BIN
sample/src/main/res/drawable-mdpi/ic_cloud_done.png
Normal file
|
After Width: | Height: | Size: 265 B |
BIN
sample/src/main/res/drawable-mdpi/ic_cloud_download.png
Normal file
|
After Width: | Height: | Size: 242 B |
BIN
sample/src/main/res/drawable-xhdpi/ic_cloud_done.png
Normal file
|
After Width: | Height: | Size: 449 B |
BIN
sample/src/main/res/drawable-xhdpi/ic_cloud_download.png
Normal file
|
After Width: | Height: | Size: 417 B |
BIN
sample/src/main/res/drawable-xxhdpi/ic_cloud_done.png
Normal file
|
After Width: | Height: | Size: 672 B |
BIN
sample/src/main/res/drawable-xxhdpi/ic_cloud_download.png
Normal file
|
After Width: | Height: | Size: 610 B |
BIN
sample/src/main/res/drawable-xxxhdpi/ic_cloud_done.png
Normal file
|
After Width: | Height: | Size: 855 B |
BIN
sample/src/main/res/drawable-xxxhdpi/ic_cloud_download.png
Normal file
|
After Width: | Height: | Size: 789 B |
@@ -10,6 +10,13 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/cacheStatusImageView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:src="@drawable/ic_cloud_download" />
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/progressBar"
|
||||
style="@android:style/Widget.Holo.ProgressBar.Horizontal"
|
||||
|
||||
@@ -210,6 +210,52 @@ public class HttpProxyCacheServerTest {
|
||||
assertThat(file(cacheFolder, HTTP_DATA_URL_6_REDIRECTS)).exists();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckFileExistForNotCachedUrl() throws Exception {
|
||||
HttpProxyCacheServer proxy = newProxy(cacheFolder);
|
||||
proxy.shutdown();
|
||||
assertThat(proxy.isCached(HTTP_DATA_URL)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckFileExistForFullyCachedUrl() throws Exception {
|
||||
HttpProxyCacheServer proxy = newProxy(cacheFolder);
|
||||
readProxyResponse(proxy, HTTP_DATA_URL, 0);
|
||||
proxy.shutdown();
|
||||
|
||||
assertThat(proxy.isCached(HTTP_DATA_URL)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckFileExistForPartiallyCachedUrl() throws Exception {
|
||||
File cacheDir = RuntimeEnvironment.application.getExternalCacheDir();
|
||||
File file = file(cacheDir, HTTP_DATA_URL);
|
||||
int partialCacheSize = 1000;
|
||||
byte[] partialData = ProxyCacheTestUtils.generate(partialCacheSize);
|
||||
File partialCacheFile = ProxyCacheTestUtils.getTempFile(file);
|
||||
IoUtils.saveToFile(partialData, partialCacheFile);
|
||||
|
||||
HttpProxyCacheServer proxy = newProxy(cacheDir);
|
||||
assertThat(proxy.isCached(HTTP_DATA_URL)).isFalse();
|
||||
|
||||
readProxyResponse(proxy, HTTP_DATA_URL);
|
||||
proxy.shutdown();
|
||||
|
||||
assertThat(proxy.isCached(HTTP_DATA_URL)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckFileExistForDeletedCacheFile() throws Exception {
|
||||
HttpProxyCacheServer proxy = newProxy(cacheFolder);
|
||||
readProxyResponse(proxy, HTTP_DATA_URL, 0);
|
||||
proxy.shutdown();
|
||||
File cacheFile = file(cacheFolder, HTTP_DATA_URL);
|
||||
boolean deleted = cacheFile.delete();
|
||||
|
||||
assertThat(deleted).isTrue();
|
||||
assertThat(proxy.isCached(HTTP_DATA_URL)).isFalse();
|
||||
}
|
||||
|
||||
private Pair<File, Response> readProxyData(String url, int offset) throws IOException {
|
||||
File file = file(cacheFolder, url);
|
||||
HttpProxyCacheServer proxy = newProxy(cacheFolder);
|
||||
|
||||