From 70baa564c059be17fe4e806ffd09ae8173f369eb Mon Sep 17 00:00:00 2001 From: Alexey Danilov Date: Wed, 1 Apr 2015 14:24:35 +0300 Subject: [PATCH] :tada: VideoCache 1.0 released --- .gitignore | 11 + build.gradle | 14 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 49896 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 164 ++++++++++++ library/build.gradle | 5 + .../danikula/videocache/ByteArrayCache.java | 67 +++++ .../danikula/videocache/ByteArraySource.java | 39 +++ .../java/com/danikula/videocache/Cache.java | 21 ++ .../danikula/videocache/CacheListener.java | 10 + .../com/danikula/videocache/FileCache.java | 111 ++++++++ .../danikula/videocache/HttpProxyCache.java | 240 ++++++++++++++++++ .../danikula/videocache/HttpUrlSource.java | 112 ++++++++ .../danikula/videocache/Preconditions.java | 30 +++ .../com/danikula/videocache/ProxyCache.java | 202 +++++++++++++++ .../videocache/ProxyCacheException.java | 21 ++ .../danikula/videocache/ProxyCacheUtils.java | 60 +++++ .../java/com/danikula/videocache/Source.java | 17 ++ sample/build.gradle | 19 ++ sample/src/main/AndroidManifest.xml | 24 ++ .../videocache/sample/VideoActivity.java | 75 ++++++ sample/src/main/res/layout/activity_video.xml | 22 ++ .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 7718 bytes sample/src/main/res/values/strings.xml | 3 + settings.gradle | 1 + test/build.gradle | 48 ++++ test/src/main/AndroidManifest.xml | 10 + test/src/main/assets/android.jpg | Bin 0 -> 4768 bytes test/src/main/assets/phones.jpg | Bin 0 -> 94363 bytes .../danikula/videocache/FileCacheTest.java | 145 +++++++++++ .../videocache/HttpProxyCacheTest.java | 141 ++++++++++ .../videocache/HttpUrlSourceTest.java | 68 +++++ .../danikula/videocache/ProxyCacheTest.java | 180 +++++++++++++ .../support/AngryHttpUrlSource.java | 46 ++++ .../support/PhlegmaticByteArraySource.java | 31 +++ .../support/ProxyCacheTestUtils.java | 74 ++++++ .../danikula/videocache/support/Response.java | 25 ++ 37 files changed, 2042 insertions(+) create mode 100644 .gitignore create mode 100644 build.gradle create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 library/build.gradle create mode 100644 library/src/main/java/com/danikula/videocache/ByteArrayCache.java create mode 100644 library/src/main/java/com/danikula/videocache/ByteArraySource.java create mode 100644 library/src/main/java/com/danikula/videocache/Cache.java create mode 100644 library/src/main/java/com/danikula/videocache/CacheListener.java create mode 100644 library/src/main/java/com/danikula/videocache/FileCache.java create mode 100644 library/src/main/java/com/danikula/videocache/HttpProxyCache.java create mode 100644 library/src/main/java/com/danikula/videocache/HttpUrlSource.java create mode 100644 library/src/main/java/com/danikula/videocache/Preconditions.java create mode 100644 library/src/main/java/com/danikula/videocache/ProxyCache.java create mode 100644 library/src/main/java/com/danikula/videocache/ProxyCacheException.java create mode 100644 library/src/main/java/com/danikula/videocache/ProxyCacheUtils.java create mode 100644 library/src/main/java/com/danikula/videocache/Source.java create mode 100644 sample/build.gradle create mode 100644 sample/src/main/AndroidManifest.xml create mode 100644 sample/src/main/java/com/danikula/videocache/sample/VideoActivity.java create mode 100644 sample/src/main/res/layout/activity_video.xml create mode 100644 sample/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 sample/src/main/res/values/strings.xml create mode 100644 settings.gradle create mode 100644 test/build.gradle create mode 100644 test/src/main/AndroidManifest.xml create mode 100644 test/src/main/assets/android.jpg create mode 100644 test/src/main/assets/phones.jpg create mode 100644 test/src/test/java/com/danikula/videocache/FileCacheTest.java create mode 100644 test/src/test/java/com/danikula/videocache/HttpProxyCacheTest.java create mode 100644 test/src/test/java/com/danikula/videocache/HttpUrlSourceTest.java create mode 100644 test/src/test/java/com/danikula/videocache/ProxyCacheTest.java create mode 100644 test/src/test/java/com/danikula/videocache/support/AngryHttpUrlSource.java create mode 100644 test/src/test/java/com/danikula/videocache/support/PhlegmaticByteArraySource.java create mode 100644 test/src/test/java/com/danikula/videocache/support/ProxyCacheTestUtils.java create mode 100644 test/src/test/java/com/danikula/videocache/support/Response.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..47d5e74 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +*.iml +.DS_Store +.gradle + +/.idea +/build +/local.properties +/gradle.properties +/library/build +/sample/build +/test/build diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..eb35ea4 --- /dev/null +++ b/build.gradle @@ -0,0 +1,14 @@ +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.0.0-rc4' + } +} + +allprojects { + repositories { + mavenCentral() + } +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..8c0fb64a8698b08ecc4158d828ca593c4928e9dd GIT binary patch literal 49896 zcmagFb986H(k`5d^NVfUwr$(C?M#x1ZQHiZiEVpg+jrjgoQrerx!>1o_ul)D>ebz~ zs=Mmxr&>W81QY-S1PKWQ%N-;H^tS;2*XwVA`dej1RRn1z<;3VgfE4~kaG`A%QSPsR z#ovnZe+tS9%1MfeDyz`RirvdjPRK~p(#^q2(^5@O&NM19EHdvN-A&StN>0g6QA^VN z0Gx%Gq#PD$QMRFzmK+utjS^Y1F0e8&u&^=w5K<;4Rz|i3A=o|IKLY+g`iK6vfr9?+ z-`>gmU&i?FGSL5&F?TXFu`&Js6h;15QFkXp2M1H9|Eq~bpov-GU(uz%mH0n55wUl- zv#~ccAz`F5wlQ>e_KlJS3@{)B?^v*EQM=IxLa&76^y51a((wq|2-`qON>+4dLc{Oo z51}}o^Zen(oAjxDK7b++9_Yg`67p$bPo3~BCpGM7uAWmvIhWc5Gi+gQZ|Pwa-Gll@<1xmcPy z|NZmu6m)g5Ftu~BG&Xdxclw7Cij{xbBMBn-LMII#Slp`AElb&2^Hw+w>(3crLH!;I zN+Vk$D+wP1#^!MDCiad@vM>H#6+`Ct#~6VHL4lzmy;lSdk>`z6)=>Wh15Q2)dQtGqvn0vJU@+(B5{MUc*qs4!T+V=q=wy)<6$~ z!G>e_4dN@lGeF_$q9`Ju6Ncb*x?O7=l{anm7Eahuj_6lA{*#Gv*TaJclevPVbbVYu z(NY?5q+xxbO6%g1xF0r@Ix8fJ~u)VRUp`S%&rN$&e!Od`~s+64J z5*)*WSi*i{k%JjMSIN#X;jC{HG$-^iX+5f5BGOIHWAl*%15Z#!xntpk($-EGKCzKa zT7{siZ9;4TICsWQ$pu&wKZQTCvpI$Xvzwxoi+XkkpeE&&kFb!B?h2hi%^YlXt|-@5 zHJ~%AN!g_^tmn1?HSm^|gCE#!GRtK2(L{9pL#hp0xh zME}|DB>(5)`iE7CM)&_+S}-Bslc#@B5W4_+k4Cp$l>iVyg$KP>CN?SVGZ(&02>iZK zB<^HP$g$Lq*L$BWd?2(F?-MUbNWTJVQdW7$#8a|k_30#vHAD1Z{c#p;bETk0VnU5A zBgLe2HFJ3032$G<`m*OB!KM$*sdM20jm)It5OSru@tXpK5LT>#8)N!*skNu1$TpIw zufjjdp#lyH5bZ%|Iuo|iu9vG1HrIVWLH>278xo>aVBkPN3V$~!=KnlXQ4eDqS7%E% zQ!z^$Q$b^6Q)g#cLpwur(|<0gWHo6A6jc;n`t(V9T;LzTAU{IAu*uEQ%Ort1k+Kn+f_N`9|bxYC+~Z1 zCC1UCWv*Orx$_@ydv9mIe(liLfOr7mhbV@tKw{6)q^1DH1nmvZ0cj215R<~&I<4S| zgnr;9Cdjqpz#o8i0CQjtl`}{c*P)aSdH|abxGdrR)-3z+02-eX(k*B)Uqv6~^nh** z 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 \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/library/build.gradle b/library/build.gradle new file mode 100644 index 0000000..752dcbf --- /dev/null +++ b/library/build.gradle @@ -0,0 +1,5 @@ +apply plugin: 'java' + +dependencies { + compile 'com.google.android:android:1.6_r2' +} \ No newline at end of file diff --git a/library/src/main/java/com/danikula/videocache/ByteArrayCache.java b/library/src/main/java/com/danikula/videocache/ByteArrayCache.java new file mode 100644 index 0000000..3b1aae0 --- /dev/null +++ b/library/src/main/java/com/danikula/videocache/ByteArrayCache.java @@ -0,0 +1,67 @@ +package com.danikula.videocache; + +import java.io.ByteArrayInputStream; +import java.util.Arrays; + +import static com.danikula.videocache.Preconditions.checkArgument; +import static com.danikula.videocache.Preconditions.checkNotNull; + +/** + * Simple memory based {@link Cache} implementation. + * + * @author Alexey Danilov (danikula@gmail.com). + */ +public class ByteArrayCache implements Cache { + + private volatile byte[] data; + private volatile boolean completed; + + public ByteArrayCache() { + this(new byte[0]); + } + + public ByteArrayCache(byte[] data) { + this.data = Preconditions.checkNotNull(data); + } + + + @Override + public int read(byte[] buffer, long offset, int length) throws ProxyCacheException { + if (offset >= data.length) { + return -1; + } + if (offset > Integer.MAX_VALUE) { + throw new IllegalArgumentException("Too long offset for memory cache " + offset); + } + return new ByteArrayInputStream(data).read(buffer, (int) offset, length); + } + + @Override + public int available() throws ProxyCacheException { + return data.length; + } + + @Override + public void append(byte[] newData, int length) throws ProxyCacheException { + Preconditions.checkNotNull(data); + Preconditions.checkArgument(length >= 0 && length <= newData.length); + + byte[] appendedData = Arrays.copyOf(data, data.length + length); + System.arraycopy(newData, 0, appendedData, data.length, length); + data = appendedData; + } + + @Override + public void close() throws ProxyCacheException { + } + + @Override + public void complete() { + completed = true; + } + + @Override + public boolean isCompleted() { + return completed; + } +} diff --git a/library/src/main/java/com/danikula/videocache/ByteArraySource.java b/library/src/main/java/com/danikula/videocache/ByteArraySource.java new file mode 100644 index 0000000..d66efea --- /dev/null +++ b/library/src/main/java/com/danikula/videocache/ByteArraySource.java @@ -0,0 +1,39 @@ +package com.danikula.videocache; + +import java.io.ByteArrayInputStream; + +/** + * Simple memory based {@link Source} implementation. + * + * @author Alexey Danilov (danikula@gmail.com). + */ +public class ByteArraySource implements Source { + + private final byte[] data; + private ByteArrayInputStream arrayInputStream; + + public ByteArraySource(byte[] data) { + this.data = data; + } + + @Override + public int read(byte[] buffer) throws ProxyCacheException { + return arrayInputStream.read(buffer, 0, buffer.length); + } + + @Override + public int available() throws ProxyCacheException { + return data.length; + } + + @Override + public void open(int offset) throws ProxyCacheException { + arrayInputStream = new ByteArrayInputStream(data); + arrayInputStream.skip(offset); + } + + @Override + public void close() throws ProxyCacheException { + } +} + diff --git a/library/src/main/java/com/danikula/videocache/Cache.java b/library/src/main/java/com/danikula/videocache/Cache.java new file mode 100644 index 0000000..961d980 --- /dev/null +++ b/library/src/main/java/com/danikula/videocache/Cache.java @@ -0,0 +1,21 @@ +package com.danikula.videocache; + +/** + * Cache for proxy. + * + * @author Alexey Danilov (danikula@gmail.com). + */ +public interface Cache { + + int available() throws ProxyCacheException; + + int read(byte[] buffer, long offset, int length) throws ProxyCacheException; + + void append(byte[] data, int length) throws ProxyCacheException; + + void close() throws ProxyCacheException; + + void complete() throws ProxyCacheException; + + boolean isCompleted(); +} diff --git a/library/src/main/java/com/danikula/videocache/CacheListener.java b/library/src/main/java/com/danikula/videocache/CacheListener.java new file mode 100644 index 0000000..a4e507f --- /dev/null +++ b/library/src/main/java/com/danikula/videocache/CacheListener.java @@ -0,0 +1,10 @@ +package com.danikula.videocache; + +/** + * @author Egor Makovsky (yahor.makouski@gmail.com). + */ +public interface CacheListener { + void onError(ProxyCacheException e); + + void onCacheDataAvailable(int cachePercentage); +} diff --git a/library/src/main/java/com/danikula/videocache/FileCache.java b/library/src/main/java/com/danikula/videocache/FileCache.java new file mode 100644 index 0000000..d1600b9 --- /dev/null +++ b/library/src/main/java/com/danikula/videocache/FileCache.java @@ -0,0 +1,111 @@ +package com.danikula.videocache; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; + +import static com.danikula.videocache.Preconditions.checkNotNull; + +/** + * {@link Cache} that uses file for storing data. + * + * @author Alexey Danilov (danikula@gmail.com). + */ +public class FileCache implements Cache { + + private static final String TEMP_POSTFIX = ".download"; + + private RandomAccessFile dataFile; + private File file; + + public FileCache(File file) throws ProxyCacheException { + try { + Preconditions.checkNotNull(file); + boolean partialFile = isTempFile(file); + boolean completed = file.exists() && !partialFile; + if (completed) { + this.dataFile = new RandomAccessFile(file, "r"); + this.file = file; + } else { + ProxyCacheUtils.createDirectory(file.getParentFile()); + this.file = partialFile ? file : new File(file.getParentFile(), file.getName() + TEMP_POSTFIX); + this.dataFile = new RandomAccessFile(this.file, "rw"); + } + } catch (IOException e) { + throw new ProxyCacheException("Error using file " + file + " as disc cache", e); + } + } + + @Override + public synchronized int available() throws ProxyCacheException { + try { + return (int) dataFile.length(); + } catch (IOException e) { + throw new ProxyCacheException("Error reading length of file " + dataFile, e); + } + } + + @Override + public synchronized int read(byte[] buffer, long offset, int length) throws ProxyCacheException { + try { + dataFile.seek(offset); + return dataFile.read(buffer, 0, length); + } catch (IOException e) { + String format = "Error reading %d bytes with offset %d from file[%d bytes] to buffer[%d bytes]"; + throw new ProxyCacheException(String.format(format, length, offset, available(), buffer.length), e); + } + } + + @Override + public synchronized void append(byte[] data, int length) throws ProxyCacheException { + try { + if (isCompleted()) { + throw new ProxyCacheException("Error append cache: cache file " + file + " is completed!"); + } + dataFile.seek(available()); + dataFile.write(data, 0, length); + } catch (IOException e) { + String format = "Error writing %d bytes to %s from buffer with size %d"; + throw new ProxyCacheException(String.format(format, length, dataFile, data.length), e); + } + } + + @Override + public synchronized void close() throws ProxyCacheException { + try { + dataFile.close(); + } catch (IOException e) { + throw new ProxyCacheException("Error closing file " + file, e); + } + } + + @Override + public synchronized void complete() throws ProxyCacheException { + if (isCompleted()) { + return; + } + + close(); + String fileName = file.getName().substring(0, file.getName().length() - TEMP_POSTFIX.length()); + File completedFile = new File(file.getParentFile(), fileName); + boolean renamed = file.renameTo(completedFile); + if (!renamed) { + throw new ProxyCacheException("Error renaming file " + file + " to " + completedFile + " for completion!"); + } + file = completedFile; + try { + dataFile = new RandomAccessFile(file, "r"); + } catch (IOException e) { + throw new ProxyCacheException("Error opening " + file + " as disc cache", e); + } + } + + @Override + public synchronized boolean isCompleted() { + return !isTempFile(file); + } + + private boolean isTempFile(File file) { + return file.getName().endsWith(TEMP_POSTFIX); + } +} diff --git a/library/src/main/java/com/danikula/videocache/HttpProxyCache.java b/library/src/main/java/com/danikula/videocache/HttpProxyCache.java new file mode 100644 index 0000000..7b97fea --- /dev/null +++ b/library/src/main/java/com/danikula/videocache/HttpProxyCache.java @@ -0,0 +1,240 @@ +package com.danikula.videocache; + +import android.net.Uri; +import android.text.TextUtils; +import android.util.Log; + +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * {@link ProxyCache} that uses local server to handle requests and cache data. + * Typical usage: + *

