1 /* 2 * Copyright (C) 2015 Square, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.squareup.okhttp.recipes; 17 18 import com.squareup.okhttp.Interceptor; 19 import com.squareup.okhttp.MediaType; 20 import com.squareup.okhttp.OkHttpClient; 21 import com.squareup.okhttp.Response; 22 import com.squareup.okhttp.ResponseBody; 23 import com.squareup.okhttp.Request; 24 import java.io.IOException; 25 import okio.Buffer; 26 import okio.BufferedSource; 27 import okio.ForwardingSource; 28 import okio.Okio; 29 import okio.Source; 30 31 public final class Progress { 32 33 private final OkHttpClient client = new OkHttpClient(); 34 35 public void run() throws Exception { 36 Request request = new Request.Builder() 37 .url("https://publicobject.com/helloworld.txt") 38 .build(); 39 40 final ProgressListener progressListener = new ProgressListener() { 41 @Override public void update(long bytesRead, long contentLength, boolean done) { 42 System.out.println(bytesRead); 43 System.out.println(contentLength); 44 System.out.println(done); 45 System.out.format("%d%% done\n", (100 * bytesRead) / contentLength); 46 } 47 }; 48 49 client.networkInterceptors().add(new Interceptor() { 50 @Override public Response intercept(Chain chain) throws IOException { 51 Response originalResponse = chain.proceed(chain.request()); 52 return originalResponse.newBuilder() 53 .body(new ProgressResponseBody(originalResponse.body(), progressListener)) 54 .build(); 55 } 56 }); 57 58 Response response = client.newCall(request).execute(); 59 if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); 60 61 System.out.println(response.body().string()); 62 } 63 64 public static void main(String... args) throws Exception { 65 new Progress().run(); 66 } 67 68 private static class ProgressResponseBody extends ResponseBody { 69 70 private final ResponseBody responseBody; 71 private final ProgressListener progressListener; 72 private BufferedSource bufferedSource; 73 74 public ProgressResponseBody(ResponseBody responseBody, ProgressListener progressListener) { 75 this.responseBody = responseBody; 76 this.progressListener = progressListener; 77 } 78 79 @Override public MediaType contentType() { 80 return responseBody.contentType(); 81 } 82 83 @Override public long contentLength() throws IOException { 84 return responseBody.contentLength(); 85 } 86 87 @Override public BufferedSource source() throws IOException { 88 if (bufferedSource == null) { 89 bufferedSource = Okio.buffer(source(responseBody.source())); 90 } 91 return bufferedSource; 92 } 93 94 private Source source(Source source) { 95 return new ForwardingSource(source) { 96 long totalBytesRead = 0L; 97 @Override public long read(Buffer sink, long byteCount) throws IOException { 98 long bytesRead = super.read(sink, byteCount); 99 // read() returns the number of bytes read, or -1 if this source is exhausted. 100 totalBytesRead += bytesRead != -1 ? bytesRead : 0; 101 progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1); 102 return bytesRead; 103 } 104 }; 105 } 106 } 107 108 interface ProgressListener { 109 void update(long bytesRead, long contentLength, boolean done); 110 } 111 } 112