diff --git a/components/browser/storage-memory/src/main/java/mozilla/components/browser/storage/memory/InMemoryHistoryStorage.kt b/components/browser/storage-memory/src/main/java/mozilla/components/browser/storage/memory/InMemoryHistoryStorage.kt index 28d7652bd05..9e69be2e048 100644 --- a/components/browser/storage-memory/src/main/java/mozilla/components/browser/storage/memory/InMemoryHistoryStorage.kt +++ b/components/browser/storage-memory/src/main/java/mozilla/components/browser/storage/memory/InMemoryHistoryStorage.kt @@ -11,6 +11,7 @@ import mozilla.components.concept.storage.PageObservation import mozilla.components.concept.storage.SearchResult import mozilla.components.concept.storage.PageVisit import mozilla.components.concept.storage.RedirectSource +import mozilla.components.concept.storage.TopFrecentSiteInfo import mozilla.components.concept.storage.VisitInfo import mozilla.components.concept.storage.VisitType import mozilla.components.support.utils.StorageUtils.levenshteinDistance @@ -93,6 +94,10 @@ class InMemoryHistoryStorage : HistoryStorage { return visits } + override suspend fun getTopFrecentSites(numItems: Int): List { + throw UnsupportedOperationException("getTopFrecentSites is not yet supported by the in-memory history storage") + } + override fun getSuggestions(query: String, limit: Int): List = synchronized(pages + pageMeta) { data class Hit(val url: String, val score: Int) diff --git a/components/browser/storage-sync/src/main/java/mozilla/components/browser/storage/sync/PlacesHistoryStorage.kt b/components/browser/storage-sync/src/main/java/mozilla/components/browser/storage/sync/PlacesHistoryStorage.kt index 1960861d7a7..eb60cf586ad 100644 --- a/components/browser/storage-sync/src/main/java/mozilla/components/browser/storage/sync/PlacesHistoryStorage.kt +++ b/components/browser/storage-sync/src/main/java/mozilla/components/browser/storage/sync/PlacesHistoryStorage.kt @@ -15,6 +15,7 @@ import mozilla.components.concept.storage.PageObservation import mozilla.components.concept.storage.PageVisit import mozilla.components.concept.storage.SearchResult import mozilla.components.concept.storage.RedirectSource +import mozilla.components.concept.storage.TopFrecentSiteInfo import mozilla.components.concept.storage.VisitInfo import mozilla.components.concept.storage.VisitType import mozilla.components.concept.sync.SyncAuthInfo @@ -97,6 +98,12 @@ open class PlacesHistoryStorage(context: Context) : PlacesStorage(context), Hist } } + override suspend fun getTopFrecentSites(numItems: Int): List { + return withContext(scope.coroutineContext) { + places.reader().getTopFrecentSiteInfos(numItems).map { it.into() } + } + } + override fun getSuggestions(query: String, limit: Int): List { require(limit >= 0) { "Limit must be a positive integer" } return places.reader().queryAutocomplete(query, limit = limit).map { diff --git a/components/browser/storage-sync/src/main/java/mozilla/components/browser/storage/sync/Types.kt b/components/browser/storage-sync/src/main/java/mozilla/components/browser/storage/sync/Types.kt index 7e46982205f..921291308d8 100644 --- a/components/browser/storage-sync/src/main/java/mozilla/components/browser/storage/sync/Types.kt +++ b/components/browser/storage-sync/src/main/java/mozilla/components/browser/storage/sync/Types.kt @@ -12,6 +12,7 @@ import mozilla.appservices.places.BookmarkTreeNode import mozilla.appservices.places.SyncAuthInfo import mozilla.components.concept.storage.BookmarkNode import mozilla.components.concept.storage.BookmarkNodeType +import mozilla.components.concept.storage.TopFrecentSiteInfo import mozilla.components.concept.storage.VisitInfo import mozilla.components.concept.storage.VisitType @@ -68,6 +69,13 @@ internal fun mozilla.appservices.places.VisitInfo.into(): VisitInfo { ) } +internal fun mozilla.appservices.places.TopFrecentSiteInfo.into(): TopFrecentSiteInfo { + return TopFrecentSiteInfo( + url = this.url, + title = this.title + ) +} + internal fun BookmarkTreeNode.asBookmarkNode(): BookmarkNode { return when (this) { is BookmarkItem -> { diff --git a/components/browser/storage-sync/src/test/java/mozilla/components/browser/storage/sync/PlacesHistoryStorageTest.kt b/components/browser/storage-sync/src/test/java/mozilla/components/browser/storage/sync/PlacesHistoryStorageTest.kt index 59964cbae95..a50e78ffe43 100644 --- a/components/browser/storage-sync/src/test/java/mozilla/components/browser/storage/sync/PlacesHistoryStorageTest.kt +++ b/components/browser/storage-sync/src/test/java/mozilla/components/browser/storage/sync/PlacesHistoryStorageTest.kt @@ -139,6 +139,40 @@ class PlacesHistoryStorageTest { assertEquals("Mozilla", recordedVisits[0].title) } + @Test + fun `store can be used to query top frecent site information`() = runBlocking { + val toAdd = listOf( + "https://www.example.com/123", + "https://www.example.com/123", + "https://www.example.com/12345", + "https://www.mozilla.com/foo/bar/baz", + "https://www.mozilla.com/foo/bar/baz", + "https://mozilla.com/a1/b2/c3", + "https://news.ycombinator.com/", + "https://www.mozilla.com/foo/bar/baz" + ) + + for (url in toAdd) { + history.recordVisit(url, PageVisit(VisitType.LINK, RedirectSource.NOT_A_SOURCE)) + } + + var infos = history.getTopFrecentSites(0) + assertEquals(0, infos.size) + + infos = history.getTopFrecentSites(3) + assertEquals(3, infos.size) + assertEquals("https://www.mozilla.com/foo/bar/baz", infos[0].url) + assertEquals("https://www.example.com/123", infos[1].url) + + infos = history.getTopFrecentSites(5) + assertEquals(5, infos.size) + assertEquals("https://www.mozilla.com/foo/bar/baz", infos[0].url) + assertEquals("https://www.example.com/123", infos[1].url) + assertEquals("https://news.ycombinator.com/", infos[2].url) + assertEquals("https://mozilla.com/a1/b2/c3", infos[3].url) + assertEquals("https://www.example.com/12345", infos[4].url) + } + @Test fun `store can be used to query detailed visit information`() = runBlocking { history.recordVisit("http://www.mozilla.org", PageVisit(VisitType.LINK, RedirectSource.NOT_A_SOURCE)) diff --git a/components/concept/storage/src/main/java/mozilla/components/concept/storage/HistoryStorage.kt b/components/concept/storage/src/main/java/mozilla/components/concept/storage/HistoryStorage.kt index c306d44ec3a..ab8b79c1944 100644 --- a/components/concept/storage/src/main/java/mozilla/components/concept/storage/HistoryStorage.kt +++ b/components/concept/storage/src/main/java/mozilla/components/concept/storage/HistoryStorage.kt @@ -68,6 +68,15 @@ interface HistoryStorage : Storage { excludeTypes: List = listOf() ): List + /** + * Returns a list of the top frecent site infos limited by the given number of items + * sorted by most to least frecent. + * + * @param numItems the number of top frecent sites to return in the list. + * @return a list of the top frecent site infos sorted by most to least frecent. + */ + suspend fun getTopFrecentSites(numItems: Int): List + /** * Retrieves suggestions matching the [query]. * @param query A query by which to search the underlying store. @@ -145,6 +154,17 @@ enum class RedirectSource { data class PageObservation(val title: String?) +/** + * Information about a top frecent site. + * + * @property url The URL of the page that was visited. + * @property title The title of the page that was visited, if known. + */ +data class TopFrecentSiteInfo( + val url: String, + val title: String? +) + /** * Information about a history visit. * diff --git a/components/feature/session/src/test/java/mozilla/components/feature/session/HistoryDelegateTest.kt b/components/feature/session/src/test/java/mozilla/components/feature/session/HistoryDelegateTest.kt index f4857a03a28..aec6cfd802c 100644 --- a/components/feature/session/src/test/java/mozilla/components/feature/session/HistoryDelegateTest.kt +++ b/components/feature/session/src/test/java/mozilla/components/feature/session/HistoryDelegateTest.kt @@ -12,6 +12,7 @@ import mozilla.components.concept.storage.PageObservation import mozilla.components.concept.storage.PageVisit import mozilla.components.concept.storage.RedirectSource import mozilla.components.concept.storage.SearchResult +import mozilla.components.concept.storage.TopFrecentSiteInfo import mozilla.components.concept.storage.VisitInfo import mozilla.components.concept.storage.VisitType import mozilla.components.support.test.mock @@ -96,6 +97,11 @@ class HistoryDelegateTest { return emptyList() } + override suspend fun getTopFrecentSites(numItems: Int): List { + fail() + return emptyList() + } + override fun getSuggestions(query: String, limit: Int): List { fail() return listOf() diff --git a/docs/changelog.md b/docs/changelog.md index 85b26904df4..237371b0b80 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -12,6 +12,10 @@ permalink: /changelog/ * [Gecko](https://github.com/mozilla-mobile/android-components/blob/master/buildSrc/src/main/java/Gecko.kt) * [Configuration](https://github.com/mozilla-mobile/android-components/blob/master/buildSrc/src/main/java/Config.kt) +* **browser-storage-sync** + * Added `getTopFrecentSites` to `PlacesHistoryStorage` to returns a list of the top frecent site infos + sorted by most to least frecent. + # 44.0.0 * [Commits](https://github.com/mozilla-mobile/android-components/compare/v43.0.0...v44.0.0)