mirror of
https://github.com/zhigang1992/AndroidVideoCache.git
synced 2026-06-15 18:07:51 +08:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
079bb4db6f | ||
|
|
acdf747a99 | ||
|
|
89ab5937c6 |
26
README.md
26
README.md
@@ -9,6 +9,8 @@
|
||||
- [Disk cache limit](#disk-cache-limit)
|
||||
- [Listen caching progress](#listen-caching-progress)
|
||||
- [Providing names for cached files](#providing-names-for-cached-files)
|
||||
- [Adding custom http headers](#adding-custom-http-headers)
|
||||
- [Using exoPlayer](#using-exoplayer)
|
||||
- [Sample](#sample)
|
||||
- [Known problems](#known-problems)
|
||||
- [Whats new](#whats-new)
|
||||
@@ -19,7 +21,7 @@
|
||||
|
||||
## Why AndroidVideoCache?
|
||||
Because there is no sense to download video a lot of times while streaming!
|
||||
`AndroidVideoCache` allows to add caching support to your `VideoView/MediaPlayer`, [ExoPlayer](https://github.com/danikula/ExoPlayer/commit/6110be8559f003f98020ada8c5e09691b67aaff4) or any another player with help of single line!
|
||||
`AndroidVideoCache` allows to add caching support to your `VideoView/MediaPlayer`, [ExoPlayer](https://github.com/danikula/AndroidVideoCache/tree/exoPlayer) or any another player with help of single line!
|
||||
|
||||
## Features
|
||||
- caching to disk during streaming;
|
||||
@@ -136,6 +138,28 @@ HttpProxyCacheServer proxy = HttpProxyCacheServer.Builder(context)
|
||||
.build()
|
||||
```
|
||||
|
||||
### Adding custom http headers
|
||||
You can add custom headers to requests with help of `HeadersInjector`:
|
||||
``` java
|
||||
public class UserAgentHeadersInjector implements HeaderInjector {
|
||||
|
||||
@Override
|
||||
public Map<String, String> addHeaders(String url) {
|
||||
return Maps.newHashMap("User-Agent", "Cool app v1.1");
|
||||
}
|
||||
}
|
||||
|
||||
private HttpProxyCacheServer newProxy() {
|
||||
return new HttpProxyCacheServer.Builder(this)
|
||||
.headerInjector(new UserAgentHeadersInjector())
|
||||
.build();
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Using exoPlayer
|
||||
You can use [`exoPlayer`](https://google.github.io/ExoPlayer/) with `AndroidVideoCache`. See `sample` app in [`exoPlayer`](https://github.com/danikula/AndroidVideoCache/tree/exoPlayer) branch. Note [exoPlayer supports](https://github.com/google/ExoPlayer/commit/bd7be1b5e7cc41a59ebbc348d394820fc857db92) cache as well.
|
||||
|
||||
### Sample
|
||||
See `sample` app.
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.danikula.videocache;
|
||||
|
||||
import com.danikula.videocache.file.DiskUsage;
|
||||
import com.danikula.videocache.file.FileNameGenerator;
|
||||
import com.danikula.videocache.headers.HeaderInjector;
|
||||
import com.danikula.videocache.sourcestorage.SourceInfoStorage;
|
||||
|
||||
import java.io.File;
|
||||
@@ -17,12 +18,14 @@ class Config {
|
||||
public final FileNameGenerator fileNameGenerator;
|
||||
public final DiskUsage diskUsage;
|
||||
public final SourceInfoStorage sourceInfoStorage;
|
||||
public final HeaderInjector headerInjector;
|
||||
|
||||
Config(File cacheRoot, FileNameGenerator fileNameGenerator, DiskUsage diskUsage, SourceInfoStorage sourceInfoStorage) {
|
||||
Config(File cacheRoot, FileNameGenerator fileNameGenerator, DiskUsage diskUsage, SourceInfoStorage sourceInfoStorage, HeaderInjector headerInjector) {
|
||||
this.cacheRoot = cacheRoot;
|
||||
this.fileNameGenerator = fileNameGenerator;
|
||||
this.diskUsage = diskUsage;
|
||||
this.sourceInfoStorage = sourceInfoStorage;
|
||||
this.headerInjector = headerInjector;
|
||||
}
|
||||
|
||||
File generateCacheFile(String url) {
|
||||
|
||||
@@ -8,6 +8,8 @@ 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 com.danikula.videocache.headers.EmptyHeadersInjector;
|
||||
import com.danikula.videocache.headers.HeaderInjector;
|
||||
import com.danikula.videocache.sourcestorage.SourceInfoStorage;
|
||||
import com.danikula.videocache.sourcestorage.SourceInfoStorageFactory;
|
||||
|
||||
@@ -350,12 +352,14 @@ public class HttpProxyCacheServer {
|
||||
private FileNameGenerator fileNameGenerator;
|
||||
private DiskUsage diskUsage;
|
||||
private SourceInfoStorage sourceInfoStorage;
|
||||
private HeaderInjector headerInjector;
|
||||
|
||||
public Builder(Context context) {
|
||||
this.sourceInfoStorage = SourceInfoStorageFactory.newSourceInfoStorage(context);
|
||||
this.cacheRoot = StorageUtils.getIndividualCacheDirectory(context);
|
||||
this.diskUsage = new TotalSizeLruDiskUsage(DEFAULT_MAX_SIZE);
|
||||
this.fileNameGenerator = new Md5FileNameGenerator();
|
||||
this.headerInjector = new EmptyHeadersInjector();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -426,6 +430,17 @@ public class HttpProxyCacheServer {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add headers along the request to the server
|
||||
*
|
||||
* @param headerInjector to inject header base on url
|
||||
* @return a builder
|
||||
*/
|
||||
public Builder headerInjector(HeaderInjector headerInjector) {
|
||||
this.headerInjector = checkNotNull(headerInjector);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds new instance of {@link HttpProxyCacheServer}.
|
||||
*
|
||||
@@ -437,7 +452,7 @@ public class HttpProxyCacheServer {
|
||||
}
|
||||
|
||||
private Config buildConfig() {
|
||||
return new Config(cacheRoot, fileNameGenerator, diskUsage, sourceInfoStorage);
|
||||
return new Config(cacheRoot, fileNameGenerator, diskUsage, sourceInfoStorage, headerInjector);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ final class HttpProxyCacheServerClients {
|
||||
}
|
||||
|
||||
private HttpProxyCache newHttpProxyCache() throws ProxyCacheException {
|
||||
HttpUrlSource source = new HttpUrlSource(url, config.sourceInfoStorage);
|
||||
HttpUrlSource source = new HttpUrlSource(url, config.sourceInfoStorage, config.headerInjector);
|
||||
FileCache cache = new FileCache(config.generateCacheFile(url), config.diskUsage);
|
||||
HttpProxyCache httpProxyCache = new HttpProxyCache(source, cache);
|
||||
httpProxyCache.registerCacheListener(uiCacheListener);
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.danikula.videocache;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.danikula.videocache.headers.EmptyHeadersInjector;
|
||||
import com.danikula.videocache.headers.HeaderInjector;
|
||||
import com.danikula.videocache.sourcestorage.SourceInfoStorage;
|
||||
import com.danikula.videocache.sourcestorage.SourceInfoStorageFactory;
|
||||
|
||||
@@ -14,6 +16,7 @@ import java.io.InputStream;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.danikula.videocache.Preconditions.checkNotNull;
|
||||
import static com.danikula.videocache.ProxyCacheUtils.DEFAULT_BUFFER_SIZE;
|
||||
@@ -34,6 +37,7 @@ public class HttpUrlSource implements Source {
|
||||
|
||||
private static final int MAX_REDIRECTS = 5;
|
||||
private final SourceInfoStorage sourceInfoStorage;
|
||||
private final HeaderInjector headerInjector;
|
||||
private SourceInfo sourceInfo;
|
||||
private HttpURLConnection connection;
|
||||
private InputStream inputStream;
|
||||
@@ -43,7 +47,12 @@ public class HttpUrlSource implements Source {
|
||||
}
|
||||
|
||||
public HttpUrlSource(String url, SourceInfoStorage sourceInfoStorage) {
|
||||
this(url, sourceInfoStorage, new EmptyHeadersInjector());
|
||||
}
|
||||
|
||||
public HttpUrlSource(String url, SourceInfoStorage sourceInfoStorage, HeaderInjector headerInjector) {
|
||||
this.sourceInfoStorage = checkNotNull(sourceInfoStorage);
|
||||
this.headerInjector = checkNotNull(headerInjector);
|
||||
SourceInfo sourceInfo = sourceInfoStorage.get(url);
|
||||
this.sourceInfo = sourceInfo != null ? sourceInfo :
|
||||
new SourceInfo(url, Integer.MIN_VALUE, ProxyCacheUtils.getSupposablyMime(url));
|
||||
@@ -52,6 +61,7 @@ public class HttpUrlSource implements Source {
|
||||
public HttpUrlSource(HttpUrlSource source) {
|
||||
this.sourceInfo = source.sourceInfo;
|
||||
this.sourceInfoStorage = source.sourceInfoStorage;
|
||||
this.headerInjector = source.headerInjector;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -150,6 +160,7 @@ public class HttpUrlSource implements Source {
|
||||
do {
|
||||
LOG.debug("Open connection " + (offset > 0 ? " with offset " + offset : "") + " to " + url);
|
||||
connection = (HttpURLConnection) new URL(url).openConnection();
|
||||
injectCustomHeaders(connection, url);
|
||||
if (offset > 0) {
|
||||
connection.setRequestProperty("Range", "bytes=" + offset + "-");
|
||||
}
|
||||
@@ -171,6 +182,13 @@ public class HttpUrlSource implements Source {
|
||||
return connection;
|
||||
}
|
||||
|
||||
private void injectCustomHeaders(HttpURLConnection connection, String url) {
|
||||
Map<String, String> extraHeaders = headerInjector.addHeaders(url);
|
||||
for (Map.Entry<String, String> header : extraHeaders.entrySet()) {
|
||||
connection.setRequestProperty(header.getKey(), header.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized String getMime() throws ProxyCacheException {
|
||||
if (TextUtils.isEmpty(sourceInfo.mime)) {
|
||||
fetchContentInfo();
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.danikula.videocache.headers;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Empty {@link HeaderInjector} implementation.
|
||||
*
|
||||
* @author Lucas Nelaupe (https://github.com/lucas34).
|
||||
*/
|
||||
public class EmptyHeadersInjector implements HeaderInjector {
|
||||
|
||||
@Override
|
||||
public Map<String, String> addHeaders(String url) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.danikula.videocache.headers;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Allows to add custom headers to server's requests.
|
||||
*
|
||||
* @author Lucas Nelaupe (https://github.com/lucas34).
|
||||
*/
|
||||
public interface HeaderInjector {
|
||||
|
||||
/**
|
||||
* Adds headers to server's requests for corresponding url.
|
||||
*
|
||||
* @param url an url headers will be added for
|
||||
* @return a map with headers, where keys are header's names, and values are header's values. {@code null} is not acceptable!
|
||||
*/
|
||||
Map<String, String> addHeaders(String url);
|
||||
|
||||
}
|
||||
@@ -36,6 +36,7 @@ apt {
|
||||
|
||||
dependencies {
|
||||
// compile project(':library')
|
||||
compile 'com.google.android.exoplayer:exoplayer:r2.3.1'
|
||||
compile 'com.android.support:support-v4:23.1.0'
|
||||
compile 'org.androidannotations:androidannotations-api:3.3.2'
|
||||
compile 'com.danikula:videocache:2.7.0'
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
</activity>
|
||||
<activity android:name=".SingleVideoActivity_" />
|
||||
<activity android:name=".MultipleVideosActivity_" />
|
||||
<activity android:name=".VideoGalleryActivity_" />
|
||||
<activity android:name=".SharedCacheActivity_" />
|
||||
</application>
|
||||
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
package com.danikula.videocache.sample;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.VideoView;
|
||||
|
||||
import com.danikula.videocache.CacheListener;
|
||||
import com.danikula.videocache.HttpProxyCacheServer;
|
||||
|
||||
import org.androidannotations.annotations.AfterViews;
|
||||
import org.androidannotations.annotations.EFragment;
|
||||
import org.androidannotations.annotations.FragmentArg;
|
||||
import org.androidannotations.annotations.InstanceState;
|
||||
import org.androidannotations.annotations.SeekBarTouchStop;
|
||||
import org.androidannotations.annotations.ViewById;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@EFragment(R.layout.fragment_video)
|
||||
public class GalleryVideoFragment extends Fragment implements CacheListener {
|
||||
|
||||
@FragmentArg String url;
|
||||
|
||||
@InstanceState int position;
|
||||
@InstanceState boolean playerStarted;
|
||||
|
||||
@ViewById VideoView videoView;
|
||||
@ViewById ProgressBar progressBar;
|
||||
|
||||
private boolean visibleForUser;
|
||||
|
||||
private final VideoProgressUpdater updater = new VideoProgressUpdater();
|
||||
|
||||
public static Fragment build(String url) {
|
||||
return GalleryVideoFragment_.builder()
|
||||
.url(url)
|
||||
.build();
|
||||
}
|
||||
|
||||
@AfterViews
|
||||
void afterViewInjected() {
|
||||
startProxy();
|
||||
|
||||
if (visibleForUser) {
|
||||
startPlayer();
|
||||
}
|
||||
}
|
||||
|
||||
private void startPlayer() {
|
||||
videoView.seekTo(position);
|
||||
videoView.start();
|
||||
playerStarted = true;
|
||||
}
|
||||
|
||||
private void startProxy() {
|
||||
HttpProxyCacheServer proxy = App.getProxy(getActivity());
|
||||
proxy.registerCacheListener(this, url);
|
||||
videoView.setVideoPath(proxy.getProxyUrl(url));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUserVisibleHint(boolean isVisibleToUser) {
|
||||
super.setUserVisibleHint(isVisibleToUser);
|
||||
|
||||
visibleForUser = isVisibleToUser;
|
||||
if (videoView != null) {
|
||||
if (visibleForUser) {
|
||||
startPlayer();
|
||||
} else if (playerStarted) {
|
||||
position = videoView.getCurrentPosition();
|
||||
videoView.pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
updater.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
updater.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
videoView.stopPlayback();
|
||||
App.getProxy(getActivity()).unregisterCacheListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCacheAvailable(File file, String url, int percentsAvailable) {
|
||||
progressBar.setSecondaryProgress(percentsAvailable);
|
||||
}
|
||||
|
||||
private void updateVideoProgress() {
|
||||
int videoProgress = videoView.getCurrentPosition() * 100 / videoView.getDuration();
|
||||
progressBar.setProgress(videoProgress);
|
||||
}
|
||||
|
||||
@SeekBarTouchStop(R.id.progressBar)
|
||||
void seekVideo() {
|
||||
int videoPosition = videoView.getDuration() * progressBar.getProgress() / 100;
|
||||
videoView.seekTo(videoPosition);
|
||||
}
|
||||
|
||||
private final class VideoProgressUpdater extends Handler {
|
||||
|
||||
public void start() {
|
||||
sendEmptyMessage(0);
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
removeMessages(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
updateVideoProgress();
|
||||
sendEmptyMessageDelayed(0, 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,6 @@ public class MenuActivity extends FragmentActivity {
|
||||
return Arrays.asList(
|
||||
new ListEntry("Single Video", SingleVideoActivity_.class),
|
||||
new ListEntry("Multiple Videos", MultipleVideosActivity_.class),
|
||||
new ListEntry("Video Gallery with pre-caching", VideoGalleryActivity_.class),
|
||||
new ListEntry("Shared Cache", SharedCacheActivity_.class)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,15 +1,33 @@
|
||||
package com.danikula.videocache.sample;
|
||||
|
||||
import android.net.Uri;
|
||||
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;
|
||||
|
||||
import com.danikula.videocache.CacheListener;
|
||||
import com.danikula.videocache.HttpProxyCacheServer;
|
||||
import com.google.android.exoplayer2.DefaultLoadControl;
|
||||
import com.google.android.exoplayer2.ExoPlayerFactory;
|
||||
import com.google.android.exoplayer2.LoadControl;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
|
||||
import com.google.android.exoplayer2.extractor.ExtractorsFactory;
|
||||
import com.google.android.exoplayer2.source.ExtractorMediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
|
||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelector;
|
||||
import com.google.android.exoplayer2.ui.SimpleExoPlayerView;
|
||||
import com.google.android.exoplayer2.upstream.BandwidthMeter;
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
|
||||
import org.androidannotations.annotations.AfterViews;
|
||||
import org.androidannotations.annotations.EFragment;
|
||||
@@ -27,8 +45,9 @@ public class VideoFragment extends Fragment implements CacheListener {
|
||||
@FragmentArg String url;
|
||||
|
||||
@ViewById ImageView cacheStatusImageView;
|
||||
@ViewById VideoView videoView;
|
||||
@ViewById SimpleExoPlayerView simpleExoPlayerView;
|
||||
@ViewById ProgressBar progressBar;
|
||||
private SimpleExoPlayer simpleExoPlayer;
|
||||
|
||||
private final VideoProgressUpdater updater = new VideoProgressUpdater();
|
||||
|
||||
@@ -41,7 +60,8 @@ public class VideoFragment extends Fragment implements CacheListener {
|
||||
@AfterViews
|
||||
void afterViewInjected() {
|
||||
checkCachedState();
|
||||
startVideo();
|
||||
simpleExoPlayer = setupPlayer();
|
||||
simpleExoPlayer.setPlayWhenReady(true);
|
||||
}
|
||||
|
||||
private void checkCachedState() {
|
||||
@@ -53,32 +73,57 @@ public class VideoFragment extends Fragment implements CacheListener {
|
||||
}
|
||||
}
|
||||
|
||||
private void startVideo() {
|
||||
private SimpleExoPlayer setupPlayer() {
|
||||
simpleExoPlayerView.setUseController(false);
|
||||
HttpProxyCacheServer proxy = App.getProxy(getActivity());
|
||||
proxy.registerCacheListener(this, url);
|
||||
String proxyUrl = proxy.getProxyUrl(url);
|
||||
Log.d(LOG_TAG, "Use proxy url " + proxyUrl + " instead of original url " + url);
|
||||
videoView.setVideoPath(proxyUrl);
|
||||
videoView.start();
|
||||
|
||||
SimpleExoPlayer exoPlayer = newSimpleExoPlayer();
|
||||
simpleExoPlayerView.setPlayer(exoPlayer);
|
||||
|
||||
MediaSource videoSource = newVideoSource(proxyUrl);
|
||||
exoPlayer.prepare(videoSource);
|
||||
|
||||
return exoPlayer;
|
||||
}
|
||||
|
||||
private SimpleExoPlayer newSimpleExoPlayer() {
|
||||
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
|
||||
TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
|
||||
TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
|
||||
LoadControl loadControl = new DefaultLoadControl();
|
||||
return ExoPlayerFactory.newSimpleInstance(getActivity(), trackSelector, loadControl);
|
||||
}
|
||||
|
||||
private MediaSource newVideoSource(String url) {
|
||||
DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
|
||||
String userAgent = Util.getUserAgent(getActivity(), "AndroidVideoCache sample");
|
||||
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(getActivity(), userAgent, bandwidthMeter);
|
||||
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
|
||||
return new ExtractorMediaSource(Uri.parse(url), dataSourceFactory, extractorsFactory, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
updater.start();
|
||||
simpleExoPlayer.setPlayWhenReady(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
updater.stop();
|
||||
simpleExoPlayer.setPlayWhenReady(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
videoView.stopPlayback();
|
||||
simpleExoPlayer.release();
|
||||
App.getProxy(getActivity()).unregisterCacheListener(this);
|
||||
}
|
||||
|
||||
@@ -90,14 +135,14 @@ public class VideoFragment extends Fragment implements CacheListener {
|
||||
}
|
||||
|
||||
private void updateVideoProgress() {
|
||||
int videoProgress = videoView.getCurrentPosition() * 100 / videoView.getDuration();
|
||||
progressBar.setProgress(videoProgress);
|
||||
long videoProgress = simpleExoPlayer.getCurrentPosition() * 100 / simpleExoPlayer.getDuration();
|
||||
progressBar.setProgress((int) videoProgress);
|
||||
}
|
||||
|
||||
@SeekBarTouchStop(R.id.progressBar)
|
||||
void seekVideo() {
|
||||
int videoPosition = videoView.getDuration() * progressBar.getProgress() / 100;
|
||||
videoView.seekTo(videoPosition);
|
||||
long videoPosition = simpleExoPlayer.getDuration() * progressBar.getProgress() / 100;
|
||||
simpleExoPlayer.seekTo(videoPosition);
|
||||
}
|
||||
|
||||
private void setCachedState(boolean cached) {
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
package com.danikula.videocache.sample;
|
||||
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.support.v4.app.FragmentStatePagerAdapter;
|
||||
import android.support.v4.view.ViewPager;
|
||||
|
||||
import com.viewpagerindicator.CirclePageIndicator;
|
||||
|
||||
import org.androidannotations.annotations.AfterViews;
|
||||
import org.androidannotations.annotations.EActivity;
|
||||
import org.androidannotations.annotations.ViewById;
|
||||
|
||||
@EActivity(R.layout.activity_video_gallery)
|
||||
public class VideoGalleryActivity extends FragmentActivity {
|
||||
|
||||
@ViewById ViewPager viewPager;
|
||||
@ViewById CirclePageIndicator viewPagerIndicator;
|
||||
|
||||
@AfterViews
|
||||
void afterViewInjected() {
|
||||
ViewsPagerAdapter viewsPagerAdapter = new ViewsPagerAdapter(this);
|
||||
viewPager.setAdapter(viewsPagerAdapter);
|
||||
viewPagerIndicator.setViewPager(viewPager);
|
||||
}
|
||||
|
||||
private static final class ViewsPagerAdapter extends FragmentStatePagerAdapter {
|
||||
|
||||
public ViewsPagerAdapter(FragmentActivity activity) {
|
||||
super(activity.getSupportFragmentManager());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
Video video = Video.values()[position];
|
||||
return GalleryVideoFragment.build(video.url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return Video.values().length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position) {
|
||||
return Video.values()[position].name();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,8 @@
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".VideoActivity">
|
||||
|
||||
<VideoView
|
||||
android:id="@+id/videoView"
|
||||
<com.google.android.exoplayer2.ui.SimpleExoPlayerView
|
||||
android:id="@+id/simpleExoPlayerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
|
||||
@@ -6,11 +6,13 @@ import android.util.Pair;
|
||||
import com.danikula.android.garden.io.IoUtils;
|
||||
import com.danikula.videocache.file.FileNameGenerator;
|
||||
import com.danikula.videocache.file.Md5FileNameGenerator;
|
||||
import com.danikula.videocache.headers.HeaderInjector;
|
||||
import com.danikula.videocache.support.ProxyCacheTestUtils;
|
||||
import com.danikula.videocache.support.Response;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import java.io.File;
|
||||
@@ -36,6 +38,8 @@ import static com.danikula.videocache.support.ProxyCacheTestUtils.loadAssetFile;
|
||||
import static com.danikula.videocache.support.ProxyCacheTestUtils.readProxyResponse;
|
||||
import static com.danikula.videocache.support.ProxyCacheTestUtils.resetSystemProxy;
|
||||
import static org.fest.assertions.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* @author Alexey Danilov (danikula@gmail.com).
|
||||
@@ -360,6 +364,20 @@ public class HttpProxyCacheServerTest extends BaseTest {
|
||||
assertThat(proxiedUrl).isEqualTo(HTTP_DATA_URL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHeadersInjectorIsInvoked() throws Exception {
|
||||
HeaderInjector mockedHeaderInjector = Mockito.mock(HeaderInjector.class);
|
||||
|
||||
HttpProxyCacheServer proxy = new HttpProxyCacheServer.Builder(RuntimeEnvironment.application)
|
||||
.headerInjector(mockedHeaderInjector)
|
||||
.build();
|
||||
|
||||
readProxyResponse(proxy, HTTP_DATA_URL);
|
||||
proxy.shutdown();
|
||||
|
||||
verify(mockedHeaderInjector, times(2)).addHeaders(HTTP_DATA_URL); // content info & fetch data requests
|
||||
}
|
||||
|
||||
private Pair<File, Response> readProxyData(String url, int offset) throws IOException {
|
||||
File file = file(cacheFolder, url);
|
||||
HttpProxyCacheServer proxy = newProxy(cacheFolder);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.danikula.videocache;
|
||||
|
||||
import com.danikula.videocache.headers.HeaderInjector;
|
||||
import com.danikula.videocache.sourcestorage.SourceInfoStorage;
|
||||
import com.danikula.videocache.sourcestorage.SourceInfoStorageFactory;
|
||||
import com.danikula.videocache.support.ProxyCacheTestUtils;
|
||||
@@ -25,6 +26,7 @@ import static com.danikula.videocache.support.ProxyCacheTestUtils.loadAssetFile;
|
||||
import static org.fest.assertions.api.Assertions.assertThat;
|
||||
import static org.fest.assertions.api.Assertions.fail;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author Alexey Danilov (danikula@gmail.com).
|
||||
@@ -156,6 +158,16 @@ public class HttpUrlSourceTest extends BaseTest {
|
||||
fail("source.open() should throw exception");
|
||||
}
|
||||
|
||||
@Test(expected = NullPointerException.class)
|
||||
public void testHeaderInjectorNullNotAcceptable() throws Exception {
|
||||
HeaderInjector mockedHeaderInjector = Mockito.mock(HeaderInjector.class);
|
||||
when(mockedHeaderInjector.addHeaders(Mockito.anyString())).thenReturn(null);
|
||||
SourceInfoStorage emptySourceInfoStorage = SourceInfoStorageFactory.newEmptySourceInfoStorage();
|
||||
HttpUrlSource source = new HttpUrlSource(HTTP_DATA_URL_ONE_REDIRECT, emptySourceInfoStorage, mockedHeaderInjector);
|
||||
source.open(0);
|
||||
fail("source.open should throw NPE!");
|
||||
}
|
||||
|
||||
private void readSource(Source source, byte[] target) throws ProxyCacheException {
|
||||
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
|
||||
int totalRead = 0;
|
||||
|
||||
Reference in New Issue
Block a user