You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
169 lines
5.8 KiB
169 lines
5.8 KiB
package acr.browser.lightning.search; |
|
|
|
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.Nullable; |
|
import android.text.TextUtils; |
|
import android.util.Log; |
|
|
|
import java.io.File; |
|
import java.io.FileInputStream; |
|
import java.io.FileOutputStream; |
|
import java.io.InputStream; |
|
import java.io.UnsupportedEncodingException; |
|
import java.net.HttpURLConnection; |
|
import java.net.URL; |
|
import java.net.URLEncoder; |
|
import java.util.ArrayList; |
|
import java.util.List; |
|
import java.util.Locale; |
|
import java.util.concurrent.TimeUnit; |
|
import java.util.zip.GZIPInputStream; |
|
|
|
import javax.net.ssl.HttpsURLConnection; |
|
|
|
import acr.browser.lightning.database.HistoryItem; |
|
import acr.browser.lightning.utils.Utils; |
|
|
|
abstract class BaseSuggestionsTask { |
|
|
|
private static final String TAG = BaseSuggestionsTask.class.getSimpleName(); |
|
|
|
private static final long INTERVAL_DAY = TimeUnit.DAYS.toMillis(1); |
|
private static final String DEFAULT_LANGUAGE = "en"; |
|
@Nullable private static String sLanguage; |
|
@NonNull private final SuggestionsResult mResultCallback; |
|
@NonNull private final Application mApplication; |
|
@NonNull private String mQuery; |
|
|
|
protected abstract String getQueryUrl(@NonNull String query, @NonNull String language); |
|
|
|
protected abstract void parseResults(FileInputStream inputStream, List<HistoryItem> results) throws Exception; |
|
|
|
protected abstract String getEncoding(); |
|
|
|
BaseSuggestionsTask(@NonNull String query, |
|
@NonNull Application application, |
|
@NonNull SuggestionsResult callback) { |
|
mQuery = query; |
|
mResultCallback = callback; |
|
mApplication = application; |
|
} |
|
|
|
@NonNull |
|
private static synchronized String getLanguage() { |
|
if (sLanguage == null) { |
|
sLanguage = Locale.getDefault().getLanguage(); |
|
} |
|
if (TextUtils.isEmpty(sLanguage)) { |
|
sLanguage = DEFAULT_LANGUAGE; |
|
} |
|
return sLanguage; |
|
} |
|
|
|
void run() { |
|
List<HistoryItem> filter = new ArrayList<>(5); |
|
try { |
|
mQuery = URLEncoder.encode(mQuery, getEncoding()); |
|
} catch (UnsupportedEncodingException e) { |
|
Log.e(TAG, "Unable to encode the URL", e); |
|
} |
|
File cache = downloadSuggestionsForQuery(mQuery, getLanguage(), mApplication); |
|
if (!cache.exists()) { |
|
post(filter); |
|
return; |
|
} |
|
FileInputStream fileInput = null; |
|
try { |
|
fileInput = new FileInputStream(cache); |
|
parseResults(fileInput, filter); |
|
} catch (Exception e) { |
|
post(filter); |
|
Log.e(TAG, "Unable to parse results", e); |
|
return; |
|
} finally { |
|
Utils.close(fileInput); |
|
} |
|
post(filter); |
|
} |
|
|
|
private void post(@NonNull List<HistoryItem> result) { |
|
mResultCallback.resultReceived(result); |
|
} |
|
|
|
/** |
|
* This method downloads the search suggestions for the specific query. |
|
* NOTE: This is a blocking operation, do not run on the UI thread. |
|
* |
|
* @param query the query to get suggestions for |
|
* @return the cache file containing the suggestions |
|
*/ |
|
@NonNull |
|
private File downloadSuggestionsForQuery(@NonNull String query, String language, @NonNull Application app) { |
|
String queryUrl = getQueryUrl(query, language); |
|
File cacheFile = new File(app.getCacheDir(), queryUrl.hashCode() + Suggestions.CACHE_FILE_TYPE); |
|
if (System.currentTimeMillis() - INTERVAL_DAY < cacheFile.lastModified()) { |
|
return cacheFile; |
|
} |
|
if (!isNetworkConnected(app)) { |
|
return cacheFile; |
|
} |
|
InputStream in = null; |
|
FileOutputStream fos = null; |
|
try { |
|
URL url = new URL(queryUrl); |
|
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); |
|
connection.setDoInput(true); |
|
connection.setRequestProperty("Accept-Encoding", "gzip"); |
|
connection.setRequestProperty("Accept-Charset", getEncoding()); |
|
connection.connect(); |
|
if (connection.getResponseCode() >= HttpURLConnection.HTTP_MULT_CHOICE || |
|
connection.getResponseCode() < HttpURLConnection.HTTP_OK) { |
|
Log.e(TAG, "Search API Responded with code: " + connection.getResponseCode()); |
|
connection.disconnect(); |
|
return cacheFile; |
|
} |
|
|
|
in = connection.getInputStream(); |
|
|
|
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(); |
|
} |
|
connection.disconnect(); |
|
cacheFile.setLastModified(System.currentTimeMillis()); |
|
} catch (Exception e) { |
|
Log.w(TAG, "Problem getting search suggestions", e); |
|
} finally { |
|
Utils.close(in); |
|
Utils.close(fos); |
|
} |
|
return cacheFile; |
|
} |
|
|
|
private static boolean isNetworkConnected(@NonNull Context context) { |
|
NetworkInfo networkInfo = getActiveNetworkInfo(context); |
|
return networkInfo != null && networkInfo.isConnected(); |
|
} |
|
|
|
@Nullable |
|
private static NetworkInfo getActiveNetworkInfo(@NonNull Context context) { |
|
ConnectivityManager connectivity = (ConnectivityManager) context |
|
.getApplicationContext() |
|
.getSystemService(Context.CONNECTIVITY_SERVICE); |
|
if (connectivity == null) { |
|
return null; |
|
} |
|
return connectivity.getActiveNetworkInfo(); |
|
} |
|
|
|
}
|
|
|