diff --git a/README-places.md b/README-places.md new file mode 100644 index 000000000..d0b8cce96 --- /dev/null +++ b/README-places.md @@ -0,0 +1,41 @@ +This branch is a WIP for hooking up the "places" component in the reference +browser. It will only work with +[this android-components branch](https://github.com/mhammond/android-components/tree/autocomplete-places), +and in particular, after following +[these instructions](https://github.com/mhammond/android-components/blob/autocomplete-places/components/service/sync-places/README.md) + +There's a new `BrowserAutocompleteProvider.kt` which wraps both the +`DomainAutocompleteProvider` and the places component. It first tries to +find matches using places, then using the `DomainAutocompleteProvider`. + +Note that because we don't yet have geckoview hooked up to collect visit +information and write them to the places database. the places database will +be empty - meaning only +suggestions from `DomainAutocompleteProvider` will be shown. However, there's +a trick you can use to import your desktop places database and have it use +that. + +* You will need to check out the application-services repo, and from the + `places` directory (soon to be `components/places`), execute: + + `cargo run --release --example autocomplete -- --import-places auto` + + (alternatively, in the place of `auto`, specify the full path to a desktop + `places.sqlite`) + + This will also start a demo-app where you can perform auto-complete queries. + Press ESC to exit the app, and note that in the same directory you will have + a file `new-places.db` - rename this file to `places.sqlite` + +* Kill the app in the emulator. + +* Use the "Device File Explorer" in Android Studio, and navigate to the + `sdcard/Android/data/org.mozilla.reference.browser/files` directory - if + you've run the app before, you should already find a `places.sqlite` there. + Upload the file created above here and restart the app. + +Note that if you have many many visits (eg, mine has ~170k places with ~230k +visits with a db size of ~75MB) a search for a full domain may take a couple +of seconds, but we know how to fix this. Even with a database this size, +searches of small substrings (eg, a few letters) are fast. We never expect a +"real" mobile device database to be this large, but it's a nice stress-test. diff --git a/app/build.gradle b/app/build.gradle index 06528e097..9d44ebf0a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -94,6 +94,7 @@ dependencies { implementation Deps.mozilla_ui_autocomplete + implementation Deps.mozilla_service_sync_places implementation Deps.mozilla_service_firefox_accounts implementation Deps.mozilla_support_utils diff --git a/app/src/main/java/org/mozilla/reference/browser/browser/BrowserAutocompleteProvider.kt b/app/src/main/java/org/mozilla/reference/browser/browser/BrowserAutocompleteProvider.kt new file mode 100644 index 000000000..e7578575e --- /dev/null +++ b/app/src/main/java/org/mozilla/reference/browser/browser/BrowserAutocompleteProvider.kt @@ -0,0 +1,66 @@ +/* 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/. */ + +// This is, roughly, an "auto-complete aggregator" - it first tries to find a match via "places", +// and if that fails, falls back to the "domain" provider. +package org.mozilla.reference.browser.browser + +import android.app.Activity +import android.content.Context +import kotlinx.coroutines.experimental.launch +import mozilla.components.browser.domains.DomainAutoCompleteProvider +import mozilla.components.browser.toolbar.BrowserToolbar +import mozilla.components.ui.autocomplete.InlineAutocompleteEditText +import mozilla.components.service.sync.places.PlacesAwesomeBarProvider + +// NOTE: this should be updated or replaced once mozilla.components.concept.awesomebar is in-place +// and has an implementation. Consider this a proof-of-concept only. +class BrowserAutocompleteProvider ( + context: Context, + toolbar: BrowserToolbar, + sessionId: String? = null) { + + private val domainAutoCompleteProvider = DomainAutoCompleteProvider().apply { + initialize(context) + } + + // XXX - this should be in the "profile" dir, but I'm not sure how to fetch that. + private val placesProvider = PlacesAwesomeBarProvider(context) + + init { + toolbar.setAutocompleteFilter { value, view -> + view?.let { _ -> + // use a coroutine to do this off the main thread. + launch { + // First try places. + // XXX - given the inlineautocomplete functionality, we eventually want to perform + // an OriginOrUrl search - however, for now, we just perform a "normal" search, + // then iterate the results until we find one that matches at the start. + var finalResult: String? = null + var finalSource: String? = null + var finalSize: Int? = 0; + + val placesResult = placesProvider.getSuggestion(value) + if (placesResult != null) { + finalResult = placesResult + finalSource = "places" + finalSize = 1 + } else { + val result = domainAutoCompleteProvider.autocomplete(value) + finalResult = result.text + finalSource = result.source + finalSize = result.size + } + // domainAutoCompleteProvider always provides a result, even if it is empty strings. + val activity = view.context as Activity + activity.runOnUiThread { + view.applyAutocompleteResult( + InlineAutocompleteEditText.AutocompleteResult(finalResult, finalSource!!, finalSize!!) + ) + } + } + } + } + } +} diff --git a/app/src/main/java/org/mozilla/reference/browser/browser/BrowserFragment.kt b/app/src/main/java/org/mozilla/reference/browser/browser/BrowserFragment.kt index c6a15bb10..8685b0313 100644 --- a/app/src/main/java/org/mozilla/reference/browser/browser/BrowserFragment.kt +++ b/app/src/main/java/org/mozilla/reference/browser/browser/BrowserFragment.kt @@ -4,6 +4,7 @@ package org.mozilla.reference.browser.browser +import android.app.Activity import android.Manifest.permission.WRITE_EXTERNAL_STORAGE import android.os.Bundle import android.support.v4.app.Fragment @@ -47,6 +48,8 @@ class BrowserFragment : Fragment(), BackHandler, DownloadDialogListener { tabsToolbarFeature = TabsToolbarFeature(context!!, toolbar, ::showTabs) + BrowserAutocompleteProvider(context!!, toolbar) + downloadsFeature = DownloadsFeature( requireContext(), sessionManager = requireComponents.sessionManager, diff --git a/build.gradle b/build.gradle index 5f84255b0..05e4d84e4 100644 --- a/build.gradle +++ b/build.gradle @@ -31,6 +31,8 @@ plugins { allprojects { repositories { + mavenLocal() + google() maven { diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index 37468aed7..fdc6b73e0 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -17,7 +17,7 @@ private object Versions { const val android_gradle_plugin = "3.1.4" - const val mozilla_android_components = "0.28.0" + const val mozilla_android_components = "0.28.0-SNAPSHOT" } // Synchronized dependencies used by (some) modules @@ -50,6 +50,8 @@ object Deps { const val mozilla_support_utils = "org.mozilla.components:support-utils:${Versions.mozilla_android_components}" const val mozilla_support_ktx= "org.mozilla.components:support-ktx:${Versions.mozilla_android_components}" + const val mozilla_service_sync_places = "org.mozilla.components:service-sync-places:0.28.0-SNAPSHOT" // TODO: use a released version. + const val testing_junit = "junit:junit:${Versions.junit}" const val testing_robolectric = "org.robolectric:robolectric:${Versions.robolectric}" const val testing_mockito = "org.mockito:mockito-core:${Versions.mockito}"