@ -1,31 +1,28 @@
@@ -1,31 +1,28 @@
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.IOException ;
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 acr.browser.lightning.database.HistoryItem ;
import acr.browser.lightning.utils.FileUtils ;
import acr.browser.lightning.utils.Utils ;
import okhttp3.Cache ;
import okhttp3.CacheControl ;
import okhttp3.Interceptor ;
import okhttp3.OkHttpClient ;
import okhttp3.Request ;
import okhttp3.Response ;
@ -35,26 +32,27 @@ abstract class BaseSuggestionsModel {
@@ -35,26 +32,27 @@ abstract class BaseSuggestionsModel {
private static final String TAG = BaseSuggestionsModel . class . getSimpleName ( ) ;
static final int MAX_RESULTS = 5 ;
private static final long INTERVAL_DAY = TimeUnit . DAYS . toMilli s ( 1 ) ;
private static final long INTERVAL_DAY = TimeUnit . DAYS . toSecond s ( 1 ) ;
@NonNull private static final String DEFAULT_LANGUAGE = "en" ;
@Nullable private static String sLanguage ;
@NonNull private final Application mApplication ;
@NonNull private final OkHttpClient mHttpClient = new OkHttpClient ( ) ;
@NonNull private final OkHttpClient mHttpClient ;
@NonNull private final CacheControl mCacheControl ;
@NonNull private final ConnectivityManager mConnectivityManager ;
@NonNull
protected abstract String createQueryUrl ( @NonNull String query , @NonNull String language ) ;
protected abstract void parseResults ( @NonNull File InputStream inputStream , @NonNull List < HistoryItem > results ) throws Exception ;
protected abstract void parseResults ( @NonNull InputStream inputStream , @NonNull List < HistoryItem > results ) throws Exception ;
@NonNull
protected abstract String getEncoding ( ) ;
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 ( ) ;
mConnectivityManager = getConnectivityManager ( mApplication ) ;
}
@NonNull
@ -76,20 +74,18 @@ abstract class BaseSuggestionsModel {
@@ -76,20 +74,18 @@ abstract class BaseSuggestionsModel {
} catch ( UnsupportedEncodingException e ) {
Log . e ( TAG , "Unable to encode the URL" , e ) ;
}
File cache = downloadSuggestionsForQuery ( query , getLanguage ( ) , mApplication ) ;
if ( ! cache . exists ( ) ) {
InputStream inputStream = downloadSuggestionsForQuery ( query , getLanguage ( ) ) ;
if ( inputStream = = null ) {
// There are no suggestions for this query, return an empty list.
return filter ;
}
FileInputStream fileInput = null ;
try {
fileInput = new FileInputStream ( cache ) ;
parseResults ( fileInput , filter ) ;
parseResults ( inputStream , filter ) ;
} catch ( Exception e ) {
Log . e ( TAG , "Unable to parse results" , e ) ;
return filter ;
} finally {
Utils . close ( f ileI nput) ;
Utils . close ( inputStream ) ;
}
return filter ;
@ -102,68 +98,37 @@ abstract class BaseSuggestionsModel {
@@ -102,68 +98,37 @@ abstract class BaseSuggestionsModel {
* @param query the query to get suggestions for
* @return the cache file containing the suggestions
* /
@NonN ull
private File downloadSuggestionsForQuery ( @NonNull String query , String language , @NonNull Application app ) {
@Nullable
private InputStream downloadSuggestionsForQuery ( @NonNull String query , String 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 {
URL url = new URL ( queryUrl ) ;
// OkHttp automatically gzips requests
Request suggestionsRequest = new Request . Builder ( ) . url ( url )
. addHeader ( "Accept-Encoding" , "gzip" )
. addHeader ( "Accept-Charset" , getEncoding ( ) )
. cacheControl ( mCacheControl )
. build ( ) ;
Response suggestionsResponse = mHttpClient . newCall ( suggestionsRequest ) . execute ( ) ;
if ( suggestionsResponse . code ( ) > = HttpURLConnection . HTTP_MULT_CHOICE | |
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 ( ) ) ;
return suggestionsResponse . body ( ) . byteStream ( ) ;
} catch ( Exception e ) {
Log . w ( TAG , "Problem getting search suggestions" , e ) ;
} finally {
Utils . close ( in ) ;
Utils . close ( fos ) ;
Log . e ( TAG , "Problem getting search suggestions" , e ) ;
}
return cacheFile ;
}
private boolean isNetworkConnected ( ) {
NetworkInfo networkInfo = mConnectivityManager . getActiveNetworkInfo ( ) ;
return networkInfo ! = null & & networkInfo . isConnected ( ) ;
return null ;
}
@NonNull
private static ConnectivityManager getConnectivityManager ( @NonNull Context context ) {
return ( ConnectivityManager ) context
. getApplicationContext ( )
. getSystemService ( Context . CONNECTIVITY_SERVICE ) ;
}
private static final Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor ( ) {
@Override
public Response intercept ( Chain chain ) throws IOException {
Response originalResponse = chain . proceed ( chain . request ( ) ) ;
return originalResponse . newBuilder ( )
. header ( "cache-control" , "max-age=" + INTERVAL_DAY + ", max-stale=" + INTERVAL_DAY )
. build ( ) ;
}
} ;
}