Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for bookmarks and history in the awesome bar #1425

Merged
merged 2 commits into from
Jul 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.vrbrowser.browser

import android.content.Context
import android.os.Handler
import android.os.Looper
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.future.future
import mozilla.components.concept.storage.VisitType
import org.mozilla.vrbrowser.VRBrowserApplication
import java.util.concurrent.CompletableFuture

class HistoryStore constructor(val context: Context) {
private var listeners = ArrayList<HistoryListener>()
private val storage = (context.applicationContext as VRBrowserApplication).places.history

interface HistoryListener {
fun onHistoryUpdated()
}

fun addListener(aListener: HistoryListener) {
if (!listeners.contains(aListener)) {
listeners.add(aListener)
}
}

fun removeListener(aListener: HistoryListener) {
listeners.remove(aListener)
}

fun removeAllListeners() {
listeners.clear()
}

fun getHistory(): CompletableFuture<List<String>?> = GlobalScope.future {
storage.getVisited()
}

fun addHistory(aURL: String, visitType: VisitType) = GlobalScope.future {
storage.recordVisit(aURL, visitType)
notifyListeners()
}

fun deleteHistory(aUrl: String, timestamp: Long) = GlobalScope.future {
storage.deleteVisit(aUrl, timestamp)
notifyListeners()
}

fun isInHistory(aURL: String): CompletableFuture<Boolean> = GlobalScope.future {
storage.getVisited(listOf(aURL)) != null
}

private fun notifyListeners() {
if (listeners.size > 0) {
val listenersCopy = ArrayList(listeners)
Handler(Looper.getMainLooper()).post {
for (listener in listenersCopy) {
listener.onHistoryUpdated()
}
}
}
}
}

2 changes: 2 additions & 0 deletions app/src/common/shared/org/mozilla/vrbrowser/browser/Places.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ package org.mozilla.vrbrowser.browser

import android.content.Context
import mozilla.components.browser.storage.sync.PlacesBookmarksStorage
import mozilla.components.browser.storage.sync.PlacesHistoryStorage

