Use built in OkHttpCache instead of manual cache
This commit is contained in:
parent
e7c5819a89
commit
ba1bad6d95
@ -1,31 +1,28 @@
|
|||||||
package acr.browser.lightning.search;
|
package acr.browser.lightning.search;
|
||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import android.content.Context;
|
|
||||||
import android.net.ConnectivityManager;
|
|
||||||
import android.net.NetworkInfo;
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.IOException;
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.zip.GZIPInputStream;
|
|
||||||
|
|
||||||
import acr.browser.lightning.database.HistoryItem;
|
import acr.browser.lightning.database.HistoryItem;
|
||||||
|
import acr.browser.lightning.utils.FileUtils;
|
||||||
import acr.browser.lightning.utils.Utils;
|
import acr.browser.lightning.utils.Utils;
|
||||||
|
import okhttp3.Cache;
|
||||||
import okhttp3.CacheControl;
|
import okhttp3.CacheControl;
|
||||||
|
import okhttp3.Interceptor;
|
||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
import okhttp3.Request;
|
import okhttp3.Request;
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
@ -35,26 +32,27 @@ abstract class BaseSuggestionsModel {
|
|||||||
private static final String TAG = BaseSuggestionsModel.class.getSimpleName();
|
private static final String TAG = BaseSuggestionsModel.class.getSimpleName();
|
||||||
|
|
||||||
static final int MAX_RESULTS = 5;
|
static final int MAX_RESULTS = 5;
|
||||||
private static final long INTERVAL_DAY = TimeUnit.DAYS.toMillis(1);
|
private static final long INTERVAL_DAY = TimeUnit.DAYS.toSeconds(1);
|
||||||
@NonNull private static final String DEFAULT_LANGUAGE = "en";
|
@NonNull private static final String DEFAULT_LANGUAGE = "en";
|
||||||
@Nullable private static String sLanguage;
|
@Nullable private static String sLanguage;
|
||||||
@NonNull private final Application mApplication;
|
@NonNull private final OkHttpClient mHttpClient;
|
||||||
@NonNull private final OkHttpClient mHttpClient = new OkHttpClient();
|
|
||||||
@NonNull private final CacheControl mCacheControl;
|
@NonNull private final CacheControl mCacheControl;
|
||||||
@NonNull private final ConnectivityManager mConnectivityManager;
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
protected abstract String createQueryUrl(@NonNull String query, @NonNull String language);
|
protected abstract String createQueryUrl(@NonNull String query, @NonNull String language);
|
||||||
|
|
||||||
protected abstract void parseResults(@NonNull FileInputStream inputStream, @NonNull List<HistoryItem> results) throws Exception;
|
protected abstract void parseResults(@NonNull InputStream inputStream, @NonNull List<HistoryItem> results) throws Exception;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
protected abstract String getEncoding();
|
protected abstract String getEncoding();
|
||||||
|
|
||||||
BaseSuggestionsModel(@NonNull Application application) {
|
BaseSuggestionsModel(@NonNull Application application) {
|
||||||
mApplication = application;
|
File suggestionsCache = new File(application.getCacheDir(), "suggestion_responses");
|
||||||
|
mHttpClient = new OkHttpClient.Builder()
|
||||||
|
.cache(new Cache(suggestionsCache, FileUtils.megabytesToBytes(1)))
|
||||||
|
.addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)
|
||||||
|
.build();
|
||||||
mCacheControl = new CacheControl.Builder().maxStale(1, TimeUnit.DAYS).build();
|
mCacheControl = new CacheControl.Builder().maxStale(1, TimeUnit.DAYS).build();
|
||||||
mConnectivityManager = getConnectivityManager(mApplication);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@ -76,20 +74,18 @@ abstract class BaseSuggestionsModel {
|
|||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
Log.e(TAG, "Unable to encode the URL", e);
|
Log.e(TAG, "Unable to encode the URL", e);
|
||||||
}
|
}
|
||||||
File cache = downloadSuggestionsForQuery(query, getLanguage(), mApplication);
|
InputStream inputStream = downloadSuggestionsForQuery(query, getLanguage());
|
||||||
if (!cache.exists()) {
|
if (inputStream == null) {
|
||||||
// There are no suggestions for this query, return an empty list.
|
// There are no suggestions for this query, return an empty list.
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
FileInputStream fileInput = null;
|
|
||||||
try {
|
try {
|
||||||
fileInput = new FileInputStream(cache);
|
parseResults(inputStream, filter);
|
||||||
parseResults(fileInput, filter);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(TAG, "Unable to parse results", e);
|
Log.e(TAG, "Unable to parse results", e);
|
||||||
return filter;
|
return filter;
|
||||||
} finally {
|
} finally {
|
||||||
Utils.close(fileInput);
|
Utils.close(inputStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
return filter;
|
return filter;
|
||||||
@ -102,68 +98,37 @@ abstract class BaseSuggestionsModel {
|
|||||||
* @param query the query to get suggestions for
|
* @param query the query to get suggestions for
|
||||||
* @return the cache file containing the suggestions
|
* @return the cache file containing the suggestions
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@Nullable
|
||||||
private File downloadSuggestionsForQuery(@NonNull String query, String language, @NonNull Application app) {
|
private InputStream downloadSuggestionsForQuery(@NonNull String query, String language) {
|
||||||
String queryUrl = createQueryUrl(query, language);
|
String queryUrl = createQueryUrl(query, language);
|
||||||
File cacheFile = new File(app.getCacheDir(), queryUrl.hashCode() + SuggestionsAdapter.CACHE_FILE_TYPE);
|
|
||||||
if (System.currentTimeMillis() - INTERVAL_DAY < cacheFile.lastModified()) {
|
|
||||||
return cacheFile;
|
|
||||||
}
|
|
||||||
if (!isNetworkConnected()) {
|
|
||||||
return cacheFile;
|
|
||||||
}
|
|
||||||
InputStream in = null;
|
|
||||||
FileOutputStream fos = null;
|
|
||||||
try {
|
try {
|
||||||
URL url = new URL(queryUrl);
|
URL url = new URL(queryUrl);
|
||||||
|
|
||||||
|
// OkHttp automatically gzips requests
|
||||||
Request suggestionsRequest = new Request.Builder().url(url)
|
Request suggestionsRequest = new Request.Builder().url(url)
|
||||||
.addHeader("Accept-Encoding", "gzip")
|
|
||||||
.addHeader("Accept-Charset", getEncoding())
|
.addHeader("Accept-Charset", getEncoding())
|
||||||
.cacheControl(mCacheControl)
|
.cacheControl(mCacheControl)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
Response suggestionsResponse = mHttpClient.newCall(suggestionsRequest).execute();
|
Response suggestionsResponse = mHttpClient.newCall(suggestionsRequest).execute();
|
||||||
|
|
||||||
if (suggestionsResponse.code() >= HttpURLConnection.HTTP_MULT_CHOICE ||
|
return suggestionsResponse.body().byteStream();
|
||||||
suggestionsResponse.code() < HttpURLConnection.HTTP_OK) {
|
|
||||||
Log.e(TAG, "Search API Responded with code: " + suggestionsResponse.code());
|
|
||||||
suggestionsResponse.body().close();
|
|
||||||
return cacheFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
in = suggestionsResponse.body().byteStream();
|
|
||||||
|
|
||||||
if (in != null) {
|
|
||||||
in = new GZIPInputStream(in);
|
|
||||||
//noinspection IOResourceOpenedButNotSafelyClosed
|
|
||||||
fos = new FileOutputStream(cacheFile);
|
|
||||||
int buffer;
|
|
||||||
while ((buffer = in.read()) != -1) {
|
|
||||||
fos.write(buffer);
|
|
||||||
}
|
|
||||||
fos.flush();
|
|
||||||
}
|
|
||||||
suggestionsResponse.body().close();
|
|
||||||
cacheFile.setLastModified(System.currentTimeMillis());
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.w(TAG, "Problem getting search suggestions", e);
|
Log.e(TAG, "Problem getting search suggestions", e);
|
||||||
} finally {
|
|
||||||
Utils.close(in);
|
|
||||||
Utils.close(fos);
|
|
||||||
}
|
}
|
||||||
return cacheFile;
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isNetworkConnected() {
|
private static final Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {
|
||||||
NetworkInfo networkInfo = mConnectivityManager.getActiveNetworkInfo();
|
@Override
|
||||||
return networkInfo != null && networkInfo.isConnected();
|
public Response intercept(Chain chain) throws IOException {
|
||||||
}
|
Response originalResponse = chain.proceed(chain.request());
|
||||||
|
return originalResponse.newBuilder()
|
||||||
@NonNull
|
.header("cache-control", "max-age=" + INTERVAL_DAY + ", max-stale=" + INTERVAL_DAY)
|
||||||
private static ConnectivityManager getConnectivityManager(@NonNull Context context) {
|
.build();
|
||||||
return (ConnectivityManager) context
|
}
|
||||||
.getApplicationContext()
|
};
|
||||||
.getSystemService(Context.CONNECTIVITY_SERVICE);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import org.json.JSONArray;
|
|||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import acr.browser.lightning.R;
|
import acr.browser.lightning.R;
|
||||||
@ -30,8 +31,8 @@ final class DuckSuggestionsModel extends BaseSuggestionsModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void parseResults(@NonNull FileInputStream inputStream, @NonNull List<HistoryItem> results) throws Exception {
|
protected void parseResults(@NonNull InputStream inputStream, @NonNull List<HistoryItem> results) throws Exception {
|
||||||
String content = FileUtils.readStringFromFile(inputStream, ENCODING);
|
String content = FileUtils.readStringFromStream(inputStream, ENCODING);
|
||||||
JSONArray jsonArray = new JSONArray(content);
|
JSONArray jsonArray = new JSONArray(content);
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
for (int n = 0, size = jsonArray.length(); n < size; n++) {
|
for (int n = 0, size = jsonArray.length(); n < size; n++) {
|
||||||
|
@ -10,6 +10,7 @@ import org.xmlpull.v1.XmlPullParserFactory;
|
|||||||
|
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import acr.browser.lightning.R;
|
import acr.browser.lightning.R;
|
||||||
@ -33,10 +34,10 @@ class GoogleSuggestionsModel extends BaseSuggestionsModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void parseResults(@NonNull FileInputStream inputStream, @NonNull List<HistoryItem> results) throws Exception {
|
protected void parseResults(@NonNull InputStream inputStream, @NonNull List<HistoryItem> results) throws Exception {
|
||||||
BufferedInputStream fileInput = new BufferedInputStream(inputStream);
|
BufferedInputStream bufferedInput = new BufferedInputStream(inputStream);
|
||||||
XmlPullParser parser = getParser();
|
XmlPullParser parser = getParser();
|
||||||
parser.setInput(fileInput, ENCODING);
|
parser.setInput(bufferedInput, ENCODING);
|
||||||
int eventType = parser.getEventType();
|
int eventType = parser.getEventType();
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
while (eventType != XmlPullParser.END_DOCUMENT) {
|
while (eventType != XmlPullParser.END_DOCUMENT) {
|
||||||
|
@ -96,6 +96,7 @@ public class SuggestionsAdapter extends BaseAdapter implements Filterable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void clearCache() {
|
public void clearCache() {
|
||||||
|
// We don't need these cache files anymore
|
||||||
Schedulers.io().execute(new ClearCacheRunnable(BrowserApp.get(mContext)));
|
Schedulers.io().execute(new ClearCacheRunnable(BrowserApp.get(mContext)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -382,12 +383,9 @@ public class SuggestionsAdapter extends BaseAdapter implements Filterable {
|
|||||||
public void run() {
|
public void run() {
|
||||||
File dir = new File(app.getCacheDir().toString());
|
File dir = new File(app.getCacheDir().toString());
|
||||||
String[] fileList = dir.list(new NameFilter());
|
String[] fileList = dir.list(new NameFilter());
|
||||||
long earliestTimeAllowed = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1);
|
|
||||||
for (String fileName : fileList) {
|
for (String fileName : fileList) {
|
||||||
File file = new File(dir.getPath() + fileName);
|
File file = new File(dir.getPath() + fileName);
|
||||||
if (earliestTimeAllowed > file.lastModified()) {
|
file.delete();
|
||||||
file.delete();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,7 +138,8 @@ public class FileUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static String readStringFromFile(@NonNull InputStream inputStream, @NonNull String encoding) throws IOException {
|
public static String readStringFromStream(@NonNull InputStream inputStream,
|
||||||
|
@NonNull String encoding) throws IOException {
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, encoding));
|
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, encoding));
|
||||||
StringBuilder result = new StringBuilder();
|
StringBuilder result = new StringBuilder();
|
||||||
String line;
|
String line;
|
||||||
@ -148,4 +149,14 @@ public class FileUtils {
|
|||||||
return result.toString();
|
return result.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts megabytes to bytes.
|
||||||
|
*
|
||||||
|
* @param megaBytes the number of megabytes.
|
||||||
|
* @return the converted bytes.
|
||||||
|
*/
|
||||||
|
public static long megabytesToBytes(long megaBytes) {
|
||||||
|
return megaBytes * 1024 * 1024;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user