Skip to content
This repository was archived by the owner on Jul 22, 2024. It is now read-only.

Commit ede1763

Browse files
keianhzoMortimerGoro
authored andcommitted
Hamburger menu (#2071)
* Hamburger menu * Updated the menu icon tooltip * Show sent tab notification after sending a tab * Keep the devices list always synced * Handle devices list when not signed it * Override user agent for accounts.firefox.com * Change UA string to Desktop mode * Show a syncing text while devices are being refreshed * Remove user agent override from json * Add the FxA login url in a new tab * Fixed rebase issues * UA mode fixes * Update the accounts icon * Invalidated menu views after changing image drawable * Review fixes
1 parent 751a846 commit ede1763

File tree

80 files changed

+1710
-810
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

80 files changed

+1710
-810
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ infer-out/
5656
fastlane/
5757

5858
app/.externalNativeBuild
59+
app/.cxx
5960
openwnn/.externalNativeBuild
6061

6162
*.swp

app/build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,9 @@ dependencies {
464464
// TODO this should not be necessary at all, see Services.kt
465465
implementation deps.work.runtime
466466

467+
// TODO this should not be necessary at all, see Services.kt
468+
implementation deps.work.runtime
469+
467470
// Kotlin dependency
468471
implementation deps.kotlin.stdlib
469472
implementation deps.kotlin.coroutines

app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
import org.mozilla.vrbrowser.ui.widgets.RootWidget;
5959
import org.mozilla.vrbrowser.ui.widgets.TrayWidget;
6060
import org.mozilla.vrbrowser.ui.widgets.UIWidget;
61-
import org.mozilla.vrbrowser.ui.widgets.VideoProjectionMenuWidget;
61+
import org.mozilla.vrbrowser.ui.widgets.menus.VideoProjectionMenuWidget;
6262
import org.mozilla.vrbrowser.ui.widgets.Widget;
6363
import org.mozilla.vrbrowser.ui.widgets.WidgetManagerDelegate;
6464
import org.mozilla.vrbrowser.ui.widgets.WidgetPlacement;
@@ -1402,6 +1402,11 @@ public void openNewTab(@NonNull String uri) {
14021402
mWindows.addBackgroundTab(mWindows.getFocusedWindow(), uri);
14031403
}
14041404

1405+
@Override
1406+
public void openNewTabForeground(@NonNull String uri) {
1407+
mWindows.addTab(mWindows.getFocusedWindow(), uri);
1408+
}
1409+
14051410
@Override
14061411
public WindowWidget getFocusedWindow() {
14071412
return mWindows.getFocusedWindow();

app/src/common/shared/org/mozilla/vrbrowser/browser/Accounts.kt

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,8 @@ import androidx.lifecycle.ProcessLifecycleOwner
1212
import kotlinx.coroutines.CoroutineScope
1313
import kotlinx.coroutines.Dispatchers
1414
import kotlinx.coroutines.future.future
15-
import mozilla.components.concept.sync.AccountObserver
16-
import mozilla.components.concept.sync.AuthType
17-
import mozilla.components.concept.sync.OAuthAccount
18-
import mozilla.components.concept.sync.Profile
15+
import kotlinx.coroutines.launch
16+
import mozilla.components.concept.sync.*
1917
import mozilla.components.service.fxa.SyncEngine
2018
import mozilla.components.service.fxa.manager.SyncEnginesStorage
2119
import mozilla.components.service.fxa.sync.SyncReason
@@ -49,7 +47,9 @@ class Accounts constructor(val context: Context) {
4947
var accountStatus = AccountStatus.SIGNED_OUT
5048
private val accountListeners = ArrayList<AccountObserver>()
5149
private val syncListeners = ArrayList<SyncStatusObserver>()
50+
private val deviceConstellationListeners = ArrayList<DeviceConstellationObserver>()
5251
private val services = (context.applicationContext as VRBrowserApplication).services
52+
private var otherDevices = emptyList<Device>()
5353
private val syncStorage = SyncEnginesStorage(context)
5454
var isSyncing = false
5555

@@ -82,6 +82,17 @@ class Accounts constructor(val context: Context) {
8282
}
8383
}
8484

85+
private val deviceConstellationObserver = object : DeviceConstellationObserver {
86+
override fun onDevicesUpdate(constellation: ConstellationState) {
87+
otherDevices = constellation.otherDevices
88+
deviceConstellationListeners.toMutableList().forEach {
89+
Handler(Looper.getMainLooper()).post {
90+
it.onDevicesUpdate(constellation)
91+
}
92+
}
93+
}
94+
}
95+
8596
private val accountObserver = object : AccountObserver {
8697
override fun onAuthenticated(account: OAuthAccount, authType: AuthType) {
8798
accountStatus = AccountStatus.SIGNED_IN
@@ -91,6 +102,13 @@ class Accounts constructor(val context: Context) {
91102
syncStorage.setStatus(SyncEngine.History, SettingsStore.getInstance(context).isHistorySyncEnabled)
92103
services.accountManager.syncNowAsync(SyncReason.EngineChange, false)
93104

105+
// Update device list
106+
account.deviceConstellation().registerDeviceObserver(
107+
deviceConstellationObserver,
108+
ProcessLifecycleOwner.get(),
109+
true
110+
)
111+
94112
account.deviceConstellation().refreshDevicesAsync()
95113
accountListeners.toMutableList().forEach {
96114
Handler(Looper.getMainLooper()).post {
@@ -173,6 +191,20 @@ class Accounts constructor(val context: Context) {
173191
syncListeners.clear()
174192
}
175193

194+
fun addDeviceConstellationListener(aListener: DeviceConstellationObserver) {
195+
if (!deviceConstellationListeners.contains(aListener)) {
196+
deviceConstellationListeners.add(aListener)
197+
}
198+
}
199+
200+
fun removeDeviceConstellationListener(aListener: DeviceConstellationObserver) {
201+
deviceConstellationListeners.remove(aListener)
202+
}
203+
204+
fun removeAllDeviceConstellationListeners() {
205+
deviceConstellationListeners.clear()
206+
}
207+
176208
fun authUrlAsync(): CompletableFuture<String?>? {
177209
return CoroutineScope(Dispatchers.Main).future {
178210
services.accountManager.beginAuthenticationAsync().await()
@@ -219,6 +251,7 @@ class Accounts constructor(val context: Context) {
219251
}
220252

221253
fun logoutAsync(): CompletableFuture<Unit?>? {
254+
otherDevices = emptyList()
222255
return CoroutineScope(Dispatchers.Main).future {
223256
services.accountManager.logoutAsync().await()
224257
}
@@ -283,4 +316,26 @@ class Accounts constructor(val context: Context) {
283316
return getLastSynced(context)
284317
}
285318

319+
fun devicesByCapability(capabilities: List<DeviceCapability>): List<Device> {
320+
return otherDevices.filter { it.capabilities.containsAll(capabilities) }
321+
}
322+
323+
fun sendTabs(targetDevices: List<Device>, url: String, title: String) {
324+
CoroutineScope(Dispatchers.Main).launch {
325+
services.accountManager.authenticatedAccount()?.deviceConstellation()?.let { constellation ->
326+
// Ignore devices that can't receive tabs or are not in the received list
327+
val targets = constellation.state()?.otherDevices?.filter {
328+
it.capabilities.contains(DeviceCapability.SEND_TAB)
329+
targetDevices.contains(it)
330+
}
331+
332+
targets?.forEach {
333+
constellation.sendEventToDeviceAsync(
334+
it.id, DeviceEventOutgoing.SendTab(title, url)
335+
).await()
336+
}
337+
}
338+
}
339+
}
340+
286341
}

app/src/common/shared/org/mozilla/vrbrowser/browser/BookmarksStore.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,10 @@ class BookmarksStore constructor(val context: Context) {
162162
}
163163
}
164164

165+
fun searchBookmarks(query: String, limit: Int): CompletableFuture<List<BookmarkNode>> = GlobalScope.future {
166+
storage.searchBookmarks(query, limit)
167+
}
168+
165169
private suspend fun getBookmarkByUrl(aURL: String): BookmarkNode? {
166170
val bookmarks: List<BookmarkNode>? = storage.getBookmarksWithUrl(aURL)
167171
if (bookmarks == null || bookmarks.isEmpty()) {

app/src/common/shared/org/mozilla/vrbrowser/browser/HistoryStore.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,7 @@ import android.os.Looper
1111
import androidx.lifecycle.ProcessLifecycleOwner
1212
import kotlinx.coroutines.GlobalScope
1313
import kotlinx.coroutines.future.future
14-
import mozilla.components.concept.storage.PageObservation
15-
import mozilla.components.concept.storage.PageVisit
16-
import mozilla.components.concept.storage.VisitInfo
17-
import mozilla.components.concept.storage.VisitType
14+
import mozilla.components.concept.storage.*
1815
import mozilla.components.service.fxa.sync.SyncStatusObserver
1916
import mozilla.components.support.base.log.logger.Logger
2017
import org.mozilla.vrbrowser.VRBrowserApplication
@@ -126,6 +123,10 @@ class HistoryStore constructor(val context: Context) {
126123
result.isNotEmpty() && result[0]
127124
}
128125

126+
fun getSuggestions(query: String, limit: Int): CompletableFuture<List<SearchResult>> = GlobalScope.future {
127+
storage.getSuggestions(query, limit)
128+
}
129+
129130
private fun notifyListeners() {
130131
if (listeners.size > 0) {
131132
val listenersCopy = ArrayList(listeners)

app/src/common/shared/org/mozilla/vrbrowser/browser/PromptDelegate.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ private void handlePopUpRequest(@NonNull PopUpRequest request) {
262262
mPopUpPrompt.setButtonsDelegate(new BaseAppDialogWidget.Delegate() {
263263
@Override
264264
public void onButtonClicked(int index) {
265-
boolean allowed = index != PopUpBlockDialogWidget.LEFT;
265+
boolean allowed = index != PopUpBlockDialogWidget.NEGATIVE;
266266
boolean askAgain = mPopUpPrompt.askAgain();
267267
if (!askAgain) {
268268
mAllowedPopUpSites.add(new PopUpSite(request.uri, allowed));

app/src/common/shared/org/mozilla/vrbrowser/browser/Services.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ import mozilla.components.support.rustlog.RustLog
2727
import org.mozilla.geckoview.AllowOrDeny
2828
import org.mozilla.geckoview.GeckoResult
2929
import org.mozilla.geckoview.GeckoSession
30-
import org.mozilla.vrbrowser.browser.engine.SessionStore
3130
import org.mozilla.vrbrowser.R
31+
import org.mozilla.vrbrowser.browser.engine.SessionStore
3232

3333
class Services(context: Context, places: Places): GeckoSession.NavigationDelegate {
3434
companion object {
@@ -83,15 +83,13 @@ class Services(context: Context, places: Places): GeckoSession.NavigationDelegat
8383
}
8484
}
8585
}
86-
8786
val accountManager = FxaAccountManager(
8887
context = context,
8988
serverConfig = ServerConfig.release(CLIENT_ID, REDIRECT_URL),
9089
deviceConfig = DeviceConfig(
9190
// This is a default name, and can be changed once user is logged in.
9291
// E.g. accountManager.authenticatedAccount()?.deviceConstellation()?.setDeviceNameAsync("new name")
9392
name = "${context.getString(R.string.app_name)} on ${Build.MANUFACTURER} ${Build.MODEL}",
94-
// TODO need a new device type! "VR"
9593
type = DeviceType.VR,
9694
capabilities = setOf(DeviceCapability.SEND_TAB)
9795
),

app/src/common/shared/org/mozilla/vrbrowser/search/suggestions/SuggestionsProvider.java

Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616
import java.util.List;
1717
import java.util.concurrent.CompletableFuture;
1818

19-
import mozilla.appservices.places.BookmarkRoot;
20-
2119
public class SuggestionsProvider {
2220

2321
private static final String LOGTAG = SuggestionsProvider.class.getSimpleName();
@@ -31,31 +29,27 @@ public int compare(Object obj1, Object obj2) {
3129
return 0;
3230

3331
} else if (suggestion1.type == suggestion2.type) {
34-
if (mFilterText != null) {
35-
if (suggestion1.title != null && suggestion2.title != null) {
36-
return suggestion1.title.toLowerCase().indexOf(mFilterText) - suggestion2.title.toLowerCase().indexOf(mFilterText);
32+
if (suggestion1.type == Type.HISTORY) {
33+
if (suggestion1.score != suggestion2.score) {
34+
return suggestion1.score - suggestion2.score;
3735
}
38-
return suggestion1.url.toLowerCase().indexOf(mFilterText) - suggestion2.url.indexOf(mFilterText);
39-
40-
} else {
41-
return suggestion1.url.compareTo(suggestion2.url);
4236
}
4337

38+
return suggestion1.url.compareTo(suggestion2.url);
39+
4440
} else {
4541
return suggestion1.type.ordinal() - suggestion2.type.ordinal();
4642
}
4743
}
4844
}
4945

50-
private Context mContext;
5146
private SearchEngineWrapper mSearchEngineWrapper;
5247
private String mText;
5348
private String mFilterText;
5449
private Comparator mComparator;
5550

5651
public SuggestionsProvider(Context context) {
57-
mContext = context;
58-
mSearchEngineWrapper = SearchEngineWrapper.get(mContext);
52+
mSearchEngineWrapper = SearchEngineWrapper.get(context);
5953
mFilterText = "";
6054
mComparator = new DefaultSuggestionsComparator();
6155
}
@@ -81,16 +75,16 @@ public void setComparator(Comparator comparator) {
8175

8276
public CompletableFuture<List<SuggestionItem>> getBookmarkSuggestions(@NonNull List<SuggestionItem> items) {
8377
CompletableFuture future = new CompletableFuture();
84-
// Explicitly passing Root will look in all the bookmarks, default is just to look in the mobile bookmarks.
85-
SessionStore.get().getBookmarkStore().getBookmarks(BookmarkRoot.Root.getId()).thenAcceptAsync((bookmarks) -> {
86-
bookmarks.stream().
87-
filter(b -> b.getUrl().toLowerCase().contains(mFilterText) ||
88-
b.getTitle().toLowerCase().contains(mFilterText))
78+
SessionStore.get().getBookmarkStore().searchBookmarks(mFilterText, 100).thenAcceptAsync((bookmarks) -> {
79+
bookmarks.stream()
80+
.filter((b) -> !b.getUrl().startsWith("place:") &&
81+
!b.getUrl().startsWith("about:reader"))
8982
.forEach(b -> items.add(SuggestionItem.create(
9083
b.getTitle(),
9184
b.getUrl(),
9285
null,
93-
Type.BOOKMARK
86+
Type.BOOKMARK,
87+
0
9488
)));
9589
if (mComparator != null) {
9690
items.sort(mComparator);
@@ -108,15 +102,13 @@ public CompletableFuture<List<SuggestionItem>> getBookmarkSuggestions(@NonNull L
108102

109103
public CompletableFuture<List<SuggestionItem>> getHistorySuggestions(@NonNull final List<SuggestionItem> items) {
110104
CompletableFuture future = new CompletableFuture();
111-
SessionStore.get().getHistoryStore().getHistory().thenAcceptAsync((history) -> {
112-
history.stream()
113-
.filter(h ->
114-
h.toLowerCase().contains(mFilterText))
115-
.forEach(h -> items.add(SuggestionItem.create(
116-
h,
117-
h,
105+
SessionStore.get().getHistoryStore().getSuggestions(mFilterText, 100).thenAcceptAsync((history) -> {
106+
history.forEach(h -> items.add(SuggestionItem.create(
107+
h.getTitle(),
108+
h.getUrl(),
118109
null,
119-
Type.HISTORY
110+
Type.HISTORY,
111+
h.getScore()
120112
)));
121113
if (mComparator != null) {
122114
items.sort(mComparator);
@@ -141,7 +133,8 @@ public CompletableFuture<List<SuggestionItem>> getSearchEngineSuggestions(@NonNu
141133
mText,
142134
getSearchURLOrDomain(mText),
143135
null,
144-
Type.COMPLETION
136+
Type.COMPLETION,
137+
0
145138
));
146139
}
147140

@@ -150,7 +143,8 @@ public CompletableFuture<List<SuggestionItem>> getSearchEngineSuggestions(@NonNu
150143
mFilterText,
151144
getSearchURLOrDomain(mFilterText),
152145
null,
153-
Type.SUGGESTION
146+
Type.SUGGESTION,
147+
0
154148
));
155149

156150
// Suggestions
@@ -161,7 +155,8 @@ public CompletableFuture<List<SuggestionItem>> getSearchEngineSuggestions(@NonNu
161155
s,
162156
url,
163157
null,
164-
Type.SUGGESTION
158+
Type.SUGGESTION,
159+
0
165160
));
166161
});
167162
if (mComparator != null) {

app/src/common/shared/org/mozilla/vrbrowser/ui/adapters/BindingAdapters.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@
99
import android.view.ViewGroup;
1010
import android.widget.TextView;
1111

12+
import androidx.annotation.DimenRes;
1213
import androidx.annotation.Dimension;
1314
import androidx.annotation.DrawableRes;
1415
import androidx.annotation.NonNull;
1516
import androidx.databinding.BindingAdapter;
1617

1718
import org.mozilla.vrbrowser.R;
1819
import org.mozilla.vrbrowser.ui.views.HoneycombButton;
20+
import org.mozilla.vrbrowser.ui.views.UIButton;
1921

2022
import java.text.SimpleDateFormat;
2123
import java.util.Calendar;
@@ -111,4 +113,9 @@ public static void setFxALastSync(@NonNull TextView view, long lastSync) {
111113
}
112114

113115

116+
117+
@BindingAdapter("android:layout_width")
118+
public static void setLayoutWidth(@NonNull UIButton button, @NonNull @Dimension float dimen) {
119+
button.setLayoutWidth(dimen);
120+
}
114121
}

0 commit comments

Comments
 (0)