diff options
Diffstat (limited to 'org.fox.ttrss/src/main/java/org/fox/ttrss/util/OkHttpProgressGlideModule.java')
-rw-r--r-- | org.fox.ttrss/src/main/java/org/fox/ttrss/util/OkHttpProgressGlideModule.java | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/util/OkHttpProgressGlideModule.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/util/OkHttpProgressGlideModule.java new file mode 100644 index 00000000..b333807e --- /dev/null +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/util/OkHttpProgressGlideModule.java @@ -0,0 +1,160 @@ +package org.fox.ttrss.util; + +import java.io.*; +import java.util.*; + +import android.content.Context; +import android.os.*; + +import com.bumptech.glide.*; +import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader; +import com.bumptech.glide.load.model.GlideUrl; +import com.bumptech.glide.module.GlideModule; + +import okhttp3.*; +import okio.*; + +public class OkHttpProgressGlideModule implements GlideModule { + @Override public void applyOptions(Context context, GlideBuilder builder) { + + } + @Override public void registerComponents(Context context, Glide glide) { + OkHttpClient client = new OkHttpClient.Builder() + .addNetworkInterceptor(createInterceptor(new DispatchingProgressListener())) + .build(); + glide.register(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory(client)); + } + + private static Interceptor createInterceptor(final ResponseProgressListener listener) { + return new Interceptor() { + @Override public Response intercept(Chain chain) throws IOException { + Request request = chain.request(); + Response response = chain.proceed(request); + return response.newBuilder() + .body(new OkHttpProgressResponseBody(request.url(), response.body(), listener)) + .build(); + } + }; + } + + public interface UIProgressListener { + void onProgress(long bytesRead, long expectedLength); + /** + * Control how often the listener needs an update. 0% and 100% will always be dispatched. + * @return in percentage (0.2 = call {@link #onProgress} around every 0.2 percent of progress) + */ + float getGranualityPercentage(); + } + + public static void forget(String url) { + DispatchingProgressListener.forget(url); + } + public static void expect(String url, UIProgressListener listener) { + DispatchingProgressListener.expect(url, listener); + } + + private interface ResponseProgressListener { + void update(HttpUrl url, long bytesRead, long contentLength); + } + + private static class DispatchingProgressListener implements ResponseProgressListener { + private static final Map<String, UIProgressListener> LISTENERS = new HashMap<>(); + private static final Map<String, Long> PROGRESSES = new HashMap<>(); + + private final Handler handler; + DispatchingProgressListener() { + this.handler = new Handler(Looper.getMainLooper()); + } + + static void forget(String url) { + LISTENERS.remove(url); + PROGRESSES.remove(url); + } + static void expect(String url, UIProgressListener listener) { + LISTENERS.put(url, listener); + } + + @Override public void update(HttpUrl url, final long bytesRead, final long contentLength) { + //System.out.printf("%s: %d/%d = %.2f%%%n", url, bytesRead, contentLength, (100f * bytesRead) / contentLength); + + String key = url.toString(); + final UIProgressListener listener = LISTENERS.get(key); + + if (listener == null) { + return; + } + if (contentLength <= bytesRead) { + forget(key); + } + if (needsDispatch(key, bytesRead, contentLength, listener.getGranualityPercentage())) { + handler.post(new Runnable() { + @Override public void run() { + listener.onProgress(bytesRead, contentLength); + } + }); + } + } + + private boolean needsDispatch(String key, long current, long total, float granularity) { + if (granularity == 0 || current == 0 || total == current) { + return true; + } + float percent = 100f * current / total; + long currentProgress = (long)(percent / granularity); + Long lastProgress = PROGRESSES.get(key); + if (lastProgress == null || currentProgress != lastProgress) { + PROGRESSES.put(key, currentProgress); + return true; + } else { + return false; + } + } + } + + private static class OkHttpProgressResponseBody extends ResponseBody { + private final HttpUrl url; + private final ResponseBody responseBody; + private final ResponseProgressListener progressListener; + private BufferedSource bufferedSource; + + OkHttpProgressResponseBody(HttpUrl url, ResponseBody responseBody, + ResponseProgressListener progressListener) { + + this.url = url; + this.responseBody = responseBody; + this.progressListener = progressListener; + } + + @Override public MediaType contentType() { + return responseBody.contentType(); + } + + @Override public long contentLength() { + return responseBody.contentLength(); + } + + @Override public BufferedSource source() { + if (bufferedSource == null) { + bufferedSource = Okio.buffer(source(responseBody.source())); + } + return bufferedSource; + } + + private Source source(Source source) { + return new ForwardingSource(source) { + long totalBytesRead = 0L; + @Override public long read(Buffer sink, long byteCount) throws IOException { + long bytesRead = super.read(sink, byteCount); + long fullLength = responseBody.contentLength(); + if (bytesRead == -1) { // this source is exhausted + totalBytesRead = fullLength; + } else { + totalBytesRead += bytesRead; + } + progressListener.update(url, totalBytesRead, fullLength); + return bytesRead; + } + }; + } + } +}
\ No newline at end of file |