/**
* Entry point for interacting with places-backed storage layers.
*/
class Places(context: Context) {
val bookmarks by lazy { PlacesBookmarksStorage(context) }
val history by lazy { PlacesHistoryStorage(context) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import mozilla.components.concept.storage.VisitType;

import static org.mozilla.vrbrowser.utils.ServoUtils.createServoSession;
import static org.mozilla.vrbrowser.utils.ServoUtils.isInstanceOfServoSession;
import static org.mozilla.vrbrowser.utils.ServoUtils.isServoAvailable;
Expand Down Expand Up @@ -134,6 +136,7 @@ class State {
private Context mContext;
private SharedPreferences mPrefs;
private BookmarksStore mBookmarksStore;
private HistoryStore mHistoryStore;

private SessionStore() {
mSessions = new LinkedHashMap<>();
Expand Down Expand Up @@ -170,6 +173,9 @@ public void unregisterListeners() {
if (mBookmarksStore != null) {
mBookmarksStore.removeAllListeners();
}
if (mHistoryStore!= null) {
mHistoryStore.removeAllListeners();
}
}

public void setContext(Context aContext, Bundle aExtras) {
Expand Down Expand Up @@ -208,6 +214,7 @@ public void setContext(Context aContext, Bundle aExtras) {
mContext = aContext;
mPrefs = PreferenceManager.getDefaultSharedPreferences(mContext);
mBookmarksStore = new BookmarksStore(mContext);
mHistoryStore = new HistoryStore(mContext);
if (mUserAgentOverride == null) {
mUserAgentOverride = new UserAgentOverride();
mUserAgentOverride.loadOverridesFromAssets((Activity)aContext, aContext.getString(R.string.user_agent_override_file));
Expand All @@ -218,6 +225,10 @@ public BookmarksStore getBookmarkStore() {
return mBookmarksStore;
}

public HistoryStore getHistoryStore() {
return mHistoryStore;
}

public void dumpAllState(Integer sessionId) {
dumpAllState(getSession(sessionId));
}
Expand Down Expand Up @@ -1045,6 +1056,11 @@ public void onCanGoForward(@NonNull GeckoSession aSession, boolean aCanGoForward

@Override
public @Nullable GeckoResult<AllowOrDeny> onLoadRequest(@NonNull GeckoSession aSession, @NonNull LoadRequest aRequest) {
if (aRequest.isRedirect)
mHistoryStore.addHistory(aRequest.uri, VisitType.EMBED);
else if (aRequest.triggerUri != null)
mHistoryStore.addHistory(aRequest.uri, VisitType.LINK);

final GeckoResult<AllowOrDeny> result = new GeckoResult<>();

String uri = aRequest.uri;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Handler;
import android.preference.PreferenceManager;

import androidx.annotation.NonNull;

import org.mozilla.vrbrowser.R;
import org.mozilla.vrbrowser.browser.SettingsStore;
import org.mozilla.vrbrowser.geolocation.GeolocationData;
Expand All @@ -19,8 +22,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import androidx.annotation.NonNull;
import java.util.concurrent.CompletableFuture;

import kotlinx.coroutines.Dispatchers;
import mozilla.components.browser.search.SearchEngine;
Expand Down Expand Up @@ -102,13 +104,14 @@ private String getSuggestionURL(String aQuery) {
return mSearchEngine.buildSuggestionsURL(aQuery);
}

public void getSuggestions(String aQuery, SuggestionsDelegate delegate) {
public CompletableFuture<List<String>> getSuggestions(String aQuery) {
CompletableFuture<List<String>> future = new CompletableFuture<>();
// TODO: Use mSuggestionsClient.getSuggestions when fixed in browser-search.
bluemarvin marked this conversation as resolved.
Show resolved Hide resolved
String query = getSuggestionURL(aQuery);
SuggestionsClient.getSuggestions(mSearchEngine, query, result -> {
delegate.OnSuggestions(result);
return null;
});
new Handler(mContext.getMainLooper()).post(() ->
SuggestionsClient.getSuggestions(mSearchEngine, query).thenAcceptAsync((result) -> future.complete(result)));

return future;
}

public String getResourceURL() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import com.loopj.android.http.TextHttpResponseHandler;

import java.util.List;
import java.util.function.Function;
import java.util.concurrent.CompletableFuture;

import cz.msebera.android.httpclient.Header;
import mozilla.components.browser.search.SearchEngine;
Expand All @@ -13,17 +13,21 @@ public class SuggestionsClient {

private static AsyncHttpClient client = new AsyncHttpClient();

public static void getSuggestions(SearchEngine mEngine, String aQuery, Function<List<String>, Void> callback) {
public static CompletableFuture<List<String>> getSuggestions(SearchEngine mEngine, String aQuery) {
final CompletableFuture future = new CompletableFuture();
client.cancelAllRequests(true);
client.get(aQuery, null, new TextHttpResponseHandler("ISO-8859-1") {
@Override
public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
future.completeExceptionally(throwable);
}

@Override
public void onSuccess(int statusCode, Header[] headers, String responseString) {
callback.apply(SuggestionParser.selectResponseParser(mEngine).apply(responseString));
future.complete(SuggestionParser.selectResponseParser(mEngine).apply(responseString));
}
});

return future;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
package org.mozilla.vrbrowser.search.suggestions;

import android.content.Context;

import androidx.annotation.NonNull;

import org.mozilla.vrbrowser.browser.SessionStore;
import org.mozilla.vrbrowser.search.SearchEngineWrapper;
import org.mozilla.vrbrowser.ui.widgets.SuggestionsWidget.SuggestionItem;
import org.mozilla.vrbrowser.ui.widgets.SuggestionsWidget.SuggestionItem.Type;
import org.mozilla.vrbrowser.utils.UrlUtils;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.CompletableFuture;

public class SuggestionsProvider {

public class DefaultSuggestionsComparator implements Comparator {

public int compare(Object obj1, Object obj2) {
SuggestionItem suggestion1 = (SuggestionItem)obj1;
SuggestionItem suggestion2 = (SuggestionItem)obj2;
if (suggestion1.type == Type.SUGGESTION && suggestion2.type == Type.SUGGESTION) {
return 0;

} else if (suggestion1.type == suggestion2.type) {
if (mFilterText != null) {
if (suggestion1.title != null && suggestion2.title != null)
return suggestion1.title.toLowerCase().indexOf(mFilterText) - suggestion2.title.toLowerCase().indexOf(mFilterText);
return suggestion1.url.toLowerCase().indexOf(mFilterText) - suggestion2.url.indexOf(mFilterText);

} else {
return suggestion1.url.compareTo(suggestion2.url);
}

} else {
return suggestion1.type.ordinal() - suggestion2.type.ordinal();
}
}
}

private Context mContext;
private SearchEngineWrapper mSearchEngineWrapper;
private String mText;
private String mFilterText;
private Comparator mComparator;

public SuggestionsProvider(Context context) {
mContext = context;
mSearchEngineWrapper = SearchEngineWrapper.get(mContext);
mFilterText = "";
mComparator = new DefaultSuggestionsComparator();
}

private String getSearchURLOrDomain(String text) {
if (UrlUtils.isDomain(text)) {
return text;

} else {
return mSearchEngineWrapper.getSearchURL(text);
}
}

public void setFilterText(String text) {
mFilterText = text.toLowerCase();
}

public void setText(String text) { mText = text; }

public void setComparator(Comparator comparator) {
mComparator = comparator;
}

public CompletableFuture<List<SuggestionItem>> getBookmarkSuggestions(@NonNull List<SuggestionItem> items) {
CompletableFuture future = new CompletableFuture();
SessionStore.get().getBookmarkStore().getBookmarks().thenAcceptAsync((bookmarks) -> {
bookmarks.stream().
filter(b -> b.getUrl().toLowerCase().contains(mFilterText) ||
b.getTitle().toLowerCase().contains(mFilterText))
.forEach(b -> items.add(SuggestionItem.create(
b.getTitle(),
b.getUrl(),
null,
Type.BOOKMARK
)));
if (mComparator != null)
items.sort(mComparator);
future.complete(items);
});

return future;
}

public CompletableFuture<List<SuggestionItem>> getHistorySuggestions(@NonNull final List<SuggestionItem> items) {
CompletableFuture future = new CompletableFuture();
SessionStore.get().getHistoryStore().getHistory().thenAcceptAsync((history) -> {
history.stream()
.filter(h ->
h.toLowerCase().contains(mFilterText))
.forEach(h -> items.add(SuggestionItem.create(
h,
h,
null,
Type.HISTORY
)));
if (mComparator != null)
items.sort(mComparator);
future.complete(items);
});

return future;
}

public CompletableFuture<List<SuggestionItem>> getSearchEngineSuggestions(@NonNull final List<SuggestionItem> items) {
CompletableFuture future = new CompletableFuture();

// Completion from browser-domains
if (!mText.equals(mFilterText)) {
items.add(SuggestionItem.create(
mText,
getSearchURLOrDomain(mText),
null,
Type.COMPLETION
));
}

// Original text
items.add(SuggestionItem.create(
mFilterText,
getSearchURLOrDomain(mFilterText),
null,
Type.SUGGESTION
));

// Suggestions
mSearchEngineWrapper.getSuggestions(mFilterText).thenAcceptAsync((suggestions) -> {
suggestions.forEach(s -> {
String url = mSearchEngineWrapper.getSearchURL(s);
items.add(SuggestionItem.create(
s,
url,
null,
Type.SUGGESTION
));
});
if (mComparator != null)
items.sort(mComparator);
future.complete(items);
});

return future;
}

public CompletableFuture<List<SuggestionItem>> getSuggestions() {
return CompletableFuture.supplyAsync(() -> new ArrayList<SuggestionItem>())
.thenComposeAsync(this::getSearchEngineSuggestions)
.thenComposeAsync(this::getBookmarkSuggestions)
.thenComposeAsync(this::getHistorySuggestions);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import androidx.databinding.DataBindingUtil;

import mozilla.components.concept.storage.BookmarkNode;
import mozilla.components.concept.storage.VisitType;

public class BookmarksView extends FrameLayout implements GeckoSession.NavigationDelegate, BookmarksStore.BookmarkListener {

Expand Down Expand Up @@ -103,6 +104,7 @@ public void onClick(BookmarkNode bookmark) {
mAudio.playSound(AudioEngine.Sound.CLICK);
}

SessionStore.get().getHistoryStore().addHistory(bookmark.getUrl(), VisitType.BOOKMARK);
SessionStore.get().loadUri(bookmark.getUrl());
}

Expand Down