Switched HTTP library. Using OkHttp explicitly now, instead of the default Android one, which varies acroos OS versions.

OkHttp is also used as the backend for loading images (Picasso).
Added disk cache to image loading.
This commit is contained in:
Synced Synapse 2015-04-18 10:52:31 +01:00
parent ba54c3b4dc
commit 1fc9eb3301
6 changed files with 333 additions and 159 deletions

View File

@ -72,7 +72,8 @@ dependencies {
compile 'com.fasterxml.jackson.core:jackson-databind:2.4.2' compile 'com.fasterxml.jackson.core:jackson-databind:2.4.2'
compile 'com.jakewharton:butterknife:5.1.2' compile 'com.jakewharton:butterknife:5.1.2'
compile 'com.squareup.picasso:picasso:2.4.0' compile 'com.squareup.okhttp:okhttp:2.3.0'
compile 'com.squareup.picasso:picasso:2.5.2'
compile 'de.greenrobot:eventbus:2.2.1' compile 'de.greenrobot:eventbus:2.2.1'
compile 'javax.jmdns:jmdns:3.4.1' compile 'javax.jmdns:jmdns:3.4.1'
compile 'com.astuetz:pagerslidingtabstrip:1.0.1' compile 'com.astuetz:pagerslidingtabstrip:1.0.1'

View File

@ -15,6 +15,9 @@
# Picasso # Picasso
-dontwarn com.squareup.okhttp.** -dontwarn com.squareup.okhttp.**
# okio via OkHttp
-dontwarn okio.**
# Butterknife # Butterknife
-dontwarn butterknife.internal.** -dontwarn butterknife.internal.**
-keep class **$$ViewInjector { *; } -keep class **$$ViewInjector { *; }

View File

@ -21,14 +21,26 @@ import android.content.SharedPreferences;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.text.TextUtils;
import android.util.Base64;
import com.squareup.okhttp.Interceptor;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import com.squareup.picasso.OkHttpDownloader;
import com.squareup.picasso.Picasso; import com.squareup.picasso.Picasso;
import org.xbmc.kore.BuildConfig;
import org.xbmc.kore.Settings; import org.xbmc.kore.Settings;
import org.xbmc.kore.jsonrpc.HostConnection; import org.xbmc.kore.jsonrpc.HostConnection;
import org.xbmc.kore.provider.MediaContract; import org.xbmc.kore.provider.MediaContract;
import org.xbmc.kore.utils.BasicAuthPicassoDownloader; import org.xbmc.kore.utils.BasicAuthUrlConnectionDownloader;
import org.xbmc.kore.utils.LogUtils; import org.xbmc.kore.utils.LogUtils;
import org.xbmc.kore.utils.NetUtils;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
/** /**
@ -195,9 +207,40 @@ public class HostManager {
if (currentPicasso == null) { if (currentPicasso == null) {
currentHostInfo = getHostInfo(); currentHostInfo = getHostInfo();
if (currentHostInfo != null) { if (currentHostInfo != null) {
// currentPicasso = new Picasso.Builder(context)
// .downloader(new BasicAuthUrlConnectionDownloader(context,
// currentHostInfo.getUsername(), currentHostInfo.getPassword()))
// .indicatorsEnabled(BuildConfig.DEBUG)
// .build();
// Http client should already handle authentication
OkHttpClient picassoClient = getConnection().getOkHttpClient().clone();
// OkHttpClient picassoClient = new OkHttpClient();
// // Set authentication on the client
// if (!TextUtils.isEmpty(currentHostInfo.getUsername())) {
// picassoClient.interceptors().add(new Interceptor() {
// @Override
// public Response intercept(Chain chain) throws IOException {
//
// String creds = currentHostInfo.getUsername() + ":" + currentHostInfo.getPassword();
// Request newRequest = chain.request().newBuilder()
// .addHeader("Authorization",
// "Basic " + Base64.encodeToString(creds.getBytes(), Base64.NO_WRAP))
// .build();
// return chain.proceed(newRequest);
// }
// });
// }
// Set cache
File cacheDir = NetUtils.createDefaultCacheDir(context);
long cacheSize = NetUtils.calculateDiskCacheSize(cacheDir);
picassoClient.setCache(new com.squareup.okhttp.Cache(cacheDir,cacheSize));
currentPicasso = new Picasso.Builder(context) currentPicasso = new Picasso.Builder(context)
.downloader(new BasicAuthPicassoDownloader(context, .downloader(new OkHttpDownloader(picassoClient))
currentHostInfo.getUsername(), currentHostInfo.getPassword())) // .indicatorsEnabled(BuildConfig.DEBUG)
.build(); .build();
} }
} }

View File

@ -17,31 +17,36 @@ package org.xbmc.kore.jsonrpc;
import android.os.Handler; import android.os.Handler;
import android.os.Process; import android.os.Process;
import android.util.Base64; import android.text.TextUtils;
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import com.squareup.okhttp.Authenticator;
import com.squareup.okhttp.Credentials;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;
import org.xbmc.kore.host.HostInfo; import org.xbmc.kore.host.HostInfo;
import org.xbmc.kore.jsonrpc.notification.Input; import org.xbmc.kore.jsonrpc.notification.Input;
import org.xbmc.kore.jsonrpc.notification.Player; import org.xbmc.kore.jsonrpc.notification.Player;
import org.xbmc.kore.jsonrpc.notification.System; import org.xbmc.kore.jsonrpc.notification.System;
import org.xbmc.kore.utils.LogUtils; import org.xbmc.kore.utils.LogUtils;
import java.io.BufferedReader;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.ProtocolException; import java.net.Proxy;
import java.net.Socket; import java.net.Socket;
import java.net.URL;
import java.util.HashMap; import java.util.HashMap;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/** /**
* Class responsible for communicating with the host. * Class responsible for communicating with the host.
@ -140,6 +145,18 @@ public class HostConnection {
private static final int TCP_READ_TIMEOUT = 30000; // ms private static final int TCP_READ_TIMEOUT = 30000; // ms
/**
* OkHttpClient. Make sure it is initialized, by calling {@link #getOkHttpClient()}
*/
private OkHttpClient httpClient = null;
private static final MediaType MEDIA_TYPE_JSON = MediaType.parse("application/json");
/**
* Workaround for connection issues with Kodi. If we get a protocol exception,
* disable conn pooling (disable keep-alive) and try again
*/
private boolean disableConnectionPooling = false;
/** /**
* Creates a new host connection * Creates a new host connection
* @param hostInfo Host info object * @param hostInfo Host info object
@ -258,7 +275,8 @@ public class HostConnection {
public void run() { public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
if (protocol == PROTOCOL_HTTP) { if (protocol == PROTOCOL_HTTP) {
executeThroughHTTP(method, callback, handler); // executeThroughHttp(method, callback, handler);
executeThroughOkHttp(method, callback, handler);
} else { } else {
executeThroughTcp(method, callback, handler); executeThroughTcp(method, callback, handler);
} }
@ -269,60 +287,154 @@ public class HostConnection {
//new Thread(command).start(); //new Thread(command).start();
} }
/** // /**
* Sends the JSON RPC request through HTTP // * Sends the JSON RPC request through HTTP
*/ // */
private <T> void executeThroughHTTP(final ApiMethod<T> method, final ApiCallback<T> callback, // private <T> void executeThroughHttp(final ApiMethod<T> method, final ApiCallback<T> callback,
final Handler handler) { // final Handler handler) {
String jsonRequest = method.toJsonString(); // String jsonRequest = method.toJsonString();
try { // try {
HttpURLConnection connection = openHttpConnection(hostInfo); // HttpURLConnection connection = openHttpConnection(hostInfo);
sendHttpRequest(connection, jsonRequest); // sendHttpRequest(connection, jsonRequest);
// Read response and convert it // // Read response and convert it
final T result = method.resultFromJson(parseJsonResponse(readHttpResponse(connection))); // final T result = method.resultFromJson(parseJsonResponse(readHttpResponse(connection)));
//
if ((handler != null) && (callback != null)) { // if ((handler != null) && (callback != null)) {
handler.post(new Runnable() { // handler.post(new Runnable() {
@Override // @Override
public void run() { // public void run() {
callback.onSuccess(result); // callback.onSuccess(result);
} // }
}); // });
} // }
} catch (final ApiException e) { // } catch (final ApiException e) {
// Got an error, call error handler // // Got an error, call error handler
//
if ((handler != null) && (callback != null)) { // if ((handler != null) && (callback != null)) {
handler.post(new Runnable() { // handler.post(new Runnable() {
@Override // @Override
public void run() { // public void run() {
callback.onError(e.getCode(), e.getMessage()); // callback.onError(e.getCode(), e.getMessage());
} // }
}); // });
} // }
} // }
} // }
//
// /**
// * Auxiliary method to open a HTTP connection.
// * This method calls connect() so that any errors are cathced
// * @param hostInfo Host info
// * @return Connection set up
// * @throws ApiException
// */
// private HttpURLConnection openHttpConnection(HostInfo hostInfo) throws ApiException {
// try {
//// LogUtils.LOGD(TAG, "Opening HTTP connection.");
// HttpURLConnection connection = (HttpURLConnection) new URL(hostInfo.getJsonRpcHttpEndpoint()).openConnection();
// connection.setRequestMethod("POST");
// connection.setConnectTimeout(connectTimeout);
// //connection.setReadTimeout(connectTimeout);
// connection.setRequestProperty("Content-Type", "application/json");
// connection.setDoOutput(true);
//
// // http basic authorization
// if ((hostInfo.getUsername() != null) && !hostInfo.getUsername().isEmpty() &&
// (hostInfo.getPassword() != null) && !hostInfo.getPassword().isEmpty()) {
// final String token = Base64.encodeToString((hostInfo.getUsername() + ":" +
// hostInfo.getPassword()).getBytes(), Base64.DEFAULT);
// connection.setRequestProperty("Authorization", "Basic " + token);
// }
//
// // Check the connection
// connection.connect();
// return connection;
// } catch (ProtocolException e) {
// // Won't try to catch this
// LogUtils.LOGE(TAG, "Got protocol exception while opening HTTP connection.", e);
// throw new RuntimeException(e);
// } catch (IOException e) {
// LogUtils.LOGW(TAG, "Failed to open HTTP connection.", e);
// throw new ApiException(ApiException.IO_EXCEPTION_WHILE_CONNECTING, e);
// }
// }
//
// /**
// * Send an HTTP POST request
// * @param connection Open connection
// * @param request Request to send
// * @throws ApiException
// */
// private void sendHttpRequest(HttpURLConnection connection, String request) throws ApiException {
// try {
// LogUtils.LOGD(TAG, "Sending request via HTTP: " + request);
// OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream());
// out.write(request);
// out.flush();
// out.close();
// } catch (IOException e) {
// LogUtils.LOGW(TAG, "Failed to send HTTP request.", e);
// throw new ApiException(ApiException.IO_EXCEPTION_WHILE_SENDING_REQUEST, e);
// }
// }
//
// /**
// * Reads the response from the server
// * @param connection Connection
// * @return Response read
// * @throws ApiException
// */
// private String readHttpResponse(HttpURLConnection connection) throws ApiException {
// try {
//// LogUtils.LOGD(TAG, "Reading HTTP response.");
// int responseCode = connection.getResponseCode();
//
// switch (responseCode) {
// case 200:
// // All ok, read response
// BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
// StringBuilder response = new StringBuilder();
// String inputLine;
// while ((inputLine = in.readLine()) != null)
// response.append(inputLine);
// in.close();
// LogUtils.LOGD(TAG, "HTTP response: " + response.toString());
// return response.toString();
// case 401:
// LogUtils.LOGD(TAG, "HTTP response read error. Got a 401.");
// throw new ApiException(ApiException.HTTP_RESPONSE_CODE_UNAUTHORIZED,
// "Server returned response code: " + responseCode);
// case 404:
// LogUtils.LOGD(TAG, "HTTP response read error. Got a 404.");
// throw new ApiException(ApiException.HTTP_RESPONSE_CODE_NOT_FOUND,
// "Server returned response code: " + responseCode);
// default:
// LogUtils.LOGD(TAG, "HTTP response read error. Got: " + responseCode);
// throw new ApiException(ApiException.HTTP_RESPONSE_CODE_UNKNOWN,
// "Server returned response code: " + responseCode);
// }
// } catch (IOException e) {
// LogUtils.LOGW(TAG, "Failed to read HTTP response.", e);
// throw new ApiException(ApiException.IO_EXCEPTION_WHILE_READING_RESPONSE, e);
// }
// }
/** /**
* Sends the JSON RPC request through HTTP, and calls the callback with the raw response, * Sends the JSON RPC request through HTTP (using OkHttp library)
* not parsed into the internal representation.
* Useful for sync methods that don't want to incur the overhead of constructing the
* internal objects.
*
* @param method Method object that represents the method too call
* @param callback {@link ApiCallback} to post the response to. This will be the raw
* {@link ObjectNode} received
* @param handler {@link Handler} to invoke callbacks on
* @param <T> Method return type
*/ */
public <T> void executeRaw(final ApiMethod<T> method, final ApiCallback<ObjectNode> callback, private <T> void executeThroughOkHttp(final ApiMethod<T> method, final ApiCallback<T> callback,
final Handler handler) { final Handler handler) {
OkHttpClient client = getOkHttpClient();
String jsonRequest = method.toJsonString(); String jsonRequest = method.toJsonString();
try { try {
HttpURLConnection connection = openHttpConnection(hostInfo); Request request = new Request.Builder()
sendHttpRequest(connection, jsonRequest); .url(hostInfo.getJsonRpcHttpEndpoint())
// Read response and convert it .post(RequestBody.create(MEDIA_TYPE_JSON, jsonRequest))
final ObjectNode result = parseJsonResponse(readHttpResponse(connection)); .build();
Response response = sendOkHttpRequest(request);
final T result = method.resultFromJson(parseJsonResponse(handleOkHttpResponse(response)));
if ((handler != null) && (callback != null)) { if ((handler != null) && (callback != null)) {
handler.post(new Runnable() { handler.post(new Runnable() {
@ -345,107 +457,85 @@ public class HostConnection {
} }
} }
/**
* Initializes this class OkHttpClient
*/
public OkHttpClient getOkHttpClient() {
if (httpClient == null) {
httpClient = new OkHttpClient();
httpClient.setConnectTimeout(connectTimeout, TimeUnit.MILLISECONDS);
httpClient.setAuthenticator(new Authenticator() {
@Override
public Request authenticate(Proxy proxy, Response response) throws IOException {
if (TextUtils.isEmpty(hostInfo.getUsername()))
return null;
String credential = Credentials.basic(hostInfo.getUsername(), hostInfo.getPassword());
return response.request().newBuilder().header("Authorization", credential).build();
}
@Override
public Request authenticateProxy(Proxy proxy, Response response) throws IOException {
return null;
}
});
}
return httpClient;
}
/** /**
* Auxiliary method to open a HTTP connection. * Send an OkHttp POST request
* This method calls connect() so that any errors are cathced * @param request Request to send
* @param hostInfo Host info * @throws ApiException
* @return Connection set up */
* @throws ApiException private Response sendOkHttpRequest(Request request) throws ApiException {
*/ try {
private HttpURLConnection openHttpConnection(HostInfo hostInfo) throws ApiException { LogUtils.LOGD(TAG, "Sending request via OkHttp: " + request.body());
try { return httpClient.newCall(request).execute();
// LogUtils.LOGD(TAG, "Opening HTTP connection."); } catch (IOException e) {
HttpURLConnection connection = (HttpURLConnection) new URL(hostInfo.getJsonRpcHttpEndpoint()).openConnection(); LogUtils.LOGW(TAG, "Failed to send OkHttp request.", e);
connection.setRequestMethod("POST"); throw new ApiException(ApiException.IO_EXCEPTION_WHILE_SENDING_REQUEST, e);
connection.setConnectTimeout(connectTimeout); }
//connection.setReadTimeout(connectTimeout); }
connection.setRequestProperty("Content-Type", "application/json");
connection.setDoOutput(true);
// http basic authorization /**
if ((hostInfo.getUsername() != null) && !hostInfo.getUsername().isEmpty() && * Reads the response from the server
(hostInfo.getPassword() != null) && !hostInfo.getPassword().isEmpty()) { * @param response Response from OkHttp
final String token = Base64.encodeToString((hostInfo.getUsername() + ":" + * @return Response body string
hostInfo.getPassword()).getBytes(), Base64.DEFAULT); * @throws ApiException
connection.setRequestProperty("Authorization", "Basic " + token); */
} private String handleOkHttpResponse(Response response) throws ApiException {
try {
// Check the connection
connection.connect();
return connection;
} catch (ProtocolException e) {
// Won't try to catch this
LogUtils.LOGE(TAG, "Got protocol exception while opening HTTP connection.", e);
throw new RuntimeException(e);
} catch (IOException e) {
LogUtils.LOGW(TAG, "Failed to open HTTP connection.", e);
throw new ApiException(ApiException.IO_EXCEPTION_WHILE_CONNECTING, e);
}
}
/**
* Send an HTTP POST request
* @param connection Open connection
* @param request Request to send
* @throws ApiException
*/
private void sendHttpRequest(HttpURLConnection connection, String request) throws ApiException {
try {
LogUtils.LOGD(TAG, "Sending request via HTTP: " + request);
OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream());
out.write(request);
out.flush();
out.close();
} catch (IOException e) {
LogUtils.LOGW(TAG, "Failed to send HTTP request.", e);
throw new ApiException(ApiException.IO_EXCEPTION_WHILE_SENDING_REQUEST, e);
}
}
/**
* Reads the response from the server
* @param connection Connection
* @return Response read
* @throws ApiException
*/
private String readHttpResponse(HttpURLConnection connection) throws ApiException {
try {
// LogUtils.LOGD(TAG, "Reading HTTP response."); // LogUtils.LOGD(TAG, "Reading HTTP response.");
int responseCode = connection.getResponseCode(); int responseCode = response.code();
switch (responseCode) { switch (responseCode) {
case 200: case 200:
// All ok, read response // All ok, read response
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream())); String res = response.body().string();
StringBuilder response = new StringBuilder(); response.body().close();
String inputLine; return res;
while ((inputLine = in.readLine()) != null) case 401:
response.append(inputLine); LogUtils.LOGD(TAG, "HTTP response read error. Got a 401: " + response);
in.close(); throw new ApiException(ApiException.HTTP_RESPONSE_CODE_UNAUTHORIZED,
LogUtils.LOGD(TAG, "HTTP response: " + response.toString()); "Server returned response code: " + response);
return response.toString(); case 404:
case 401: LogUtils.LOGD(TAG, "HTTP response read error. Got a 404: " + response);
LogUtils.LOGD(TAG, "HTTP response read error. Got a 401."); throw new ApiException(ApiException.HTTP_RESPONSE_CODE_NOT_FOUND,
throw new ApiException(ApiException.HTTP_RESPONSE_CODE_UNAUTHORIZED, "Server returned response code: " + response);
"Server returned response code: " + responseCode); default:
case 404: LogUtils.LOGD(TAG, "HTTP response read error. Got: " + response);
LogUtils.LOGD(TAG, "HTTP response read error. Got a 404."); throw new ApiException(ApiException.HTTP_RESPONSE_CODE_UNKNOWN,
throw new ApiException(ApiException.HTTP_RESPONSE_CODE_NOT_FOUND, "Server returned response code: " + response);
"Server returned response code: " + responseCode); }
default: } catch (IOException e) {
LogUtils.LOGD(TAG, "HTTP response read error. Got: " + responseCode); LogUtils.LOGW(TAG, "Failed to read HTTP response.", e);
throw new ApiException(ApiException.HTTP_RESPONSE_CODE_UNKNOWN, throw new ApiException(ApiException.IO_EXCEPTION_WHILE_READING_RESPONSE, e);
"Server returned response code: " + responseCode); }
} }
} catch (IOException e) {
LogUtils.LOGW(TAG, "Failed to read HTTP response.", e);
throw new ApiException(ApiException.IO_EXCEPTION_WHILE_READING_RESPONSE, e);
}
}
/** /**
* Parses the JSON response from the server. * Parses the JSON response from the server.
* If it is a valid result returns the JSON {@link com.fasterxml.jackson.databind.node.ObjectNode} that represents it. * If it is a valid result returns the JSON {@link com.fasterxml.jackson.databind.node.ObjectNode} that represents it.
* If it is an error (contains the error tag), returns an {@link ApiException} with the info. * If it is an error (contains the error tag), returns an {@link ApiException} with the info.
@ -793,7 +883,7 @@ public class HostConnection {
/** /**
* Cleans up used resources. * Cleans up used resources.
* This method should always be called if the protocoll used is TCP, so we can shutdown gracefully * This method should always be called if the protocol used is TCP, so we can shutdown gracefully
*/ */
public void disconnect() { public void disconnect() {
if (protocol == PROTOCOL_HTTP) if (protocol == PROTOCOL_HTTP)

View File

@ -25,18 +25,18 @@ import java.net.HttpURLConnection;
/** /**
* Picasso Downloader that sets basic authentication in the headers * Picasso Downloader that sets basic authentication in the headers
*/ */
public class BasicAuthPicassoDownloader extends UrlConnectionDownloader { public class BasicAuthUrlConnectionDownloader extends UrlConnectionDownloader {
protected final String username; protected final String username;
protected final String password; protected final String password;
public BasicAuthPicassoDownloader(android.content.Context context) { public BasicAuthUrlConnectionDownloader(android.content.Context context) {
super(context); super(context);
this.username = null; this.username = null;
this.password = null; this.password = null;
} }
public BasicAuthPicassoDownloader(android.content.Context context, String username, String password) { public BasicAuthUrlConnectionDownloader(android.content.Context context, String username, String password) {
super(context); super(context);
this.username = username; this.username = username;
this.password = password; this.password = password;

View File

@ -15,7 +15,11 @@
*/ */
package org.xbmc.kore.utils; package org.xbmc.kore.utils;
import android.content.Context;
import android.os.StatFs;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader; import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.net.DatagramPacket; import java.net.DatagramPacket;
@ -190,4 +194,37 @@ public class NetUtils {
} }
return bytes; return bytes;
} }
/**
* Utility functions to create a cache for images, used with the picasso library
* Lifted from com.squareup.picasso.Utils
*/
private static final String APP_CACHE = "app-cache";
private static final int MIN_DISK_CACHE_SIZE = 5 * 1024 * 1024; // 5MB
private static final int MAX_DISK_CACHE_SIZE = 50 * 1024 * 1024; // 50MB
public static File createDefaultCacheDir(Context context) {
File cache = new File(context.getApplicationContext().getCacheDir(), APP_CACHE);
if (!cache.exists()) {
//noinspection ResultOfMethodCallIgnored
cache.mkdirs();
}
return cache;
}
public static long calculateDiskCacheSize(File dir) {
long size = MIN_DISK_CACHE_SIZE;
try {
StatFs statFs = new StatFs(dir.getAbsolutePath());
long available = ((long) statFs.getBlockCount()) * statFs.getBlockSize();
// Target 2% of the total space.
size = available / 50;
} catch (IllegalArgumentException ignored) {
}
// Bound inside min/max size for disk cache.
return Math.max(Math.min(size, MAX_DISK_CACHE_SIZE), MIN_DISK_CACHE_SIZE);
}
} }