+ * HttpProxyCache proxy;
+ * public onCreate(Bundle state) {
+ *      super.onCreate(state);
+ *      ...
+ *      try{
+ *          HttpUrlSource source = new HttpUrlSource(YOUR_VIDEO_URI);
+ *          Cache cache = new FileCache(new File(context.getCacheDir(), "video.mp4"));
+ *          proxy = new HttpProxyCache(source, cache);
+ *          videoView.setVideoPath(proxy.getUrl());
+ *      } catch(ProxyCacheException e) {
+ *          Log.e(LOG_TAG, "Error playing video", e);
+ *      }
+ * }
+ * public onDestroy(){
+ *     super.onDestroy();
+ *
+ *     if (proxy != null) {
+ *         proxy.shutdown();
+ *     }
+ * }
+ * 
+ * + * @author Alexey Danilov (danikula@gmail.com). + */ +public class HttpProxyCache extends ProxyCache { + + private static final int CLIENT_COUNT = 3; + private static final Pattern RANGE_HEADER_PATTERN = Pattern.compile("[R,r]ange:[ ]?bytes=(\\d*)-"); + private static final String PROXY_HOST = "127.0.0.1"; + + private final HttpUrlSource httpUrlSource; + private final Cache cache; + private final ServerSocket serverSocket; + private final int port; + private final Thread waitConnectionThread; + private final ExecutorService executorService; + + public HttpProxyCache(HttpUrlSource source, Cache cache, boolean logEnabled) throws ProxyCacheException { + super(source, cache, logEnabled); + + this.httpUrlSource = source; + this.cache = cache; + this.executorService = Executors.newFixedThreadPool(CLIENT_COUNT); + try { + InetAddress inetAddress = InetAddress.getByName(PROXY_HOST); + this.serverSocket = new ServerSocket(0, CLIENT_COUNT, inetAddress); + this.port = serverSocket.getLocalPort(); + CountDownLatch startSignal = new CountDownLatch(1); + this.waitConnectionThread = new Thread(new WaitRequestsRunnable(startSignal)); + this.waitConnectionThread.start(); + startSignal.await(); // freeze thread, wait for server starts + } catch (IOException | InterruptedException e) { + executorService.shutdown(); + throw new ProxyCacheException("Error starting local server", e); + } + } + + public HttpProxyCache(HttpUrlSource source, Cache cache) throws ProxyCacheException { + this(source, cache, false); + } + + public String getUrl() { + return "http://" + PROXY_HOST + ":" + port + Uri.parse(httpUrlSource.url).getPath(); + } + + @Override + public void shutdown() { + super.shutdown(); + + Log.i(ProxyCacheUtils.LOG_TAG, "Shutdown proxy"); + waitConnectionThread.interrupt(); + try { + if (!serverSocket.isClosed()) { + serverSocket.close(); + } + } catch (IOException e) { + onError(new ProxyCacheException("Error shutting down local server", e)); + } + } + + private void waitForRequest() { + try { + while (!Thread.currentThread().isInterrupted()) { + Socket socket = serverSocket.accept(); + Log.d(ProxyCacheUtils.LOG_TAG, "Accept new socket " + socket); + processSocketInBackground(socket); + } + } catch (IOException e) { + onError(new ProxyCacheException("Error during waiting connection", e)); + } + } + + private void processSocketInBackground(final Socket socket) throws IOException { + executorService.submit(new Runnable() { + @Override + public void run() { + try { + processSocket(socket); + } catch (Throwable e) { + onError(e); + } + } + }); + } + + private void processSocket(Socket socket) { + try { + InputStream inputStream = socket.getInputStream(); + String request = readRequest(inputStream); + Log.i(ProxyCacheUtils.LOG_TAG, "Request to cache proxy:\n" + request); + long rangeOffset = getRangeOffset(request); + writeResponse(socket, rangeOffset); + } catch (ProxyCacheException | IOException e) { + onError(new ProxyCacheException("Error processing request", e)); + } finally { + releaseSocket(socket); + } + } + + private void writeResponse(Socket socket, long rangeOffset) throws ProxyCacheException, IOException { + OutputStream out = new BufferedOutputStream(socket.getOutputStream()); + byte[] buffer = new byte[ProxyCacheUtils.DEFAULT_BUFFER_SIZE]; + int readBytes; + long offset = Math.max(rangeOffset, 0); + boolean headersWrote = false; + while ((readBytes = read(buffer, offset, buffer.length)) != -1) { + // tiny optimization: to prevent HEAD request in source for content-length. content-length 'll available after reading source + if (!headersWrote) { + writeResponseHeaders(out, rangeOffset); + headersWrote = true; + } + out.write(buffer, 0, readBytes); + if (isLogEnabled()) { + Log.d(ProxyCacheUtils.LOG_TAG, "Write data[" + readBytes + " bytes] to socket " + socket + " with offset " + offset + ": " + ProxyCacheUtils.preview(buffer, readBytes)); + } + offset += readBytes; + } + out.flush(); + } + + private void writeResponseHeaders(OutputStream out, long rangeOffset) throws IOException, ProxyCacheException { + String responseHeaders = newResponseHeaders(rangeOffset); + out.write(responseHeaders.getBytes("UTF-8")); + Log.i(ProxyCacheUtils.LOG_TAG, "Response headers:\n" + responseHeaders); + } + + private String newResponseHeaders(long offset) throws IOException, ProxyCacheException { + boolean partial = offset >= 0; + String mime = httpUrlSource.getMime(); + boolean mimeKnown = !TextUtils.isEmpty(mime); + int length = cache.isCompleted() ? cache.available() : httpUrlSource.available(); + boolean lengthKnown = length >= 0; + long contentLength = partial ? length - offset : length; + return new StringBuilder() + .append(partial ? "HTTP/1.1 206 PARTIAL CONTENT\n" : "HTTP/1.1 200 OK\n") + .append("Accept-Ranges: bytes\n") + .append(lengthKnown ? String.format("Content-Length: %d\n", contentLength) : "") + .append(lengthKnown && partial ? String.format("Content-Range: bytes %d-%d/%d\n", offset, length, length) : "") + .append(mimeKnown ? String.format("Content-Type: %s\n", mime) : "") + .append("\n") // headers end + .toString(); + } + + private String readRequest(InputStream inputStream) throws IOException { + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); + StringBuilder str = new StringBuilder(); + String line; + while (!TextUtils.isEmpty(line = reader.readLine())) { // until new line (headers ending) + str.append(line).append('\n'); + } + return str.toString(); + } + + private long getRangeOffset(String request) { + Matcher matcher = RANGE_HEADER_PATTERN.matcher(request); + if (matcher.find()) { + String rangeValue = matcher.group(1); + return Long.parseLong(rangeValue); + } + return -1; + } + + private void releaseSocket(Socket socket) { + try { + socket.shutdownInput(); + } catch (IOException e) { + onError(new ProxyCacheException("Error closing socket input stream", e)); + } + try { + socket.shutdownOutput(); + } catch (IOException e) { + onError(new ProxyCacheException("Error closing socket output stream", e)); + } + try { + socket.close(); + } catch (IOException e) { + onError(new ProxyCacheException("Error closing socket", e)); + } + } + + private final class WaitRequestsRunnable implements Runnable { + + private final CountDownLatch startSignal; + + public WaitRequestsRunnable(CountDownLatch startSignal) { + this.startSignal = startSignal; + } + + @Override + public void run() { + startSignal.countDown(); + waitForRequest(); + } + } +} diff --git a/library/src/main/java/com/danikula/videocache/HttpUrlSource.java b/library/src/main/java/com/danikula/videocache/HttpUrlSource.java new file mode 100644 index 0000000..61af99e --- /dev/null +++ b/library/src/main/java/com/danikula/videocache/HttpUrlSource.java @@ -0,0 +1,112 @@ +package com.danikula.videocache; + +import android.text.TextUtils; +import android.util.Log; + +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; + +import static com.danikula.videocache.Preconditions.checkNotNull; +import static java.net.HttpURLConnection.HTTP_OK; +import static java.net.HttpURLConnection.HTTP_PARTIAL; + +/** + * {@link Source} that uses http resource as source for {@link ProxyCache}. + * + * @author Alexey Danilov (danikula@gmail.com). + */ +public class HttpUrlSource implements Source { + + final String url; + private HttpURLConnection connection; + private InputStream inputStream; + private volatile int available = Integer.MIN_VALUE; + private volatile String mime; + + public HttpUrlSource(String url) { + this(url, ProxyCacheUtils.getSupposablyMime(url)); + } + + public HttpUrlSource(String url, String mime) { + this.url = Preconditions.checkNotNull(url); + this.mime = mime; + } + + @Override + public int available() throws ProxyCacheException { + if (available == Integer.MIN_VALUE) { + fetchContentInfo(); + } + return available; + } + + @Override + public void open(int offset) throws ProxyCacheException { + try { + Log.d(ProxyCacheUtils.LOG_TAG, "Open connection " + (offset > 0 ? " with offset " + offset : "") + " to " + url); + connection = (HttpURLConnection) new URL(url).openConnection(); + if (offset > 0) { + connection.setRequestProperty("Range", "bytes=" + offset + "-"); + } + mime = connection.getContentType(); + inputStream = connection.getInputStream(); + readSourceAvailableBytes(connection, offset); + } catch (IOException e) { + throw new ProxyCacheException("Error opening connection for " + url + " with offset " + offset, e); + } + } + + private void readSourceAvailableBytes(HttpURLConnection connection, int offset) throws IOException { + int contentLength = connection.getContentLength(); + int responseCode = connection.getResponseCode(); + available = responseCode == HTTP_OK ? contentLength : + responseCode == HTTP_PARTIAL ? contentLength + offset : + available; + } + + @Override + public void close() throws ProxyCacheException { + if (connection != null) { + connection.disconnect(); + } + } + + @Override + public int read(byte[] buffer) throws ProxyCacheException { + if (inputStream == null) { + throw new ProxyCacheException("Error reading data from " + url + ": connection is absent!"); + } + try { + return inputStream.read(buffer, 0, buffer.length); + } catch (IOException e) { + throw new ProxyCacheException("Error reading data from " + url, e); + } + } + + private void fetchContentInfo() throws ProxyCacheException { + Log.d(ProxyCacheUtils.LOG_TAG, "Read content info from " + url); + HttpURLConnection urlConnection = null; + try { + urlConnection = (HttpURLConnection) new URL(url).openConnection(); + urlConnection.setRequestMethod("HEAD"); + available = urlConnection.getContentLength(); + mime = urlConnection.getContentType(); + Log.d(ProxyCacheUtils.LOG_TAG, "Content-Length of " + url + " is " + available + " bytes, mime is " + mime); + } catch (IOException e) { + throw new ProxyCacheException("Error fetching Content-Length from " + url); + } finally { + if (urlConnection != null) { + urlConnection.disconnect(); + } + } + } + + public String getMime() throws ProxyCacheException { + if (TextUtils.isEmpty(mime)) { + fetchContentInfo(); + } + return mime; + } +} diff --git a/library/src/main/java/com/danikula/videocache/Preconditions.java b/library/src/main/java/com/danikula/videocache/Preconditions.java new file mode 100644 index 0000000..2de77df --- /dev/null +++ b/library/src/main/java/com/danikula/videocache/Preconditions.java @@ -0,0 +1,30 @@ +package com.danikula.videocache; + +final class Preconditions { + + static T checkNotNull(T reference) { + if (reference == null) { + throw new NullPointerException(); + } + return reference; + } + + static T checkNotNull(T reference, String errorMessage) { + if (reference == null) { + throw new NullPointerException(errorMessage); + } + return reference; + } + + static void checkArgument(boolean expression) { + if (!expression) { + throw new IllegalArgumentException(); + } + } + + static void checkArgument(boolean expression, String errorMessage) { + if (!expression) { + throw new IllegalArgumentException(errorMessage); + } + } +} diff --git a/library/src/main/java/com/danikula/videocache/ProxyCache.java b/library/src/main/java/com/danikula/videocache/ProxyCache.java new file mode 100644 index 0000000..36938dd --- /dev/null +++ b/library/src/main/java/com/danikula/videocache/ProxyCache.java @@ -0,0 +1,202 @@ +package com.danikula.videocache; + +import android.os.Handler; +import android.os.Looper; +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}). + *

+ * Can be used only for sources with persistent data (that doesn't change with time). + * Method {@link #read(byte[], long, int)} will be blocked while fetching data from source. + * Useful for streaming something with caching e.g. streaming video/audio etc. + * + * @author Alexey Danilov (danikula@gmail.com). + */ +public class ProxyCache { + + private static final int MAX_READ_SOURCE_ATTEMPTS = 1; + + private final Source source; + private final Cache cache; + private final Object wc; + private final Handler handler; + private volatile Thread sourceReaderThread; + private volatile boolean stopped; + private final AtomicInteger readSourceErrorsCount; + private CacheListener cacheListener; + private final boolean logEnabled; + + public ProxyCache(Source source, Cache cache, boolean logEnabled) { + this.source = checkNotNull(source); + this.cache = checkNotNull(cache); + this.logEnabled = logEnabled; + this.wc = new Object(); + this.handler = new Handler(Looper.getMainLooper()); + this.readSourceErrorsCount = new AtomicInteger(); + } + + public ProxyCache(Source source, Cache cache) { + this(source, cache, false); + } + + public void setCacheListener(CacheListener cacheListener) { + this.cacheListener = cacheListener; + } + + public int read(byte[] buffer, long offset, int length) throws ProxyCacheException { + ProxyCacheUtils.assertBuffer(buffer, offset, length); + + while (!cache.isCompleted() && cache.available() < (offset + length) && !stopped) { + readSourceAsync(); + waitForSourceData(); + checkIsCacheValid(); + checkReadSourceErrorsCount(); + } + int read = cache.read(buffer, offset, length); + if (isLogEnabled()) { + Log.d(LOG_TAG, "Read data[" + read + " bytes] from cache with offset " + offset + ": " + ProxyCacheUtils.preview(buffer, read)); + } + return read; + } + + private void checkIsCacheValid() throws ProxyCacheException { + int sourceAvailable = source.available(); + if (sourceAvailable > 0 && cache.available() > sourceAvailable) { + throw new ProxyCacheException("Unexpected cache: cache [" + cache.available() + " bytes] > source[" + sourceAvailable + " bytes]"); + } + } + + private void checkReadSourceErrorsCount() throws ProxyCacheException { + int errorsCount = readSourceErrorsCount.get(); + if (errorsCount >= MAX_READ_SOURCE_ATTEMPTS) { + readSourceErrorsCount.set(0); + throw new ProxyCacheException("Error reading source " + errorsCount + " times"); + } + } + + public void shutdown() { + try { + stopped = true; + if (sourceReaderThread != null) { + sourceReaderThread.interrupt(); + } + cache.close(); + } catch (ProxyCacheException e) { + onError(e); + } + } + + private void readSourceAsync() throws ProxyCacheException { + + boolean readingInProgress = sourceReaderThread != null && sourceReaderThread.getState() != Thread.State.TERMINATED; + if (!stopped && !cache.isCompleted() && !readingInProgress) { + sourceReaderThread = new Thread(new SourceReaderRunnable(), "Source reader for ProxyCache"); + sourceReaderThread.start(); + } + } + + private void waitForSourceData() throws ProxyCacheException { + synchronized (wc) { + try { + wc.wait(1000); + } catch (InterruptedException e) { + throw new ProxyCacheException("Waiting source data is interrupted!", e); + } + } + } + + private void notifyNewCacheDataAvailable(final int cachePercentage) { + handler.post(new Runnable() { + @Override + public void run() { + if (cacheListener != null) { + cacheListener.onCacheDataAvailable(cachePercentage); + } + } + }); + + synchronized (wc) { + wc.notifyAll(); + } + } + + private void readSource() { + int cachePercentage = 0; + try { + int offset = cache.available(); + source.open(offset); + byte[] buffer = new byte[ProxyCacheUtils.DEFAULT_BUFFER_SIZE]; + int readBytes; + while ((readBytes = source.read(buffer)) != -1 && !Thread.currentThread().isInterrupted() && !stopped) { + if (isLogEnabled()) { + Log.d(LOG_TAG, "Write data[" + readBytes + " bytes] to cache from source with offset " + offset + ": " + ProxyCacheUtils.preview(buffer, readBytes)); + } + cache.append(buffer, readBytes); + offset += readBytes; + cachePercentage = offset * 100 / source.available(); + + notifyNewCacheDataAvailable(cachePercentage); + } + if (cache.available() == source.available()) { + cache.complete(); + } + } catch (Throwable e) { + readSourceErrorsCount.incrementAndGet(); + onError(e); + } finally { + closeSource(); + notifyNewCacheDataAvailable(cachePercentage); + } + } + + private void closeSource() { + try { + source.close(); + } catch (ProxyCacheException e) { + onError(new ProxyCacheException("Error closing source " + source, e)); + } + } + + protected final void onError(final Throwable e) { + Log.e(LOG_TAG, "ProxyCache error", e); + handler.post(new ErrorDeliverer(e)); + } + + protected boolean isLogEnabled() { + return logEnabled; + } + + private class SourceReaderRunnable implements Runnable { + + @Override + public void run() { + readSource(); + } + } + + private class ErrorDeliverer implements Runnable { + + private final Throwable error; + + public ErrorDeliverer(Throwable error) { + this.error = error; + } + + @Override + public void run() { + if (error instanceof ProxyCacheException) { + if (cacheListener != null) { + cacheListener.onError((ProxyCacheException) error); + } + } else { + throw new RuntimeException("Unexpected error!", error); + } + } + } +} diff --git a/library/src/main/java/com/danikula/videocache/ProxyCacheException.java b/library/src/main/java/com/danikula/videocache/ProxyCacheException.java new file mode 100644 index 0000000..3b72a14 --- /dev/null +++ b/library/src/main/java/com/danikula/videocache/ProxyCacheException.java @@ -0,0 +1,21 @@ +package com.danikula.videocache; + +/** + * Indicates any error in work of {@link ProxyCache}. + * + * @author Alexey Danilov + */ +public class ProxyCacheException extends Exception { + + public ProxyCacheException(String message) { + super(message); + } + + public ProxyCacheException(String message, Throwable cause) { + super(message, cause); + } + + public ProxyCacheException(Throwable cause) { + super(cause); + } +} diff --git a/library/src/main/java/com/danikula/videocache/ProxyCacheUtils.java b/library/src/main/java/com/danikula/videocache/ProxyCacheUtils.java new file mode 100644 index 0000000..02a09ab --- /dev/null +++ b/library/src/main/java/com/danikula/videocache/ProxyCacheUtils.java @@ -0,0 +1,60 @@ +package com.danikula.videocache; + +import android.text.TextUtils; +import android.webkit.MimeTypeMap; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; + +import static com.danikula.videocache.Preconditions.checkArgument; +import static com.danikula.videocache.Preconditions.checkNotNull; + +/** + * Just simple utils. + * + * @author Alexey Danilov (danikula@gmail.com). + */ +class ProxyCacheUtils { + + static final String LOG_TAG = "ProxyCache"; + static final int DEFAULT_BUFFER_SIZE = 8 * 1024; + static final int MAX_ARRAY_PREVIEW = 16; + + static String getSupposablyMime(String url) { + MimeTypeMap mimes = MimeTypeMap.getSingleton(); + String extension = MimeTypeMap.getFileExtensionFromUrl(url); + return TextUtils.isEmpty(extension) ? null : mimes.getMimeTypeFromExtension(extension); + } + + static void assertBuffer(byte[] buffer, long offset, int length) { + checkNotNull(buffer, "Buffer must be not null!"); + checkArgument(offset >= 0, "Data offset must be positive!"); + checkArgument(length >= 0 && length <= buffer.length, "Length must be in range [0..buffer.length]"); + } + + static String preview(byte[] data, int length) { + int previewLength = Math.min(MAX_ARRAY_PREVIEW, Math.max(length, 0)); + byte[] dataRange = Arrays.copyOfRange(data, 0, previewLength); + String preview = Arrays.toString(dataRange); + if (previewLength < length) { + preview = preview.substring(0, preview.length() - 1) + ", ...]"; + } + return preview; + } + + static void createDirectory(File directory) throws IOException { + checkNotNull(directory, "File must be not null!"); + if (directory.exists()) { + checkArgument(directory.isDirectory(), "File is not directory!"); + } else { + boolean isCreated = directory.mkdirs(); + if (!isCreated) { + String error = String.format("Directory %s can't be created", directory.getAbsolutePath()); + throw new IOException(error); + } + } + } + + +} diff --git a/library/src/main/java/com/danikula/videocache/Source.java b/library/src/main/java/com/danikula/videocache/Source.java new file mode 100644 index 0000000..98d1648 --- /dev/null +++ b/library/src/main/java/com/danikula/videocache/Source.java @@ -0,0 +1,17 @@ +package com.danikula.videocache; + +/** + * Source for proxy. + * + * @author Alexey Danilov (danikula@gmail.com). + */ +public interface Source { + + int available() throws ProxyCacheException; + + void open(int offset) throws ProxyCacheException; + + void close() throws ProxyCacheException; + + int read(byte[] buffer) throws ProxyCacheException; +} diff --git a/sample/build.gradle b/sample/build.gradle new file mode 100644 index 0000000..904d68a --- /dev/null +++ b/sample/build.gradle @@ -0,0 +1,19 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 22 + buildToolsVersion "22.0.1" + + defaultConfig { + applicationId "com.danikula.videocache.sample" + minSdkVersion 15 + targetSdkVersion 22 + versionCode 1 + versionName "1.0" + } +} + +dependencies { + compile 'com.android.support:appcompat-v7:22.0.0' + compile project(':library') +} diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml new file mode 100644 index 0000000..a08536e --- /dev/null +++ b/sample/src/main/AndroidManifest.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + diff --git a/sample/src/main/java/com/danikula/videocache/sample/VideoActivity.java b/sample/src/main/java/com/danikula/videocache/sample/VideoActivity.java new file mode 100644 index 0000000..d345f43 --- /dev/null +++ b/sample/src/main/java/com/danikula/videocache/sample/VideoActivity.java @@ -0,0 +1,75 @@ +package com.danikula.videocache.sample; + +import android.os.Bundle; +import android.support.v7.app.ActionBarActivity; +import android.util.Log; +import android.widget.ProgressBar; +import android.widget.VideoView; + +import com.danikula.videocache.Cache; +import com.danikula.videocache.CacheListener; +import com.danikula.videocache.FileCache; +import com.danikula.videocache.HttpProxyCache; +import com.danikula.videocache.HttpUrlSource; +import com.danikula.videocache.ProxyCacheException; + +import java.io.File; + +public class VideoActivity extends ActionBarActivity implements CacheListener { + + private static final String LOG_TAG = "VideoActivity"; + private static final String VIDEO_CACHE_NAME = "devbytes.mp4"; + private static final String VIDEO_URL = "https://dl.dropboxusercontent.com/u/15506779/persistent/proxycache/devbytes.mp4"; + + private VideoView videoView; + private ProgressBar progressBar; + private HttpProxyCache proxyCache; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setUpUi(); + playWithCache(); + } + + private void setUpUi() { + setContentView(R.layout.activity_video); + videoView = (VideoView) findViewById(R.id.videoView); + progressBar = (ProgressBar) findViewById(R.id.progressBar); + progressBar.setMax(100); + } + + private void playWithCache() { + try { + Cache cache = new FileCache(new File(getExternalCacheDir(), VIDEO_CACHE_NAME)); + HttpUrlSource source = new HttpUrlSource(VIDEO_URL); + proxyCache = new HttpProxyCache(source, cache); + proxyCache.setCacheListener(this); + videoView.setVideoPath(proxyCache.getUrl()); + videoView.start(); + } catch (ProxyCacheException e) { + // do nothing. onError() handles all errors + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + + if (proxyCache != null) { + proxyCache.shutdown(); + } + } + + @Override + public void onError(ProxyCacheException e) { + Log.e(LOG_TAG, "Error playing video", e); + } + + @Override + public void onCacheDataAvailable(int cachePercentage) { + progressBar.setProgress(cachePercentage); + } + +} diff --git a/sample/src/main/res/layout/activity_video.xml b/sample/src/main/res/layout/activity_video.xml new file mode 100644 index 0000000..0934988 --- /dev/null +++ b/sample/src/main/res/layout/activity_video.xml @@ -0,0 +1,22 @@ + + + + + + + diff --git a/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png b/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..324e72cdd7480cb983fa1bcc7ce686e51ef87fe7 GIT binary patch literal 7718 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 literal 0 HcmV?d00001 diff --git a/sample/src/main/res/values/strings.xml b/sample/src/main/res/values/strings.xml new file mode 100644 index 0000000..2a6f560 --- /dev/null +++ b/sample/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + VideoCacheSample + diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..c83799c --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +include ':sample', ':library', ':test' diff --git a/test/build.gradle b/test/build.gradle new file mode 100644 index 0000000..5914bc9 --- /dev/null +++ b/test/build.gradle @@ -0,0 +1,48 @@ +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath 'com.github.jcandksolutions.gradle:android-unit-test:2.1.1' + } +} + +repositories { + maven { url 'https://github.com/danikula/android-garden/raw/mvn-repo' } +} + +apply plugin: 'com.android.application' + +android { + compileSdkVersion 21 + buildToolsVersion '22.0.1' + + defaultConfig { + applicationId 'com.danikula.proxycache.test' + minSdkVersion 9 + targetSdkVersion 18 // Robolectric doesn't support API 19-21 + versionCode 1 + versionName '0.1' + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_7 + targetCompatibility JavaVersion.VERSION_1_7 + } +} + +apply plugin: 'android-unit-test' + +// to fix AS 0.8.9+ issue (https://github.com/evant/android-studio-unit-test-plugin Troubleshooting) +tasks.findByName("assembleDebug").dependsOn("testDebugClasses") + +dependencies { + compile project (':library') + + testCompile 'junit:junit:4.10' + testCompile 'org.robolectric:robolectric:2.4' + testCompile 'com.squareup:fest-android:1.0.0' + testCompile 'com.google.guava:guava-jdk5:17.0' + testCompile('com.danikula:android-garden:2.0.11-SNAPSHOT') { + exclude group: 'com.google.android' + } +} diff --git a/test/src/main/AndroidManifest.xml b/test/src/main/AndroidManifest.xml new file mode 100644 index 0000000..d667938 --- /dev/null +++ b/test/src/main/AndroidManifest.xml @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/test/src/main/assets/android.jpg b/test/src/main/assets/android.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a66fd8136158458a0fd8b2eedd15c825046f3fe4 GIT binary patch literal 4768 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 literal 0 HcmV?d00001 diff --git a/test/src/main/assets/phones.jpg b/test/src/main/assets/phones.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d29f5a58cd61eab2e9de5b74650b5973a68db6c0 GIT binary patch literal 94363 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

Zo`b!lNureiw$2=PM8_ewIX3>5nYIrE~g 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 0) { + connection.setRequestProperty("Range", "bytes=" + offset + "-"); + } + return new Response(connection); + } finally { + connection.disconnect(); + } + } + + public static byte[] loadAssetFile(String name) throws IOException { + InputStream in = Robolectric.application.getResources().getAssets().open(name); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + IoUtils.copy(in, out); + IoUtils.closeSilently(in); + IoUtils.closeSilently(out); + return out.toByteArray(); + } + + public static File getTempFile(File file) { + return new File(file.getParentFile(), file.getName() + ".download"); + } + + public static File newCacheFile() { + return new File(Robolectric.application.getCacheDir(), UUID.randomUUID().toString()); + } + + public static byte[] generate(int capacity) { + Random random = new Random(System.currentTimeMillis()); + byte[] result = new byte[capacity]; + random.nextBytes(result); + return result; + } +} diff --git a/test/src/test/java/com/danikula/videocache/support/Response.java b/test/src/test/java/com/danikula/videocache/support/Response.java new file mode 100644 index 0000000..6b68b64 --- /dev/null +++ b/test/src/test/java/com/danikula/videocache/support/Response.java @@ -0,0 +1,25 @@ +package com.danikula.videocache.support; + +import com.google.common.io.ByteStreams; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.util.List; +import java.util.Map; + +public class Response { + + public final int code; + public final byte[] data; + public final int contentLength; + public final String contentType; + public final Map> headers; + + public Response(HttpURLConnection connection) throws IOException { + this.code = connection.getResponseCode(); + this.contentLength = connection.getContentLength(); + this.contentType = connection.getContentType(); + this.headers = connection.getHeaderFields(); + this.data = ByteStreams.toByteArray(connection.getInputStream()); + } +} \ No newline at end of file