Browse Source

Cleaning up suggestions model code

master
anthony restaino 8 years ago
parent
commit
e7c5819a89
  1. 33
      app/src/main/java/acr/browser/lightning/search/BaseSuggestionsModel.java
  2. 8
      app/src/main/java/acr/browser/lightning/search/DuckSuggestionsModel.java
  3. 8
      app/src/main/java/acr/browser/lightning/search/GoogleSuggestionsModel.java
  4. 66
      app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java
  5. 47
      app/src/main/java/acr/browser/lightning/search/SuggestionsManager.java
  6. 21
      app/src/main/java/acr/browser/lightning/search/SuggestionsResult.java

33
app/src/main/java/acr/browser/lightning/search/BaseSuggestionsTask.java → app/src/main/java/acr/browser/lightning/search/BaseSuggestionsModel.java

@ -30,20 +30,18 @@ import okhttp3.OkHttpClient;
import okhttp3.Request; import okhttp3.Request;
import okhttp3.Response; import okhttp3.Response;
abstract class BaseSuggestionsTask { abstract class BaseSuggestionsModel {
private static final String TAG = BaseSuggestionsTask.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.toMillis(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 SuggestionsResult mResultCallback;
@NonNull private final Application mApplication; @NonNull private final Application mApplication;
@NonNull private final OkHttpClient mHttpClient = new OkHttpClient(); @NonNull private final OkHttpClient mHttpClient = new OkHttpClient();
@NonNull private final CacheControl mCacheControl; @NonNull private final CacheControl mCacheControl;
@NonNull private final ConnectivityManager mConnectivityManager; @NonNull private final ConnectivityManager mConnectivityManager;
@NonNull private String mQuery;
@NonNull @NonNull
protected abstract String createQueryUrl(@NonNull String query, @NonNull String language); protected abstract String createQueryUrl(@NonNull String query, @NonNull String language);
@ -53,11 +51,7 @@ abstract class BaseSuggestionsTask {
@NonNull @NonNull
protected abstract String getEncoding(); protected abstract String getEncoding();
BaseSuggestionsTask(@NonNull String query, BaseSuggestionsModel(@NonNull Application application) {
@NonNull Application application,
@NonNull SuggestionsResult callback) {
mQuery = query;
mResultCallback = callback;
mApplication = application; mApplication = application;
mCacheControl = new CacheControl.Builder().maxStale(1, TimeUnit.DAYS).build(); mCacheControl = new CacheControl.Builder().maxStale(1, TimeUnit.DAYS).build();
mConnectivityManager = getConnectivityManager(mApplication); mConnectivityManager = getConnectivityManager(mApplication);
@ -74,39 +68,36 @@ abstract class BaseSuggestionsTask {
return sLanguage; return sLanguage;
} }
void run() { @NonNull
List<HistoryItem> getResults(@NonNull String query) {
List<HistoryItem> filter = new ArrayList<>(5); List<HistoryItem> filter = new ArrayList<>(5);
try { try {
mQuery = URLEncoder.encode(mQuery, getEncoding()); query = URLEncoder.encode(query, getEncoding());
} 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(mQuery, getLanguage(), mApplication); File cache = downloadSuggestionsForQuery(query, getLanguage(), mApplication);
if (!cache.exists()) { if (!cache.exists()) {
post(filter); // There are no suggestions for this query, return an empty list.
return; return filter;
} }
FileInputStream fileInput = null; FileInputStream fileInput = null;
try { try {
fileInput = new FileInputStream(cache); fileInput = new FileInputStream(cache);
parseResults(fileInput, filter); parseResults(fileInput, filter);
} catch (Exception e) { } catch (Exception e) {
post(filter);
Log.e(TAG, "Unable to parse results", e); Log.e(TAG, "Unable to parse results", e);
return; return filter;
} finally { } finally {
Utils.close(fileInput); Utils.close(fileInput);
} }
post(filter);
}
private void post(@NonNull List<HistoryItem> result) { return filter;
mResultCallback.resultReceived(result);
} }
/** /**
* This method downloads the search suggestions for the specific query. * This method downloads the search suggestions for the specific query.
* NOTE: This is a blocking operation, do not run on the UI thread. * NOTE: This is a blocking operation, do not getResults on the UI thread.
* *
* @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

8
app/src/main/java/acr/browser/lightning/search/DuckSuggestionsTask.java → app/src/main/java/acr/browser/lightning/search/DuckSuggestionsModel.java

@ -13,15 +13,13 @@ import acr.browser.lightning.R;
import acr.browser.lightning.database.HistoryItem; import acr.browser.lightning.database.HistoryItem;
import acr.browser.lightning.utils.FileUtils; import acr.browser.lightning.utils.FileUtils;
final class DuckSuggestionsTask extends BaseSuggestionsTask { final class DuckSuggestionsModel extends BaseSuggestionsModel {
@NonNull private static final String ENCODING = "UTF-8"; @NonNull private static final String ENCODING = "UTF-8";
@NonNull private final String mSearchSubtitle; @NonNull private final String mSearchSubtitle;
DuckSuggestionsTask(@NonNull String query, DuckSuggestionsModel(@NonNull Application application) {
@NonNull Application application, super(application);
@NonNull SuggestionsResult callback) {
super(query, application, callback);
mSearchSubtitle = application.getString(R.string.suggestion); mSearchSubtitle = application.getString(R.string.suggestion);
} }

8
app/src/main/java/acr/browser/lightning/search/GoogleSuggestionsTask.java → app/src/main/java/acr/browser/lightning/search/GoogleSuggestionsModel.java

@ -15,16 +15,14 @@ import java.util.List;
import acr.browser.lightning.R; import acr.browser.lightning.R;
import acr.browser.lightning.database.HistoryItem; import acr.browser.lightning.database.HistoryItem;
class GoogleSuggestionsTask extends BaseSuggestionsTask { class GoogleSuggestionsModel extends BaseSuggestionsModel {
@NonNull private static final String ENCODING = "ISO-8859-1"; @NonNull private static final String ENCODING = "ISO-8859-1";
@Nullable private static XmlPullParser sXpp; @Nullable private static XmlPullParser sXpp;
@NonNull private final String mSearchSubtitle; @NonNull private final String mSearchSubtitle;
GoogleSuggestionsTask(@NonNull String query, GoogleSuggestionsModel(@NonNull Application application) {
@NonNull Application application, super(application);
@NonNull SuggestionsResult callback) {
super(query, application, callback);
mSearchSubtitle = application.getString(R.string.suggestion); mSearchSubtitle = application.getString(R.string.suggestion);
} }

66
app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java

@ -210,8 +210,8 @@ public class SuggestionsAdapter extends BaseAdapter implements Filterable {
subscriber.onComplete(); subscriber.onComplete();
} }
}).subscribeOn(FILTER_SCHEDULER) }).subscribeOn(FILTER_SCHEDULER)
.observeOn(Schedulers.main()) .observeOn(Schedulers.main())
.subscribe(); .subscribe();
} }
private void combineResults(final @Nullable List<HistoryItem> bookmarkList, private void combineResults(final @Nullable List<HistoryItem> bookmarkList,
@ -256,13 +256,13 @@ public class SuggestionsAdapter extends BaseAdapter implements Filterable {
subscriber.onComplete(); subscriber.onComplete();
} }
}).subscribeOn(FILTER_SCHEDULER) }).subscribeOn(FILTER_SCHEDULER)
.observeOn(Schedulers.main()) .observeOn(Schedulers.main())
.subscribe(new SingleOnSubscribe<List<HistoryItem>>() { .subscribe(new SingleOnSubscribe<List<HistoryItem>>() {
@Override @Override
public void onItem(@Nullable List<HistoryItem> item) { public void onItem(@Nullable List<HistoryItem> item) {
publishResults(item); publishResults(item);
} }
}); });
} }
@NonNull @NonNull
@ -277,7 +277,7 @@ public class SuggestionsAdapter extends BaseAdapter implements Filterable {
break; break;
} }
if (mAllBookmarks.get(n).getTitle().toLowerCase(Locale.getDefault()) if (mAllBookmarks.get(n).getTitle().toLowerCase(Locale.getDefault())
.startsWith(query)) { .startsWith(query)) {
bookmarks.add(mAllBookmarks.get(n)); bookmarks.add(mAllBookmarks.get(n));
counter++; counter++;
} else if (mAllBookmarks.get(n).getUrl().contains(query)) { } else if (mAllBookmarks.get(n).getUrl().contains(query)) {
@ -294,9 +294,9 @@ public class SuggestionsAdapter extends BaseAdapter implements Filterable {
@NonNull @NonNull
private Single<List<HistoryItem>> getSuggestionsForQuery(@NonNull final String query) { private Single<List<HistoryItem>> getSuggestionsForQuery(@NonNull final String query) {
if (mSuggestionChoice == PreferenceManager.Suggestion.SUGGESTION_GOOGLE) { if (mSuggestionChoice == PreferenceManager.Suggestion.SUGGESTION_GOOGLE) {
return SuggestionsManager.getObservable(query, mContext, SuggestionsManager.Source.GOOGLE); return SuggestionsManager.createGoogleQueryObservable(query, mContext);
} else if (mSuggestionChoice == PreferenceManager.Suggestion.SUGGESTION_DUCK) { } else if (mSuggestionChoice == PreferenceManager.Suggestion.SUGGESTION_DUCK) {
return SuggestionsManager.getObservable(query, mContext, SuggestionsManager.Source.DUCK); return SuggestionsManager.createDuckQueryObservable(query, mContext);
} else { } else {
return Single.empty(); return Single.empty();
} }
@ -325,35 +325,35 @@ public class SuggestionsAdapter extends BaseAdapter implements Filterable {
if (mSuggestionsAdapter.shouldRequestNetwork() && !SuggestionsManager.isRequestInProgress()) { if (mSuggestionsAdapter.shouldRequestNetwork() && !SuggestionsManager.isRequestInProgress()) {
mSuggestionsAdapter.getSuggestionsForQuery(query) mSuggestionsAdapter.getSuggestionsForQuery(query)
.subscribeOn(Schedulers.worker()) .subscribeOn(Schedulers.worker())
.observeOn(Schedulers.main())
.subscribe(new SingleOnSubscribe<List<HistoryItem>>() {
@Override
public void onItem(@Nullable List<HistoryItem> item) {
mSuggestionsAdapter.combineResults(null, null, item);
}
});
}
mSuggestionsAdapter.getBookmarksForQuery(query)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.main()) .observeOn(Schedulers.main())
.subscribe(new SingleOnSubscribe<List<HistoryItem>>() { .subscribe(new SingleOnSubscribe<List<HistoryItem>>() {
@Override @Override
public void onItem(@Nullable List<HistoryItem> item) { public void onItem(@Nullable List<HistoryItem> item) {
mSuggestionsAdapter.combineResults(item, null, null); mSuggestionsAdapter.combineResults(null, null, item);
} }
}); });
}
mSuggestionsAdapter.getBookmarksForQuery(query)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.main())
.subscribe(new SingleOnSubscribe<List<HistoryItem>>() {
@Override
public void onItem(@Nullable List<HistoryItem> item) {
mSuggestionsAdapter.combineResults(item, null, null);
}
});
HistoryModel.findHistoryItemsContaining(query) HistoryModel.findHistoryItemsContaining(query)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(Schedulers.main()) .observeOn(Schedulers.main())
.subscribe(new SingleOnSubscribe<List<HistoryItem>>() { .subscribe(new SingleOnSubscribe<List<HistoryItem>>() {
@Override @Override
public void onItem(@Nullable List<HistoryItem> item) { public void onItem(@Nullable List<HistoryItem> item) {
mSuggestionsAdapter.combineResults(null, item, null); mSuggestionsAdapter.combineResults(null, item, null);
} }
}); });
results.count = 1; results.count = 1;
return results; return results;
} }

47
app/src/main/java/acr/browser/lightning/search/SuggestionsManager.java

@ -15,42 +15,39 @@ import acr.browser.lightning.database.HistoryItem;
class SuggestionsManager { class SuggestionsManager {
public enum Source {
GOOGLE,
DUCK
}
private static volatile boolean sIsTaskExecuting; private static volatile boolean sIsTaskExecuting;
static boolean isRequestInProgress() { static boolean isRequestInProgress() {
return sIsTaskExecuting; return sIsTaskExecuting;
} }
static Single<List<HistoryItem>> getObservable(@NonNull final String query, @NonNull final Context context, @NonNull final Source source) { @NonNull
static Single<List<HistoryItem>> createGoogleQueryObservable(@NonNull final String query,
@NonNull final Context context) {
final Application application = BrowserApp.get(context);
return Single.create(new SingleAction<List<HistoryItem>>() {
@Override
public void onSubscribe(@NonNull final SingleSubscriber<List<HistoryItem>> subscriber) {
sIsTaskExecuting = true;
List<HistoryItem> results = new GoogleSuggestionsModel(application).getResults(query);
subscriber.onItem(results);
subscriber.onComplete();
sIsTaskExecuting = false;
}
});
}
@NonNull
static Single<List<HistoryItem>> createDuckQueryObservable(@NonNull final String query,
@NonNull final Context context) {
final Application application = BrowserApp.get(context); final Application application = BrowserApp.get(context);
return Single.create(new SingleAction<List<HistoryItem>>() { return Single.create(new SingleAction<List<HistoryItem>>() {
@Override @Override
public void onSubscribe(@NonNull final SingleSubscriber<List<HistoryItem>> subscriber) { public void onSubscribe(@NonNull final SingleSubscriber<List<HistoryItem>> subscriber) {
sIsTaskExecuting = true; sIsTaskExecuting = true;
switch (source) { List<HistoryItem> results = new DuckSuggestionsModel(application).getResults(query);
case GOOGLE: subscriber.onItem(results);
new GoogleSuggestionsTask(query, application, new SuggestionsResult() { subscriber.onComplete();
@Override
public void resultReceived(@NonNull List<HistoryItem> searchResults) {
subscriber.onItem(searchResults);
subscriber.onComplete();
}
}).run();
break;
case DUCK:
new DuckSuggestionsTask(query, application, new SuggestionsResult() {
@Override
public void resultReceived(@NonNull List<HistoryItem> searchResults) {
subscriber.onItem(searchResults);
subscriber.onComplete();
}
}).run();
}
sIsTaskExecuting = false; sIsTaskExecuting = false;
} }
}); });

21
app/src/main/java/acr/browser/lightning/search/SuggestionsResult.java

@ -1,21 +0,0 @@
package acr.browser.lightning.search;
import android.support.annotation.NonNull;
import java.util.List;
import acr.browser.lightning.database.HistoryItem;
interface SuggestionsResult {
/**
* Called when the search suggestions have
* been retrieved from the server.
*
* @param searchResults the results, a valid
* list of results. May
* be empty.
*/
void resultReceived(@NonNull List<HistoryItem> searchResults);
}
Loading…
Cancel
Save