From 7613c2a78c7e23234bbf16360f9599815df21438 Mon Sep 17 00:00:00 2001 From: Grisha Kruglov Date: Mon, 12 Jul 2021 21:43:14 -0700 Subject: [PATCH 1/2] Support for tracking external sources Mainly, does two things: - refactors SessionState.Source into a richer form (splitting sources into Internal and External, where External ones track information about originating package) - adds persistence of External sources into tab session state; we don't want to persist Internal sources as that was explicitly removed before for causing various issues (e.g. UI behaving incorrectly after restoring tabs with various internal sources set) --- .../storage/serialize/BrowserStateReader.kt | 16 +- .../storage/serialize/BrowserStateWriter.kt | 14 ++ .../browser/session/storage/serialize/Keys.kt | 4 + .../serialize/BrowserStateWriterReaderTest.kt | 114 ++++++++++- .../state/state/CustomTabSessionState.kt | 5 +- .../browser/state/state/SessionState.kt | 177 ++++++++++++++---- .../browser/state/state/TabSessionState.kt | 4 +- .../state/state/recover/RecoverableTab.kt | 17 +- .../state/action/CustomTabListActionTest.kt | 8 +- .../browser/state/action/TabListActionTest.kt | 21 ++- .../customtabs/CustomTabIntentProcessor.kt | 11 +- .../CustomTabIntentProcessorTest.kt | 6 +- .../intent/processing/TabIntentProcessor.kt | 18 +- .../processing/TabIntentProcessorTest.kt | 19 ++ .../TrustedWebActivityIntentProcessor.kt | 2 +- .../pwa/intent/WebAppIntentProcessor.kt | 2 +- .../TrustedWebActivityIntentProcessorTest.kt | 2 +- .../pwa/intent/WebAppIntentProcessorTest.kt | 4 +- .../feature/search/SearchUseCases.kt | 2 +- .../search/BrowserStoreSeachAdapterTest.kt | 3 +- .../feature/search/SearchUseCasesTest.kt | 14 +- .../feature/tabs/CustomTabsUseCases.kt | 4 +- .../components/feature/tabs/TabsUseCases.kt | 8 +- .../support/ktx/android/util/JsonReader.kt | 13 ++ .../components/support/utils/SafeIntent.kt | 3 + .../webextensions/WebExtensionSupport.kt | 2 +- .../webextensions/WebExtensionSupportTest.kt | 16 +- 27 files changed, 399 insertions(+), 110 deletions(-) diff --git a/components/browser/session-storage/src/main/java/mozilla/components/browser/session/storage/serialize/BrowserStateReader.kt b/components/browser/session-storage/src/main/java/mozilla/components/browser/session/storage/serialize/BrowserStateReader.kt index 68d7f77f647..73e07fe45be 100644 --- a/components/browser/session-storage/src/main/java/mozilla/components/browser/session/storage/serialize/BrowserStateReader.kt +++ b/components/browser/session-storage/src/main/java/mozilla/components/browser/session/storage/serialize/BrowserStateReader.kt @@ -11,12 +11,14 @@ import mozilla.components.browser.session.storage.RecoverableBrowserState import mozilla.components.browser.state.state.BrowserState import mozilla.components.browser.state.state.LastMediaAccessState import mozilla.components.browser.state.state.ReaderState +import mozilla.components.browser.state.state.SessionState import mozilla.components.browser.state.state.TabSessionState import mozilla.components.browser.state.state.recover.RecoverableTab import mozilla.components.concept.engine.Engine import mozilla.components.concept.engine.EngineSessionState import mozilla.components.concept.storage.HistoryMetadataKey import mozilla.components.support.ktx.android.util.nextBooleanOrNull +import mozilla.components.support.ktx.android.util.nextIntOrNull import mozilla.components.support.ktx.android.util.nextStringOrNull import mozilla.components.support.ktx.util.readJSON import java.util.UUID @@ -159,8 +161,8 @@ private fun JsonReader.tab( ) } -@Suppress("ComplexMethod") -private fun JsonReader.tabSession(): RecoverableTab? { +@Suppress("ComplexMethod", "LongMethod") +private fun JsonReader.tabSession(): RecoverableTab { var id: String? = null var parentId: String? = null var url: String? = null @@ -179,6 +181,10 @@ private fun JsonReader.tabSession(): RecoverableTab? { var historyMetadataSearchTerm: String? = null var historyMetadataReferrerUrl: String? = null + var externalSourceId: Int? = null + var externalSourcePackageId: String? = null + var externalSourceCategory: Int? = null + beginObject() while (hasNext()) { @@ -198,6 +204,9 @@ private fun JsonReader.tabSession(): RecoverableTab? { Keys.SESSION_LAST_MEDIA_URL -> lastMediaUrl = nextString() Keys.SESSION_LAST_MEDIA_SESSION_ACTIVE -> mediaSessionActive = nextBoolean() Keys.SESSION_LAST_MEDIA_ACCESS -> lastMediaAccess = nextLong() + Keys.SESSION_EXTERNAL_SOURCE_ID -> externalSourceId = nextInt() + Keys.SESSION_EXTERNAL_SOURCE_PACKAGE_ID -> externalSourcePackageId = nextStringOrNull() + Keys.SESSION_EXTERNAL_SOURCE_PACKAGE_CATEGORY -> externalSourceCategory = nextIntOrNull() Keys.SESSION_SOURCE_KEY -> nextString() else -> throw IllegalArgumentException("Unknown session key: $name") } @@ -232,6 +241,7 @@ private fun JsonReader.tabSession(): RecoverableTab? { lastMediaUrl ?: "", lastMediaAccess = lastMediaAccess ?: 0, mediaSessionActive = mediaSessionActive ?: false - ) + ), + source = SessionState.Source.restore(externalSourceId, externalSourcePackageId, externalSourceCategory) ) } diff --git a/components/browser/session-storage/src/main/java/mozilla/components/browser/session/storage/serialize/BrowserStateWriter.kt b/components/browser/session-storage/src/main/java/mozilla/components/browser/session/storage/serialize/BrowserStateWriter.kt index 67e2d06eb46..d42080895df 100644 --- a/components/browser/session-storage/src/main/java/mozilla/components/browser/session/storage/serialize/BrowserStateWriter.kt +++ b/components/browser/session-storage/src/main/java/mozilla/components/browser/session/storage/serialize/BrowserStateWriter.kt @@ -7,6 +7,7 @@ package mozilla.components.browser.session.storage.serialize import android.util.AtomicFile import android.util.JsonWriter import mozilla.components.browser.state.state.BrowserState +import mozilla.components.browser.state.state.SessionState import mozilla.components.browser.state.state.TabSessionState import mozilla.components.concept.engine.EngineSessionState import mozilla.components.support.ktx.util.streamJSON @@ -120,6 +121,19 @@ private fun JsonWriter.tab( value(metadata.referrerUrl) } + (tab.source as? SessionState.Source.External)?.let { source -> + name(Keys.SESSION_EXTERNAL_SOURCE_ID) + value(source.id) + + source.caller?.let { caller -> + name(Keys.SESSION_EXTERNAL_SOURCE_PACKAGE_ID) + value(caller.packageId) + + name(Keys.SESSION_EXTERNAL_SOURCE_PACKAGE_CATEGORY) + value(caller.category.id) + } + } + endObject() } diff --git a/components/browser/session-storage/src/main/java/mozilla/components/browser/session/storage/serialize/Keys.kt b/components/browser/session-storage/src/main/java/mozilla/components/browser/session/storage/serialize/Keys.kt index fd6245c8fbe..798415ebfc3 100644 --- a/components/browser/session-storage/src/main/java/mozilla/components/browser/session/storage/serialize/Keys.kt +++ b/components/browser/session-storage/src/main/java/mozilla/components/browser/session/storage/serialize/Keys.kt @@ -32,6 +32,10 @@ internal object Keys { const val SESSION_HISTORY_METADATA_SEARCH_TERM = "historyMetadataSearchTerm" const val SESSION_HISTORY_METADATA_REFERRER_URL = "historyMetadataReferrerUrl" + const val SESSION_EXTERNAL_SOURCE_ID = "externalSourceId" + const val SESSION_EXTERNAL_SOURCE_PACKAGE_ID = "externalPackageId" + const val SESSION_EXTERNAL_SOURCE_PACKAGE_CATEGORY = "externalPackageCategory" + const val SESSION_KEY = "session" const val ENGINE_SESSION_KEY = "engineSession" diff --git a/components/browser/session-storage/src/test/java/mozilla/components/browser/session/storage/serialize/BrowserStateWriterReaderTest.kt b/components/browser/session-storage/src/test/java/mozilla/components/browser/session/storage/serialize/BrowserStateWriterReaderTest.kt index 08404fa1121..a94a151c622 100644 --- a/components/browser/session-storage/src/test/java/mozilla/components/browser/session/storage/serialize/BrowserStateWriterReaderTest.kt +++ b/components/browser/session-storage/src/test/java/mozilla/components/browser/session/storage/serialize/BrowserStateWriterReaderTest.kt @@ -9,8 +9,11 @@ import android.util.JsonReader import android.util.JsonWriter import androidx.test.ext.junit.runners.AndroidJUnit4 import mozilla.components.browser.state.state.EngineState +import mozilla.components.browser.state.state.ExternalPackage import mozilla.components.browser.state.state.LastMediaAccessState +import mozilla.components.browser.state.state.PackageCategory import mozilla.components.browser.state.state.ReaderState +import mozilla.components.browser.state.state.SessionState import mozilla.components.browser.state.state.TabSessionState import mozilla.components.browser.state.state.createTab import mozilla.components.concept.engine.Engine @@ -95,8 +98,9 @@ class BrowserStateWriterReaderTest { @Test fun `Read tab with session source`() { - // We don't write tabs with session source anymore but need to be tolerant to - // session source being in the JSON to remain backward compatible. + // We don't persist session source of tabs unless it's an external source. + // However, in older versions we did persist other types of sources so need to be tolerant + // if these older cases are encountered in JSON to remain backward compatible. val engineState = createFakeEngineState() val engine = createFakeEngine(engineState) val tab = createTab(url = "https://www.mozilla.org", title = "Mozilla") @@ -105,11 +109,12 @@ class BrowserStateWriterReaderTest { ) writeTabWithSource(tab, file) - // When reading we don't care about the source either as we will just set - // it to RESTORED. So we just need to make sure we de-serialized successfully. + // When reading a tab that didn't have an external source persisted, we just need to make sure + // it is deserialized correctly. In this case, source defaults to `Internal.Restored`. val reader = BrowserStateReader() val restoredTab = reader.readTab(engine, file) assertNotNull(restoredTab!!) + assertEquals(SessionState.Source.Internal.Restored, restoredTab.source) assertEquals("https://www.mozilla.org", restoredTab.url) assertEquals("Mozilla", restoredTab.title) @@ -147,6 +152,105 @@ class BrowserStateWriterReaderTest { assertEquals(tab.content.url, restoredTab.historyMetadata!!.url) } + @Test + fun `Read and write tab with external custom tab source and full caller`() { + val engineState = createFakeEngineState() + val engine = createFakeEngine(engineState) + + val tab = createTab( + url = "https://www.mozilla.org", + title = "Mozilla", + contextId = "work", + source = SessionState.Source.External.CustomTab( + caller = ExternalPackage("com.mozilla.test", PackageCategory.PRODUCTIVITY) + ) + ) + + val writer = BrowserStateWriter() + val reader = BrowserStateReader() + + val file = AtomicFile( + File.createTempFile(UUID.randomUUID().toString(), UUID.randomUUID().toString()) + ) + + assertTrue(writer.writeTab(tab, file)) + + val restoredTab = reader.readTab(engine, file) + assertNotNull(restoredTab!!) + + assertNotNull(restoredTab.source) + assertTrue(restoredTab.source is SessionState.Source.External.CustomTab) + with(restoredTab.source as SessionState.Source.External.CustomTab) { + assertEquals("com.mozilla.test", this.caller!!.packageId) + assertEquals(PackageCategory.PRODUCTIVITY, this.caller!!.category) + } + } + + @Test + fun `Read and write tab with external action view source and partial caller`() { + val engineState = createFakeEngineState() + val engine = createFakeEngine(engineState) + + val tab = createTab( + url = "https://www.mozilla.org", + title = "Mozilla", + contextId = "work", + source = SessionState.Source.External.ActionView( + caller = ExternalPackage("com.mozilla.test", category = PackageCategory.UNKNOWN) + ) + ) + + val writer = BrowserStateWriter() + val reader = BrowserStateReader() + + val file = AtomicFile( + File.createTempFile(UUID.randomUUID().toString(), UUID.randomUUID().toString()) + ) + + assertTrue(writer.writeTab(tab, file)) + + val restoredTab = reader.readTab(engine, file) + assertNotNull(restoredTab!!) + + assertNotNull(restoredTab.source) + assertTrue(restoredTab.source is SessionState.Source.External.ActionView) + with(restoredTab.source as SessionState.Source.External.ActionView) { + assertEquals("com.mozilla.test", this.caller!!.packageId) + assertEquals(PackageCategory.UNKNOWN, this.caller!!.category) + } + } + + @Test + fun `Read and write tab with external action send source and missing caller`() { + val engineState = createFakeEngineState() + val engine = createFakeEngine(engineState) + + val tab = createTab( + url = "https://www.mozilla.org", + title = "Mozilla", + contextId = "work", + source = SessionState.Source.External.ActionSend(caller = null) + ) + + val writer = BrowserStateWriter() + val reader = BrowserStateReader() + + val file = AtomicFile( + File.createTempFile(UUID.randomUUID().toString(), UUID.randomUUID().toString()) + ) + + assertTrue(writer.writeTab(tab, file)) + + val restoredTab = reader.readTab(engine, file) + assertNotNull(restoredTab!!) + + assertNotNull(restoredTab.source) + assertTrue(restoredTab.source is SessionState.Source.External.ActionSend) + with(restoredTab.source as SessionState.Source.External.ActionSend) { + assertNull(this.caller) + } + } + @Test fun `Read and write tab with LastMediaAccessState`() { val engineState = createFakeEngineState() @@ -273,7 +377,7 @@ private fun JsonWriter.tabWithSource( value(tab.content.title) name(Keys.SESSION_SOURCE_KEY) - value(tab.source.name) + value(tab.source.toString()) endObject() } diff --git a/components/browser/state/src/main/java/mozilla/components/browser/state/state/CustomTabSessionState.kt b/components/browser/state/src/main/java/mozilla/components/browser/state/state/CustomTabSessionState.kt index 4a18aeda535..79750badb96 100644 --- a/components/browser/state/src/main/java/mozilla/components/browser/state/state/CustomTabSessionState.kt +++ b/components/browser/state/src/main/java/mozilla/components/browser/state/state/CustomTabSessionState.kt @@ -19,6 +19,7 @@ import java.util.UUID * values for this tab. * @property mediaSessionState the [MediaSessionState] of this session. * @property contextId the session context ID of this custom tab. + * @property source the [SessionState.Source] of this session. */ data class CustomTabSessionState( override val id: String = UUID.randomUUID().toString(), @@ -29,7 +30,7 @@ data class CustomTabSessionState( override val extensionState: Map = emptyMap(), override val mediaSessionState: MediaSessionState? = null, override val contextId: String? = null, - override val source: SessionState.Source = SessionState.Source.CUSTOM_TAB + override val source: SessionState.Source = SessionState.Source.Internal.CustomTab ) : SessionState { override fun createCopy( @@ -64,7 +65,7 @@ fun createCustomTab( engineSession: EngineSession? = null, mediaSessionState: MediaSessionState? = null, crashed: Boolean = false, - source: SessionState.Source = SessionState.Source.CUSTOM_TAB, + source: SessionState.Source = SessionState.Source.Internal.CustomTab, private: Boolean = false, webAppManifest: WebAppManifest? = null, initialLoadFlags: EngineSession.LoadUrlFlags = EngineSession.LoadUrlFlags.none() diff --git a/components/browser/state/src/main/java/mozilla/components/browser/state/state/SessionState.kt b/components/browser/state/src/main/java/mozilla/components/browser/state/state/SessionState.kt index 6cc4573a8de..490274ba70b 100644 --- a/components/browser/state/src/main/java/mozilla/components/browser/state/state/SessionState.kt +++ b/components/browser/state/src/main/java/mozilla/components/browser/state/state/SessionState.kt @@ -4,6 +4,10 @@ package mozilla.components.browser.state.state +import mozilla.components.support.utils.EXTRA_ACTIVITY_REFERRER_CATEGORY +import mozilla.components.support.utils.EXTRA_ACTIVITY_REFERRER_PACKAGE +import mozilla.components.support.utils.SafeIntent + /** * Interface for states that contain a [ContentState] and can be accessed via an [id]. * @@ -45,61 +49,156 @@ interface SessionState { /** * Represents the origin of a session to describe how and why it was created. + * @param id A unique identifier, exists for serialization purposes. */ - enum class Source { - /** - * Created to handle an ACTION_SEND (share) intent - */ - ACTION_SEND, + @Suppress("UNUSED_PARAMETER", "MagicNumber") + sealed class Source(val id: Int) { + companion object { + /** + * Initializes a [Source] of a correct type from its component properties. + * Intended use is for restoring persisted state. + */ + fun restore(sourceId: Int?, packageId: String?, packageCategory: Int?): Source { + val caller = if (packageId != null) { + ExternalPackage(packageId, PackageCategory.fromInt(packageCategory)) + } else { + null + } + return when (sourceId) { + 1 -> External.ActionSend(caller) + 2 -> External.ActionView(caller) + 3 -> External.ActionSearch(caller) + 4 -> External.CustomTab(caller) + // We only care about restoring 'external' types, so collapse other source types. + // This also silently handles abnormalities (like unknown or null sourceId). + else -> Internal.Restored + } + } + } /** - * Created to handle an ACTION_SEARCH and ACTION_WEB_SEARCH intent + * Describes sessions of external origins, i.e. from outside of the application. */ - ACTION_SEARCH, + sealed class External(id: Int, open val caller: ExternalPackage?) : Source(id) { + /** + * Created to handle an ACTION_SEND (share) intent. + */ + data class ActionSend(override val caller: ExternalPackage?) : External(1, caller) - /** - * Created to handle an ACTION_VIEW intent - */ - ACTION_VIEW, + /** + * Created to handle an ACTION_VIEW intent. + */ + data class ActionView(override val caller: ExternalPackage?) : External(2, caller) - /** - * Created to handle a CustomTabs intent - */ - CUSTOM_TAB, + /** + * Created to handle an ACTION_SEARCH and ACTION_WEB_SEARCH intent. + */ + data class ActionSearch(override val caller: ExternalPackage?) : External(3, caller) - /** - * User interacted with the home screen - */ - HOME_SCREEN, + /** + * Created to handle a CustomTabs intent of external origin. + */ + data class CustomTab(override val caller: ExternalPackage?) : External(4, caller) + } /** - * User interacted with a menu + * Describes sessions of internal origin, i.e. from within of the application. */ - MENU, + sealed class Internal(id: Int) : Source(id) { + /** + * User interacted with the home screen. + */ + object HomeScreen : Internal(5) - /** - * User opened a new tab - */ - NEW_TAB, + /** + * User interacted with a menu. + */ + object Menu : Internal(6) - /** - * Default value and for testing purposes - */ - NONE, + /** + * User opened a new tab. + */ + object NewTab : Internal(7) - /** - * Default value and for testing purposes - */ - TEXT_SELECTION, + /** + * Default value and for testing purposes. + */ + object None : Internal(8) - /** - * User entered a URL or search term - */ - USER_ENTERED, + /** + * Default value and for testing purposes. + */ + object TextSelection : Internal(9) + /** + * User entered a URL or search term. + */ + object UserEntered : Internal(10) + + /** + * This session was restored. + */ + object Restored : Internal(11) + + /** + * Created to handle a CustomTabs intent of internal origin. + */ + object CustomTab : Internal(12) + } + } +} + +/** + * Describes a category of an external package. + */ +@Suppress("MagicNumber") +enum class PackageCategory(val id: Int) { + UNKNOWN(-1), + GAME(0), + AUDIO(1), + VIDEO(2), + IMAGE(3), + SOCIAL(4), + NEWS(5), + MAPS(6), + PRODUCTIVITY(7); + + companion object { /** - * This session was restored + * Maps an int category (as it can be obtained from a package manager) to our internal representation. */ - RESTORED + fun fromInt(id: Int?): PackageCategory = when (id) { + 0 -> GAME + 1 -> AUDIO + 2 -> VIDEO + 3 -> IMAGE + 4 -> SOCIAL + 5 -> NEWS + 6 -> MAPS + 7 -> PRODUCTIVITY + -1 -> UNKNOWN + null -> UNKNOWN + else -> UNKNOWN + } + } +} + +/** + * Describes an external package. + * @param packageId An Android package id. + * @param category A [PackageCategory] as defined by the application. + */ +data class ExternalPackage(val packageId: String, val category: PackageCategory) + +/** + * Produces an [ExternalPackage] based on extras present in this intent. + */ +fun SafeIntent.externalPackage(): ExternalPackage? { + val referrerPackage = this.getStringExtra(EXTRA_ACTIVITY_REFERRER_PACKAGE) + val referrerCategory = this.getIntExtra(EXTRA_ACTIVITY_REFERRER_CATEGORY, -1) + return if (referrerPackage != null) { + ExternalPackage(referrerPackage, PackageCategory.fromInt(referrerCategory)) + } else { + null } } diff --git a/components/browser/state/src/main/java/mozilla/components/browser/state/state/TabSessionState.kt b/components/browser/state/src/main/java/mozilla/components/browser/state/state/TabSessionState.kt index a71ba3f1842..7f384b1be4e 100644 --- a/components/browser/state/src/main/java/mozilla/components/browser/state/state/TabSessionState.kt +++ b/components/browser/state/src/main/java/mozilla/components/browser/state/state/TabSessionState.kt @@ -38,7 +38,7 @@ data class TabSessionState( override val extensionState: Map = emptyMap(), override val mediaSessionState: MediaSessionState? = null, override val contextId: String? = null, - override val source: SessionState.Source = SessionState.Source.NONE, + override val source: SessionState.Source = SessionState.Source.Internal.None, val parentId: String? = null, val lastAccess: Long = 0L, val createdAt: Long = System.currentTimeMillis(), @@ -84,7 +84,7 @@ fun createTab( lastAccess: Long = 0L, createdAt: Long = System.currentTimeMillis(), lastMediaAccessState: LastMediaAccessState = LastMediaAccessState(), - source: SessionState.Source = SessionState.Source.NONE, + source: SessionState.Source = SessionState.Source.Internal.None, engineSession: EngineSession? = null, engineSessionState: EngineSessionState? = null, crashed: Boolean = false, diff --git a/components/browser/state/src/main/java/mozilla/components/browser/state/state/recover/RecoverableTab.kt b/components/browser/state/src/main/java/mozilla/components/browser/state/state/recover/RecoverableTab.kt index ea56735fa29..e6f4678379b 100644 --- a/components/browser/state/src/main/java/mozilla/components/browser/state/state/recover/RecoverableTab.kt +++ b/components/browser/state/src/main/java/mozilla/components/browser/state/state/recover/RecoverableTab.kt @@ -6,6 +6,7 @@ package mozilla.components.browser.state.state.recover import mozilla.components.browser.state.state.LastMediaAccessState import mozilla.components.browser.state.state.ReaderState +import mozilla.components.browser.state.state.SessionState.Source import mozilla.components.browser.state.state.TabSessionState import mozilla.components.browser.state.state.createTab import mozilla.components.concept.engine.EngineSessionState @@ -30,6 +31,8 @@ import mozilla.components.concept.storage.HistoryMetadataKey * @property createdAt Timestamp of the tab's creation. * @property lastMediaAccessState Details about the last time was playing in this tab. * @property private If tab was private. + * @property historyMetadata The last [HistoryMetadataKey] of the tab. + * @property source The last [Source] of the tab. */ data class RecoverableTab( val id: String, @@ -43,7 +46,8 @@ data class RecoverableTab( val createdAt: Long = 0, val lastMediaAccessState: LastMediaAccessState = LastMediaAccessState(), val private: Boolean = false, - val historyMetadata: HistoryMetadataKey? = null + val historyMetadata: HistoryMetadataKey? = null, + val source: Source = Source.Internal.Restored ) /** @@ -61,7 +65,8 @@ fun TabSessionState.toRecoverableTab() = RecoverableTab( createdAt = createdAt, lastMediaAccessState = lastMediaAccessState, private = content.private, - historyMetadata = historyMetadata + historyMetadata = historyMetadata, + source = source ) /** @@ -78,14 +83,10 @@ fun RecoverableTab.toTabSessionState() = createTab( lastAccess = lastAccess, createdAt = createdAt, lastMediaAccessState = lastMediaAccessState, - private = private + historyMetadata = historyMetadata, + source = source ) -/** - * Creates a list of [RecoverableTab]s from a List of [TabSessionState]s. - */ -fun List.toRecoverableTabs() = map { it.toRecoverableTab() } - /** * Creates a list of [TabSessionState]s from a List of [TabSessionState]s. */ diff --git a/components/browser/state/src/test/java/mozilla/components/browser/state/action/CustomTabListActionTest.kt b/components/browser/state/src/test/java/mozilla/components/browser/state/action/CustomTabListActionTest.kt index 24f9d36835c..219d9883e53 100644 --- a/components/browser/state/src/test/java/mozilla/components/browser/state/action/CustomTabListActionTest.kt +++ b/components/browser/state/src/test/java/mozilla/components/browser/state/action/CustomTabListActionTest.kt @@ -25,13 +25,17 @@ class CustomTabListActionTest { assertEquals(0, store.state.customTabs.size) val config = CustomTabConfig() - val customTab = createCustomTab("https://www.mozilla.org", config = config) + val customTab = createCustomTab( + "https://www.mozilla.org", + config = config, + source = SessionState.Source.Internal.CustomTab + ) store.dispatch(CustomTabListAction.AddCustomTabAction(customTab)).joinBlocking() assertEquals(0, store.state.tabs.size) assertEquals(1, store.state.customTabs.size) - assertEquals(SessionState.Source.CUSTOM_TAB, store.state.customTabs[0].source) + assertEquals(SessionState.Source.Internal.CustomTab, store.state.customTabs[0].source) assertEquals(customTab, store.state.customTabs[0]) assertSame(config, store.state.customTabs[0].config) } diff --git a/components/browser/state/src/test/java/mozilla/components/browser/state/action/TabListActionTest.kt b/components/browser/state/src/test/java/mozilla/components/browser/state/action/TabListActionTest.kt index 7426e30df95..3e35171e9a4 100644 --- a/components/browser/state/src/test/java/mozilla/components/browser/state/action/TabListActionTest.kt +++ b/components/browser/state/src/test/java/mozilla/components/browser/state/action/TabListActionTest.kt @@ -11,6 +11,7 @@ import mozilla.components.browser.state.state.createCustomTab import mozilla.components.browser.state.state.createTab import mozilla.components.browser.state.store.BrowserStore import mozilla.components.support.test.ext.joinBlocking +import mozilla.components.support.test.mock import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull import org.junit.Assert.assertNull @@ -98,14 +99,14 @@ class TabListActionTest { val store = BrowserStore() val tab1 = createTab("https://www.mozilla.org") - val tab2 = createTab("https://www.firefox.com", source = SessionState.Source.MENU) + val tab2 = createTab("https://www.firefox.com", source = SessionState.Source.Internal.Menu) store.dispatch(TabListAction.AddTabAction(tab1)).joinBlocking() store.dispatch(TabListAction.AddTabAction(tab2)).joinBlocking() assertEquals(2, store.state.tabs.size) - assertEquals(SessionState.Source.NONE, store.state.tabs[0].source) - assertEquals(SessionState.Source.MENU, store.state.tabs[1].source) + assertEquals(SessionState.Source.Internal.None, store.state.tabs[0].source) + assertEquals(SessionState.Source.Internal.Menu, store.state.tabs[1].source) } @Test @@ -233,7 +234,8 @@ class TabListActionTest { createTab(id = "a", url = "https://www.mozilla.org") ), customTabs = listOf( - createCustomTab(id = "b", url = "https://www.firefox.com") + createCustomTab(id = "b", url = "https://www.firefox.com"), + createCustomTab(id = "c", url = "https://www.firefox.com/hello", source = SessionState.Source.External.CustomTab(mock())) ), selectedTabId = "a" ) @@ -291,7 +293,7 @@ class TabListActionTest { ), customTabs = listOf( createCustomTab(id = "a1", url = "https://www.firefox.com"), - createCustomTab(id = "b1", url = "https://hubs.mozilla.com") + createCustomTab(id = "b1", url = "https://hubs.mozilla.com", source = SessionState.Source.External.CustomTab(mock())) ), selectedTabId = "d" ) @@ -324,7 +326,7 @@ class TabListActionTest { ), customTabs = listOf( createCustomTab(id = "a1", url = "https://www.firefox.com"), - createCustomTab(id = "b1", url = "https://hubs.mozilla.com") + createCustomTab(id = "b1", url = "https://hubs.mozilla.com", source = SessionState.Source.External.CustomTab(mock())) ), selectedTabId = "d" ) @@ -583,7 +585,8 @@ class TabListActionTest { createTab(id = "b", url = "https://www.firefox.com", private = true) ), customTabs = listOf( - createCustomTab(id = "a1", url = "https://www.firefox.com") + createCustomTab(id = "a1", url = "https://www.firefox.com"), + createCustomTab(id = "a2", url = "https://www.firefox.com/hello", source = SessionState.Source.External.CustomTab(mock())) ), selectedTabId = "a" ) @@ -593,8 +596,8 @@ class TabListActionTest { assertTrue(store.state.tabs.isEmpty()) assertNull(store.state.selectedTabId) - assertEquals(1, store.state.customTabs.size) - assertEquals("a1", store.state.customTabs.last().id) + assertEquals(2, store.state.customTabs.size) + assertEquals("a2", store.state.customTabs.last().id) } @Test diff --git a/components/feature/customtabs/src/main/java/mozilla/components/feature/customtabs/CustomTabIntentProcessor.kt b/components/feature/customtabs/src/main/java/mozilla/components/feature/customtabs/CustomTabIntentProcessor.kt index e49c0e1f756..905e75d1dac 100644 --- a/components/feature/customtabs/src/main/java/mozilla/components/feature/customtabs/CustomTabIntentProcessor.kt +++ b/components/feature/customtabs/src/main/java/mozilla/components/feature/customtabs/CustomTabIntentProcessor.kt @@ -9,6 +9,8 @@ import android.content.Intent.ACTION_VIEW import android.content.res.Resources import android.provider.Browser import androidx.annotation.VisibleForTesting +import mozilla.components.browser.state.state.SessionState +import mozilla.components.browser.state.state.externalPackage import mozilla.components.feature.intent.ext.putSessionId import mozilla.components.feature.intent.processing.IntentProcessor import mozilla.components.feature.tabs.CustomTabsUseCases @@ -54,7 +56,14 @@ class CustomTabIntentProcessor( return if (!url.isNullOrEmpty() && matches(intent)) { val config = createCustomTabConfigFromIntent(intent, resources) - val customTabId = addCustomTabUseCase(url, config, isPrivate, getAdditionalHeaders(safeIntent)) + val caller = safeIntent.externalPackage() + val customTabId = addCustomTabUseCase( + url, + config, + isPrivate, + getAdditionalHeaders(safeIntent), + source = SessionState.Source.External.CustomTab(caller) + ) intent.putSessionId(customTabId) true diff --git a/components/feature/customtabs/src/test/java/mozilla/components/feature/customtabs/CustomTabIntentProcessorTest.kt b/components/feature/customtabs/src/test/java/mozilla/components/feature/customtabs/CustomTabIntentProcessorTest.kt index 6939994dedf..521726f404c 100644 --- a/components/feature/customtabs/src/test/java/mozilla/components/feature/customtabs/CustomTabIntentProcessorTest.kt +++ b/components/feature/customtabs/src/test/java/mozilla/components/feature/customtabs/CustomTabIntentProcessorTest.kt @@ -77,7 +77,7 @@ class CustomTabIntentProcessorTest { val customTab = store.state.findCustomTab(customTabId!!) assertNotNull(customTab!!) assertEquals("http://mozilla.org", customTab.content.url) - assertEquals(Source.CUSTOM_TAB, customTab.source) + assertTrue(customTab.source is Source.External.CustomTab) assertNotNull(customTab.config) assertFalse(customTab.content.private) } @@ -126,7 +126,7 @@ class CustomTabIntentProcessorTest { val customTab = store.state.findCustomTab(customTabId!!) assertNotNull(customTab!!) assertEquals("http://mozilla.org", customTab.content.url) - assertEquals(Source.CUSTOM_TAB, customTab.source) + assertTrue(customTab.source is Source.External.CustomTab) assertNotNull(customTab.config) assertFalse(customTab.content.private) } @@ -168,7 +168,7 @@ class CustomTabIntentProcessorTest { val customTab = store.state.findCustomTab(customTabId!!) assertNotNull(customTab!!) assertEquals("http://mozilla.org", customTab.content.url) - assertEquals(Source.CUSTOM_TAB, customTab.source) + assertTrue(customTab.source is Source.External.CustomTab) assertNotNull(customTab.config) assertTrue(customTab.content.private) } diff --git a/components/feature/intent/src/main/java/mozilla/components/feature/intent/processing/TabIntentProcessor.kt b/components/feature/intent/src/main/java/mozilla/components/feature/intent/processing/TabIntentProcessor.kt index db48e816ee6..799304d6c26 100644 --- a/components/feature/intent/src/main/java/mozilla/components/feature/intent/processing/TabIntentProcessor.kt +++ b/components/feature/intent/src/main/java/mozilla/components/feature/intent/processing/TabIntentProcessor.kt @@ -13,7 +13,8 @@ import android.content.Intent.ACTION_VIEW import android.content.Intent.ACTION_WEB_SEARCH import android.content.Intent.EXTRA_TEXT import android.nfc.NfcAdapter.ACTION_NDEF_DISCOVERED -import mozilla.components.browser.state.state.SessionState.Source +import mozilla.components.browser.state.state.SessionState +import mozilla.components.browser.state.state.externalPackage import mozilla.components.concept.engine.EngineSession.LoadUrlFlags import mozilla.components.feature.search.SearchUseCases import mozilla.components.feature.session.SessionUseCases @@ -47,10 +48,11 @@ class TabIntentProcessor( return if (url.isNullOrEmpty()) { false } else { + val caller = intent.externalPackage() tabsUseCases.selectOrAddTab( url, private = isPrivate, - source = Source.ACTION_VIEW, + source = SessionState.Source.External.ActionView(caller), flags = LoadUrlFlags.external() ) true @@ -68,10 +70,11 @@ class TabIntentProcessor( false } else { val url = WebURLFinder(extraText).bestWebURL() + val source = SessionState.Source.External.ActionSend(intent.externalPackage()) if (url != null) { - addNewTab(url, Source.ACTION_SEND) + addNewTab(url, source) } else { - newTabSearchUseCase(extraText, Source.ACTION_SEND) + newTabSearchUseCase(extraText, source) } true } @@ -83,16 +86,17 @@ class TabIntentProcessor( return if (searchQuery.isNullOrBlank()) { false } else { + val source = SessionState.Source.External.ActionSearch(intent.externalPackage()) if (searchQuery.isUrl()) { - addNewTab(searchQuery, Source.ACTION_SEARCH) + addNewTab(searchQuery, source) } else { - newTabSearchUseCase(searchQuery, Source.ACTION_SEARCH) + newTabSearchUseCase(searchQuery, source) } true } } - private fun addNewTab(url: String, source: Source) { + private fun addNewTab(url: String, source: SessionState.Source) { tabsUseCases.addTab(url, source = source, flags = LoadUrlFlags.external(), private = isPrivate) } diff --git a/components/feature/intent/src/test/java/mozilla/components/feature/intent/processing/TabIntentProcessorTest.kt b/components/feature/intent/src/test/java/mozilla/components/feature/intent/processing/TabIntentProcessorTest.kt index 49e3299fb62..754a4decb81 100644 --- a/components/feature/intent/src/test/java/mozilla/components/feature/intent/processing/TabIntentProcessorTest.kt +++ b/components/feature/intent/src/test/java/mozilla/components/feature/intent/processing/TabIntentProcessorTest.kt @@ -18,6 +18,7 @@ import mozilla.components.browser.state.selector.findTabByUrl import mozilla.components.browser.state.selector.selectedTab import mozilla.components.browser.state.state.BrowserState import mozilla.components.browser.state.state.SearchState +import mozilla.components.browser.state.state.SessionState import mozilla.components.browser.state.state.createTab import mozilla.components.browser.state.store.BrowserStore import mozilla.components.concept.engine.Engine @@ -35,6 +36,7 @@ import mozilla.components.support.test.whenever import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertNotNull +import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Rule import org.junit.Test @@ -103,6 +105,7 @@ class TabIntentProcessorTest { handler.process(intent) store.waitUntilIdle() assertEquals(1, store.state.tabs.size) + assertTrue(store.state.tabs[0].source is SessionState.Source.External.ActionView) val tab = store.state.findTabByUrl("https://mozilla.org") assertNotNull(tab) @@ -111,11 +114,16 @@ class TabIntentProcessorTest { store.dispatch(TabListAction.AddTabAction(otherTab, select = true)).joinBlocking() assertEquals(2, store.state.tabs.size) assertEquals(otherTab, store.state.selectedTab) + assertTrue(store.state.tabs[1].source is SessionState.Source.Internal.None) + // processing the same intent again doesn't add an additional tab handler.process(intent) store.waitUntilIdle() assertEquals(2, store.state.tabs.size) assertEquals(tab, store.state.selectedTab) + // sources of existing tabs weren't affected + assertTrue(store.state.tabs[0].source is SessionState.Source.External.ActionView) + assertTrue(store.state.tabs[1].source is SessionState.Source.Internal.None) } @Test @@ -130,6 +138,7 @@ class TabIntentProcessorTest { handler.process(intent) store.waitUntilIdle() assertEquals(1, store.state.tabs.size) + assertTrue(store.state.tabs[0].source is SessionState.Source.External.ActionView) val tab = store.state.findTabByUrl("https://mozilla.org") assertNotNull(tab) @@ -185,30 +194,35 @@ class TabIntentProcessorTest { store.waitUntilIdle() assertEquals(1, store.state.tabs.size) assertEquals("https://mozilla.org", store.state.tabs[0].content.url) + assertTrue(store.state.tabs[0].source is SessionState.Source.External.ActionSend) whenever(intent.getStringExtra(Intent.EXTRA_TEXT)).thenReturn("see https://getpocket.com") handler.process(intent) store.waitUntilIdle() assertEquals(2, store.state.tabs.size) assertEquals("https://getpocket.com", store.state.tabs[1].content.url) + assertTrue(store.state.tabs[1].source is SessionState.Source.External.ActionSend) whenever(intent.getStringExtra(Intent.EXTRA_TEXT)).thenReturn("see https://firefox.com and https://mozilla.org") handler.process(intent) store.waitUntilIdle() assertEquals(3, store.state.tabs.size) assertEquals("https://firefox.com", store.state.tabs[2].content.url) + assertTrue(store.state.tabs[2].source is SessionState.Source.External.ActionSend) whenever(intent.getStringExtra(Intent.EXTRA_TEXT)).thenReturn("checkout the Tweet: https://tweets.mozilla.com") handler.process(intent) store.waitUntilIdle() assertEquals(4, store.state.tabs.size) assertEquals("https://tweets.mozilla.com", store.state.tabs[3].content.url) + assertTrue(store.state.tabs[3].source is SessionState.Source.External.ActionSend) whenever(intent.getStringExtra(Intent.EXTRA_TEXT)).thenReturn("checkout the Tweet: HTTPS://tweets.mozilla.org") handler.process(intent) store.waitUntilIdle() assertEquals(5, store.state.tabs.size) assertEquals("HTTPS://tweets.mozilla.org", store.state.tabs[4].content.url) + assertTrue(store.state.tabs[4].source is SessionState.Source.External.ActionSend) } @Test @@ -229,6 +243,7 @@ class TabIntentProcessorTest { assertEquals(1, store.state.tabs.size) assertEquals(searchUrl, store.state.tabs[0].content.url) assertEquals(searchTerms, store.state.tabs[0].content.searchTerms) + assertTrue(store.state.tabs[0].source is SessionState.Source.External.ActionSend) } @Test @@ -270,6 +285,7 @@ class TabIntentProcessorTest { assertEquals(1, store.state.tabs.size) assertEquals("http://mozilla.org", store.state.tabs[0].content.url) assertEquals("", store.state.tabs[0].content.searchTerms) + assertTrue(store.state.tabs[0].source is SessionState.Source.External.ActionSearch) } @Test @@ -290,6 +306,7 @@ class TabIntentProcessorTest { assertEquals(1, store.state.tabs.size) assertEquals(searchUrl, store.state.tabs[0].content.url) assertEquals(searchTerms, store.state.tabs[0].content.searchTerms) + assertTrue(store.state.tabs[0].source is SessionState.Source.External.ActionSearch) } @Test @@ -318,6 +335,7 @@ class TabIntentProcessorTest { assertEquals(1, store.state.tabs.size) assertEquals("http://mozilla.org", store.state.tabs[0].content.url) assertEquals("", store.state.tabs[0].content.searchTerms) + assertTrue(store.state.tabs[0].source is SessionState.Source.External.ActionSearch) } @Test @@ -337,5 +355,6 @@ class TabIntentProcessorTest { assertEquals(1, store.state.tabs.size) assertEquals(searchUrl, store.state.tabs[0].content.url) assertEquals(searchTerms, store.state.tabs[0].content.searchTerms) + assertTrue(store.state.tabs[0].source is SessionState.Source.External.ActionSearch) } } diff --git a/components/feature/pwa/src/main/java/mozilla/components/feature/pwa/intent/TrustedWebActivityIntentProcessor.kt b/components/feature/pwa/src/main/java/mozilla/components/feature/pwa/intent/TrustedWebActivityIntentProcessor.kt index 79380fd5afa..c115a3350dd 100644 --- a/components/feature/pwa/src/main/java/mozilla/components/feature/pwa/intent/TrustedWebActivityIntentProcessor.kt +++ b/components/feature/pwa/src/main/java/mozilla/components/feature/pwa/intent/TrustedWebActivityIntentProcessor.kt @@ -59,7 +59,7 @@ class TrustedWebActivityIntentProcessor( val tabId = addNewTabUseCase.invoke( url, - source = SessionState.Source.HOME_SCREEN, + source = SessionState.Source.Internal.HomeScreen, customTabConfig = customTabConfig ) diff --git a/components/feature/pwa/src/main/java/mozilla/components/feature/pwa/intent/WebAppIntentProcessor.kt b/components/feature/pwa/src/main/java/mozilla/components/feature/pwa/intent/WebAppIntentProcessor.kt index c5e38103896..5cce6416015 100644 --- a/components/feature/pwa/src/main/java/mozilla/components/feature/pwa/intent/WebAppIntentProcessor.kt +++ b/components/feature/pwa/src/main/java/mozilla/components/feature/pwa/intent/WebAppIntentProcessor.kt @@ -83,7 +83,7 @@ class WebAppIntentProcessor( private fun createSession(webAppManifest: WebAppManifest, url: String): String { return addTabUseCase.invoke( url = url, - source = Source.HOME_SCREEN, + source = Source.Internal.HomeScreen, webAppManifest = webAppManifest, customTabConfig = webAppManifest.toCustomTabConfig() ) diff --git a/components/feature/pwa/src/test/java/mozilla/components/feature/pwa/intent/TrustedWebActivityIntentProcessorTest.kt b/components/feature/pwa/src/test/java/mozilla/components/feature/pwa/intent/TrustedWebActivityIntentProcessorTest.kt index 9bcf80afe36..fcb0ced8526 100644 --- a/components/feature/pwa/src/test/java/mozilla/components/feature/pwa/intent/TrustedWebActivityIntentProcessorTest.kt +++ b/components/feature/pwa/src/test/java/mozilla/components/feature/pwa/intent/TrustedWebActivityIntentProcessorTest.kt @@ -90,7 +90,7 @@ class TrustedWebActivityIntentProcessorTest { verify(addTabUseCase).invoke( "https://example.com", - source = SessionState.Source.HOME_SCREEN, + source = SessionState.Source.Internal.HomeScreen, customTabConfig = CustomTabConfig(externalAppType = ExternalAppType.TRUSTED_WEB_ACTIVITY) ) } diff --git a/components/feature/pwa/src/test/java/mozilla/components/feature/pwa/intent/WebAppIntentProcessorTest.kt b/components/feature/pwa/src/test/java/mozilla/components/feature/pwa/intent/WebAppIntentProcessorTest.kt index 0bbeb7ccf6a..e81466b4b88 100644 --- a/components/feature/pwa/src/test/java/mozilla/components/feature/pwa/intent/WebAppIntentProcessorTest.kt +++ b/components/feature/pwa/src/test/java/mozilla/components/feature/pwa/intent/WebAppIntentProcessorTest.kt @@ -74,7 +74,7 @@ class WebAppIntentProcessorTest { whenever( addTabUseCase.invoke( url = "https://mozilla.com", - source = SessionState.Source.HOME_SCREEN, + source = SessionState.Source.Internal.HomeScreen, customTabConfig = CustomTabConfig( externalAppType = ExternalAppType.PROGRESSIVE_WEB_APP, enableUrlbarHiding = true, @@ -116,7 +116,7 @@ class WebAppIntentProcessorTest { verify(addTabUseCase).invoke( url = "https://mozilla.com", - source = SessionState.Source.HOME_SCREEN, + source = SessionState.Source.Internal.HomeScreen, customTabConfig = CustomTabConfig( externalAppType = ExternalAppType.PROGRESSIVE_WEB_APP, enableUrlbarHiding = true, diff --git a/components/feature/search/src/main/java/mozilla/components/feature/search/SearchUseCases.kt b/components/feature/search/src/main/java/mozilla/components/feature/search/SearchUseCases.kt index f33ecd5ff05..978ccece4dd 100644 --- a/components/feature/search/src/main/java/mozilla/components/feature/search/SearchUseCases.kt +++ b/components/feature/search/src/main/java/mozilla/components/feature/search/SearchUseCases.kt @@ -111,7 +111,7 @@ class SearchUseCases( ) { invoke( searchTerms, - source = SessionState.Source.NONE, + source = SessionState.Source.Internal.None, selected = true, private = isPrivate, searchEngine = searchEngine, diff --git a/components/feature/search/src/test/java/mozilla/components/feature/search/BrowserStoreSeachAdapterTest.kt b/components/feature/search/src/test/java/mozilla/components/feature/search/BrowserStoreSeachAdapterTest.kt index 29e2a65fd11..89139cef0be 100644 --- a/components/feature/search/src/test/java/mozilla/components/feature/search/BrowserStoreSeachAdapterTest.kt +++ b/components/feature/search/src/test/java/mozilla/components/feature/search/BrowserStoreSeachAdapterTest.kt @@ -6,6 +6,7 @@ package mozilla.components.feature.search import mozilla.components.browser.state.action.ContentAction import mozilla.components.browser.state.state.BrowserState +import mozilla.components.browser.state.state.SessionState import mozilla.components.browser.state.state.createCustomTab import mozilla.components.browser.state.state.createTab import mozilla.components.browser.state.store.BrowserStore @@ -28,7 +29,7 @@ class BrowserStoreSearchAdapterTest { private lateinit var browserStore: BrowserStore private val state = BrowserState( tabs = listOf(createTab(id = SELECTED_TAB_ID, url = "https://mozilla.org", private = true)), - customTabs = listOf(createCustomTab(id = CUSTOM_TAB_ID, url = "https://firefox.com")), + customTabs = listOf(createCustomTab(id = CUSTOM_TAB_ID, url = "https://firefox.com", source = SessionState.Source.Internal.CustomTab)), selectedTabId = SELECTED_TAB_ID ) diff --git a/components/feature/search/src/test/java/mozilla/components/feature/search/SearchUseCasesTest.kt b/components/feature/search/src/test/java/mozilla/components/feature/search/SearchUseCasesTest.kt index b841ab01e60..773503266cb 100644 --- a/components/feature/search/src/test/java/mozilla/components/feature/search/SearchUseCasesTest.kt +++ b/components/feature/search/src/test/java/mozilla/components/feature/search/SearchUseCasesTest.kt @@ -100,14 +100,14 @@ class SearchUseCasesTest { whenever(tabsUseCases.addTab).thenReturn(newTabUseCase) whenever(newTabUseCase(searchUrl)).thenReturn("2342") - useCases.newTabSearch(searchTerms, SessionState.Source.NEW_TAB) + useCases.newTabSearch(searchTerms, SessionState.Source.Internal.NewTab) store.waitUntilIdle() verify(newTabUseCase).invoke( searchUrl, parentId = null, selectTab = true, - source = SessionState.Source.NEW_TAB + source = SessionState.Source.Internal.NewTab ) val searchTermsAction = middleware.findFirstAction(ContentAction.UpdateSearchTermsAction::class) @@ -128,7 +128,7 @@ class SearchUseCasesTest { searchUrl, parentId = null, selectTab = true, - source = SessionState.Source.NEW_TAB + source = SessionState.Source.Internal.NewTab ) val searchTermsAction = middleware.findFirstAction(ContentAction.UpdateSearchTermsAction::class) @@ -140,7 +140,7 @@ class SearchUseCasesTest { fun newPrivateTabSearch() { val newTabUseCase: TabsUseCases.AddNewTabUseCase = mock() whenever(tabsUseCases.addTab).thenReturn(newTabUseCase) - whenever(newTabUseCase(searchUrl, source = SessionState.Source.NONE, private = true)).thenReturn("1177") + whenever(newTabUseCase(searchUrl, source = SessionState.Source.Internal.None, private = true)).thenReturn("1177") useCases.newPrivateTabSearch.invoke(searchTerms) store.waitUntilIdle() @@ -150,7 +150,7 @@ class SearchUseCasesTest { parentId = null, selectTab = true, private = true, - source = SessionState.Source.NONE + source = SessionState.Source.Internal.None ) val searchTermsAction = middleware.findFirstAction(ContentAction.UpdateSearchTermsAction::class) @@ -162,7 +162,7 @@ class SearchUseCasesTest { fun newPrivateTabSearchWithParentSession() { val newTabUseCase: TabsUseCases.AddNewTabUseCase = mock() whenever(tabsUseCases.addTab).thenReturn(newTabUseCase) - whenever(newTabUseCase(searchUrl, source = SessionState.Source.NONE, parentId = "test-parent", private = true)).thenReturn("1177") + whenever(newTabUseCase(searchUrl, source = SessionState.Source.Internal.None, parentId = "test-parent", private = true)).thenReturn("1177") useCases.newPrivateTabSearch.invoke(searchTerms, parentSessionId = "test-parent") @@ -173,7 +173,7 @@ class SearchUseCasesTest { parentId = "test-parent", selectTab = true, private = true, - source = SessionState.Source.NONE + source = SessionState.Source.Internal.None ) val searchTermsAction = middleware.findFirstAction(ContentAction.UpdateSearchTermsAction::class) diff --git a/components/feature/tabs/src/main/java/mozilla/components/feature/tabs/CustomTabsUseCases.kt b/components/feature/tabs/src/main/java/mozilla/components/feature/tabs/CustomTabsUseCases.kt index 8aae54fc0d8..990ea20684a 100644 --- a/components/feature/tabs/src/main/java/mozilla/components/feature/tabs/CustomTabsUseCases.kt +++ b/components/feature/tabs/src/main/java/mozilla/components/feature/tabs/CustomTabsUseCases.kt @@ -37,7 +37,7 @@ class CustomTabsUseCases( customTabConfig: CustomTabConfig, private: Boolean = false, additionalHeaders: Map? = null, - source: SessionState.Source = SessionState.Source.CUSTOM_TAB + source: SessionState.Source ): String { val loadUrlFlags = EngineSession.LoadUrlFlags.external() val tab = createCustomTab( @@ -66,7 +66,7 @@ class CustomTabsUseCases( */ operator fun invoke( url: String, - source: SessionState.Source = SessionState.Source.CUSTOM_TAB, + source: SessionState.Source, customTabConfig: CustomTabConfig, webAppManifest: WebAppManifest ): String { diff --git a/components/feature/tabs/src/main/java/mozilla/components/feature/tabs/TabsUseCases.kt b/components/feature/tabs/src/main/java/mozilla/components/feature/tabs/TabsUseCases.kt index fab258f680c..01451845979 100644 --- a/components/feature/tabs/src/main/java/mozilla/components/feature/tabs/TabsUseCases.kt +++ b/components/feature/tabs/src/main/java/mozilla/components/feature/tabs/TabsUseCases.kt @@ -14,7 +14,7 @@ import mozilla.components.browser.state.action.TabListAction import mozilla.components.browser.state.action.UndoAction import mozilla.components.browser.state.selector.findTab import mozilla.components.browser.state.selector.findTabByUrl -import mozilla.components.browser.state.state.SessionState.Source +import mozilla.components.browser.state.state.SessionState import mozilla.components.browser.state.state.TabSessionState import mozilla.components.browser.state.state.createTab import mozilla.components.browser.state.state.recover.RecoverableTab @@ -144,7 +144,7 @@ class TabsUseCases( flags: LoadUrlFlags = LoadUrlFlags.none(), contextId: String? = null, engineSession: EngineSession? = null, - source: Source = Source.NEW_TAB, + source: SessionState.Source = SessionState.Source.Internal.NewTab, searchTerms: String = "", private: Boolean = false ): String { @@ -212,7 +212,7 @@ class TabsUseCases( parentId: String? = null, flags: LoadUrlFlags = LoadUrlFlags.none(), engineSession: EngineSession? = null, - source: Source = Source.NEW_TAB, + source: SessionState.Source = SessionState.Source.Internal.NewTab, searchTerms: String? = null ): String { val tab = createTab( @@ -412,7 +412,7 @@ class TabsUseCases( operator fun invoke( url: String, private: Boolean = false, - source: Source = Source.NEW_TAB, + source: SessionState.Source = SessionState.Source.Internal.NewTab, flags: LoadUrlFlags = LoadUrlFlags.none() ): String { val existingTab = store.state.findTabByUrl(url) diff --git a/components/support/ktx/src/main/java/mozilla/components/support/ktx/android/util/JsonReader.kt b/components/support/ktx/src/main/java/mozilla/components/support/ktx/android/util/JsonReader.kt index d9953160835..b1d29d000da 100644 --- a/components/support/ktx/src/main/java/mozilla/components/support/ktx/android/util/JsonReader.kt +++ b/components/support/ktx/src/main/java/mozilla/components/support/ktx/android/util/JsonReader.kt @@ -32,3 +32,16 @@ fun JsonReader.nextBooleanOrNull(): Boolean? { nextBoolean() } } + +/** + * Returns the [JsonToken.NUMBER] value of the next token or `null` if the next token + * is [JsonToken.NULL]. + */ +fun JsonReader.nextIntOrNull(): Int? { + return if (peek() == JsonToken.NULL) { + nextNull() + null + } else { + nextInt() + } +} diff --git a/components/support/utils/src/main/java/mozilla/components/support/utils/SafeIntent.kt b/components/support/utils/src/main/java/mozilla/components/support/utils/SafeIntent.kt index 7ecbc9346cf..b96aa877825 100644 --- a/components/support/utils/src/main/java/mozilla/components/support/utils/SafeIntent.kt +++ b/components/support/utils/src/main/java/mozilla/components/support/utils/SafeIntent.kt @@ -96,3 +96,6 @@ class SafeIntent(val unsafe: Intent) { * Returns a [SafeIntent] for the given [Intent]. */ fun Intent.toSafeIntent(): SafeIntent = SafeIntent(this) + +const val EXTRA_ACTIVITY_REFERRER_PACKAGE = "activity_referrer_package" +const val EXTRA_ACTIVITY_REFERRER_CATEGORY = "activity_referrer_category" diff --git a/components/support/webextensions/src/main/java/mozilla/components/support/webextensions/WebExtensionSupport.kt b/components/support/webextensions/src/main/java/mozilla/components/support/webextensions/WebExtensionSupport.kt index 9b31b6c181f..4543779f0fe 100644 --- a/components/support/webextensions/src/main/java/mozilla/components/support/webextensions/WebExtensionSupport.kt +++ b/components/support/webextensions/src/main/java/mozilla/components/support/webextensions/WebExtensionSupport.kt @@ -345,7 +345,7 @@ object WebExtensionSupport { // startup and might not be ready yet. var scope: CoroutineScope? = null scope = store.flowScoped { flow -> - flow.map { state -> state.tabs.filter { it.source == SessionState.Source.RESTORED }.size } + flow.map { state -> state.tabs.filter { it.source == SessionState.Source.Internal.Restored }.size } .ifChanged() .collect { size -> if (size > 0) { diff --git a/components/support/webextensions/src/test/java/mozilla/components/support/webextensions/WebExtensionSupportTest.kt b/components/support/webextensions/src/test/java/mozilla/components/support/webextensions/WebExtensionSupportTest.kt index d1ee5f1936d..7e0a0f5016a 100644 --- a/components/support/webextensions/src/test/java/mozilla/components/support/webextensions/WebExtensionSupportTest.kt +++ b/components/support/webextensions/src/test/java/mozilla/components/support/webextensions/WebExtensionSupportTest.kt @@ -228,7 +228,7 @@ class WebExtensionSupportTest { BrowserStore( BrowserState( customTabs = listOf( - createCustomTab(id = tabId, url = "https://www.mozilla.org", engineSession = engineSession) + createCustomTab(id = tabId, url = "https://www.mozilla.org", engineSession = engineSession, source = SessionState.Source.Internal.CustomTab) ) ) ) @@ -342,7 +342,7 @@ class WebExtensionSupportTest { val store = BrowserStore( BrowserState( customTabs = listOf( - createCustomTab(id = tabId, url = "https://www.mozilla.org", engineSession = engineSession) + createCustomTab(id = tabId, url = "https://www.mozilla.org", engineSession = engineSession, source = SessionState.Source.Internal.CustomTab) ) ) ) @@ -379,7 +379,7 @@ class WebExtensionSupportTest { val customTabEngineSession: EngineSession = mock() val customTab = - createCustomTab(id = "2", url = "https://www.mozilla.org", engineSession = customTabEngineSession) + createCustomTab(id = "2", url = "https://www.mozilla.org", engineSession = customTabEngineSession, source = SessionState.Source.Internal.CustomTab) val store = spy( BrowserStore( @@ -523,7 +523,7 @@ class WebExtensionSupportTest { @Test fun `observes store and registers handlers on new engine sessions`() { val tab = createTab(id = "1", url = "https://www.mozilla.org") - val customTab = createCustomTab(id = "2", url = "https://www.mozilla.org") + val customTab = createCustomTab(id = "2", url = "https://www.mozilla.org", source = SessionState.Source.Internal.CustomTab) val store = spy( BrowserStore( BrowserState( @@ -837,9 +837,9 @@ class WebExtensionSupportTest { val store = BrowserStore( BrowserState( tabs = listOf( - createTab(id = "1", url = "https://www.mozilla.org", source = SessionState.Source.RESTORED), - createTab(id = "2", url = "moz-extension://1234-5678/test", source = SessionState.Source.RESTORED), - createTab(id = "3", url = "moz-extension://1234-5678-9/", source = SessionState.Source.RESTORED) + createTab(id = "1", url = "https://www.mozilla.org", source = SessionState.Source.Internal.Restored), + createTab(id = "2", url = "moz-extension://1234-5678/test", source = SessionState.Source.Internal.Restored), + createTab(id = "3", url = "moz-extension://1234-5678-9/", source = SessionState.Source.Internal.Restored) ) ) ) @@ -888,7 +888,7 @@ class WebExtensionSupportTest { val customTabEngineSession: EngineSession = mock() val customTab = - createCustomTab(id = "2", url = "https://www.mozilla.org", engineSession = customTabEngineSession) + createCustomTab(id = "2", url = "https://www.mozilla.org", engineSession = customTabEngineSession, source = SessionState.Source.Internal.CustomTab) val store = spy( BrowserStore( From 358785f0454a17d40f4a748c41a4e53d530118da Mon Sep 17 00:00:00 2001 From: Grisha Kruglov Date: Wed, 4 Aug 2021 18:01:02 -0700 Subject: [PATCH 2/2] Introduced 'restored' content state for tracking tab restoration --- .../storage/serialize/BrowserStateReader.kt | 8 ++--- .../storage/serialize/BrowserStateWriter.kt | 8 ++--- .../browser/session/storage/serialize/Keys.kt | 5 +-- .../serialize/BrowserStateWriterReaderTest.kt | 16 ++++----- .../state/state/CustomTabSessionState.kt | 3 +- .../browser/state/state/SessionState.kt | 36 +++++++------------ .../browser/state/state/TabSessionState.kt | 4 +++ .../state/state/recover/RecoverableTab.kt | 7 ++-- .../webextensions/WebExtensionSupport.kt | 2 +- .../webextensions/WebExtensionSupportTest.kt | 6 ++-- 10 files changed, 46 insertions(+), 49 deletions(-) diff --git a/components/browser/session-storage/src/main/java/mozilla/components/browser/session/storage/serialize/BrowserStateReader.kt b/components/browser/session-storage/src/main/java/mozilla/components/browser/session/storage/serialize/BrowserStateReader.kt index 73e07fe45be..5e784e4866d 100644 --- a/components/browser/session-storage/src/main/java/mozilla/components/browser/session/storage/serialize/BrowserStateReader.kt +++ b/components/browser/session-storage/src/main/java/mozilla/components/browser/session/storage/serialize/BrowserStateReader.kt @@ -181,7 +181,7 @@ private fun JsonReader.tabSession(): RecoverableTab { var historyMetadataSearchTerm: String? = null var historyMetadataReferrerUrl: String? = null - var externalSourceId: Int? = null + var sourceId: Int? = null var externalSourcePackageId: String? = null var externalSourceCategory: Int? = null @@ -204,10 +204,10 @@ private fun JsonReader.tabSession(): RecoverableTab { Keys.SESSION_LAST_MEDIA_URL -> lastMediaUrl = nextString() Keys.SESSION_LAST_MEDIA_SESSION_ACTIVE -> mediaSessionActive = nextBoolean() Keys.SESSION_LAST_MEDIA_ACCESS -> lastMediaAccess = nextLong() - Keys.SESSION_EXTERNAL_SOURCE_ID -> externalSourceId = nextInt() + Keys.SESSION_SOURCE_ID -> sourceId = nextInt() Keys.SESSION_EXTERNAL_SOURCE_PACKAGE_ID -> externalSourcePackageId = nextStringOrNull() Keys.SESSION_EXTERNAL_SOURCE_PACKAGE_CATEGORY -> externalSourceCategory = nextIntOrNull() - Keys.SESSION_SOURCE_KEY -> nextString() + Keys.SESSION_DEPRECATED_SOURCE_KEY -> nextString() else -> throw IllegalArgumentException("Unknown session key: $name") } } @@ -242,6 +242,6 @@ private fun JsonReader.tabSession(): RecoverableTab { lastMediaAccess = lastMediaAccess ?: 0, mediaSessionActive = mediaSessionActive ?: false ), - source = SessionState.Source.restore(externalSourceId, externalSourcePackageId, externalSourceCategory) + source = SessionState.Source.restore(sourceId, externalSourcePackageId, externalSourceCategory) ) } diff --git a/components/browser/session-storage/src/main/java/mozilla/components/browser/session/storage/serialize/BrowserStateWriter.kt b/components/browser/session-storage/src/main/java/mozilla/components/browser/session/storage/serialize/BrowserStateWriter.kt index d42080895df..bb57132b58a 100644 --- a/components/browser/session-storage/src/main/java/mozilla/components/browser/session/storage/serialize/BrowserStateWriter.kt +++ b/components/browser/session-storage/src/main/java/mozilla/components/browser/session/storage/serialize/BrowserStateWriter.kt @@ -121,11 +121,11 @@ private fun JsonWriter.tab( value(metadata.referrerUrl) } - (tab.source as? SessionState.Source.External)?.let { source -> - name(Keys.SESSION_EXTERNAL_SOURCE_ID) - value(source.id) + name(Keys.SESSION_SOURCE_ID) + value(tab.source.id) - source.caller?.let { caller -> + (tab.source as? SessionState.Source.External)?.let { externalSource -> + externalSource.caller?.let { caller -> name(Keys.SESSION_EXTERNAL_SOURCE_PACKAGE_ID) value(caller.packageId) diff --git a/components/browser/session-storage/src/main/java/mozilla/components/browser/session/storage/serialize/Keys.kt b/components/browser/session-storage/src/main/java/mozilla/components/browser/session/storage/serialize/Keys.kt index 798415ebfc3..4fcfd37b971 100644 --- a/components/browser/session-storage/src/main/java/mozilla/components/browser/session/storage/serialize/Keys.kt +++ b/components/browser/session-storage/src/main/java/mozilla/components/browser/session/storage/serialize/Keys.kt @@ -26,13 +26,14 @@ internal object Keys { const val SESSION_LAST_MEDIA_URL = "lastMediaUrl" const val SESSION_LAST_MEDIA_ACCESS = "lastMediaAccess" const val SESSION_LAST_MEDIA_SESSION_ACTIVE = "mediaSessionActive" - const val SESSION_SOURCE_KEY = "source" + // Deprecated for SESSION_SOURCE_ID, kept around for backwards compatibility. + const val SESSION_DEPRECATED_SOURCE_KEY = "source" const val SESSION_HISTORY_METADATA_URL = "historyMetadataUrl" const val SESSION_HISTORY_METADATA_SEARCH_TERM = "historyMetadataSearchTerm" const val SESSION_HISTORY_METADATA_REFERRER_URL = "historyMetadataReferrerUrl" - const val SESSION_EXTERNAL_SOURCE_ID = "externalSourceId" + const val SESSION_SOURCE_ID = "sourceId" const val SESSION_EXTERNAL_SOURCE_PACKAGE_ID = "externalPackageId" const val SESSION_EXTERNAL_SOURCE_PACKAGE_CATEGORY = "externalPackageCategory" diff --git a/components/browser/session-storage/src/test/java/mozilla/components/browser/session/storage/serialize/BrowserStateWriterReaderTest.kt b/components/browser/session-storage/src/test/java/mozilla/components/browser/session/storage/serialize/BrowserStateWriterReaderTest.kt index a94a151c622..6c5f423b93e 100644 --- a/components/browser/session-storage/src/test/java/mozilla/components/browser/session/storage/serialize/BrowserStateWriterReaderTest.kt +++ b/components/browser/session-storage/src/test/java/mozilla/components/browser/session/storage/serialize/BrowserStateWriterReaderTest.kt @@ -97,7 +97,7 @@ class BrowserStateWriterReaderTest { } @Test - fun `Read tab with session source`() { + fun `Read tab with deprecated session source`() { // We don't persist session source of tabs unless it's an external source. // However, in older versions we did persist other types of sources so need to be tolerant // if these older cases are encountered in JSON to remain backward compatible. @@ -107,14 +107,14 @@ class BrowserStateWriterReaderTest { val file = AtomicFile( File.createTempFile(UUID.randomUUID().toString(), UUID.randomUUID().toString()) ) - writeTabWithSource(tab, file) + writeTabWithDeprecatedSource(tab, file) - // When reading a tab that didn't have an external source persisted, we just need to make sure + // When reading a tab that didn't have a source persisted, we just need to make sure // it is deserialized correctly. In this case, source defaults to `Internal.Restored`. val reader = BrowserStateReader() val restoredTab = reader.readTab(engine, file) assertNotNull(restoredTab!!) - assertEquals(SessionState.Source.Internal.Restored, restoredTab.source) + assertEquals(SessionState.Source.Internal.None, restoredTab.source) assertEquals("https://www.mozilla.org", restoredTab.url) assertEquals("Mozilla", restoredTab.title) @@ -356,11 +356,11 @@ private fun createFakeEngine(engineState: EngineSessionState): Engine { return engine } -private fun writeTabWithSource(tab: TabSessionState, file: AtomicFile) { - file.streamJSON { tabWithSource(tab) } +private fun writeTabWithDeprecatedSource(tab: TabSessionState, file: AtomicFile) { + file.streamJSON { tabWithDeprecatedSource(tab) } } -private fun JsonWriter.tabWithSource( +private fun JsonWriter.tabWithDeprecatedSource( tab: TabSessionState ) { beginObject() @@ -376,7 +376,7 @@ private fun JsonWriter.tabWithSource( name(Keys.SESSION_TITLE) value(tab.content.title) - name(Keys.SESSION_SOURCE_KEY) + name(Keys.SESSION_DEPRECATED_SOURCE_KEY) value(tab.source.toString()) endObject() diff --git a/components/browser/state/src/main/java/mozilla/components/browser/state/state/CustomTabSessionState.kt b/components/browser/state/src/main/java/mozilla/components/browser/state/state/CustomTabSessionState.kt index 79750badb96..3e1d75bd49d 100644 --- a/components/browser/state/src/main/java/mozilla/components/browser/state/state/CustomTabSessionState.kt +++ b/components/browser/state/src/main/java/mozilla/components/browser/state/state/CustomTabSessionState.kt @@ -30,7 +30,8 @@ data class CustomTabSessionState( override val extensionState: Map = emptyMap(), override val mediaSessionState: MediaSessionState? = null, override val contextId: String? = null, - override val source: SessionState.Source = SessionState.Source.Internal.CustomTab + override val source: SessionState.Source = SessionState.Source.Internal.CustomTab, + override val restored: Boolean = false ) : SessionState { override fun createCopy( diff --git a/components/browser/state/src/main/java/mozilla/components/browser/state/state/SessionState.kt b/components/browser/state/src/main/java/mozilla/components/browser/state/state/SessionState.kt index 490274ba70b..57f34822c06 100644 --- a/components/browser/state/src/main/java/mozilla/components/browser/state/state/SessionState.kt +++ b/components/browser/state/src/main/java/mozilla/components/browser/state/state/SessionState.kt @@ -21,7 +21,7 @@ import mozilla.components.support.utils.SafeIntent * @property contextId the session context ID of the session. The session context ID specifies the * contextual identity to use for the session's cookie store. * https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Work_with_contextual_identities - * @property source the [Source] of this session to describe how and why it was created. + * @property restored Indicates if this session was restored from a hydrated state. */ interface SessionState { val id: String @@ -32,6 +32,7 @@ interface SessionState { val mediaSessionState: MediaSessionState? val contextId: String? val source: Source + val restored: Boolean /** * Copy the class and override some parameters. @@ -69,9 +70,15 @@ interface SessionState { 2 -> External.ActionView(caller) 3 -> External.ActionSearch(caller) 4 -> External.CustomTab(caller) - // We only care about restoring 'external' types, so collapse other source types. - // This also silently handles abnormalities (like unknown or null sourceId). - else -> Internal.Restored + 5 -> Internal.HomeScreen + 6 -> Internal.Menu + 7 -> Internal.NewTab + 8 -> Internal.None + 9 -> Internal.TextSelection + 10 -> Internal.UserEntered + 11 -> Internal.CustomTab + // Silently handle abnormalities (like invalid or null sourceId). + else -> Internal.None } } } @@ -135,15 +142,10 @@ interface SessionState { */ object UserEntered : Internal(10) - /** - * This session was restored. - */ - object Restored : Internal(11) - /** * Created to handle a CustomTabs intent of internal origin. */ - object CustomTab : Internal(12) + object CustomTab : Internal(11) } } } @@ -167,19 +169,7 @@ enum class PackageCategory(val id: Int) { /** * Maps an int category (as it can be obtained from a package manager) to our internal representation. */ - fun fromInt(id: Int?): PackageCategory = when (id) { - 0 -> GAME - 1 -> AUDIO - 2 -> VIDEO - 3 -> IMAGE - 4 -> SOCIAL - 5 -> NEWS - 6 -> MAPS - 7 -> PRODUCTIVITY - -1 -> UNKNOWN - null -> UNKNOWN - else -> UNKNOWN - } + fun fromInt(id: Int?): PackageCategory = values().find { category -> category.id == id } ?: UNKNOWN } } diff --git a/components/browser/state/src/main/java/mozilla/components/browser/state/state/TabSessionState.kt b/components/browser/state/src/main/java/mozilla/components/browser/state/state/TabSessionState.kt index 7f384b1be4e..3c0cff3de1a 100644 --- a/components/browser/state/src/main/java/mozilla/components/browser/state/state/TabSessionState.kt +++ b/components/browser/state/src/main/java/mozilla/components/browser/state/state/TabSessionState.kt @@ -29,6 +29,7 @@ import java.util.UUID * @property createdAt Timestamp of this tab's creation. * @property lastMediaAccessState - [LastMediaAccessState] detailing the tab state when media started playing. * Requires [LastMediaAccessMiddleware] to update the value when playback starts. + * @property restored Indicates if this page was restored from a persisted state. */ data class TabSessionState( override val id: String = UUID.randomUUID().toString(), @@ -39,6 +40,7 @@ data class TabSessionState( override val mediaSessionState: MediaSessionState? = null, override val contextId: String? = null, override val source: SessionState.Source = SessionState.Source.Internal.None, + override val restored: Boolean = false, val parentId: String? = null, val lastAccess: Long = 0L, val createdAt: Long = System.currentTimeMillis(), @@ -85,6 +87,7 @@ fun createTab( createdAt: Long = System.currentTimeMillis(), lastMediaAccessState: LastMediaAccessState = LastMediaAccessState(), source: SessionState.Source = SessionState.Source.Internal.None, + restored: Boolean = false, engineSession: EngineSession? = null, engineSessionState: EngineSessionState? = null, crashed: Boolean = false, @@ -112,6 +115,7 @@ fun createTab( createdAt = createdAt, lastMediaAccessState = lastMediaAccessState, source = source, + restored = restored, engineState = EngineState( engineSession = engineSession, engineSessionState = engineSessionState, diff --git a/components/browser/state/src/main/java/mozilla/components/browser/state/state/recover/RecoverableTab.kt b/components/browser/state/src/main/java/mozilla/components/browser/state/state/recover/RecoverableTab.kt index e6f4678379b..93d8b4f5ec6 100644 --- a/components/browser/state/src/main/java/mozilla/components/browser/state/state/recover/RecoverableTab.kt +++ b/components/browser/state/src/main/java/mozilla/components/browser/state/state/recover/RecoverableTab.kt @@ -47,7 +47,7 @@ data class RecoverableTab( val lastMediaAccessState: LastMediaAccessState = LastMediaAccessState(), val private: Boolean = false, val historyMetadata: HistoryMetadataKey? = null, - val source: Source = Source.Internal.Restored + val source: Source = Source.Internal.None ) /** @@ -84,10 +84,11 @@ fun RecoverableTab.toTabSessionState() = createTab( createdAt = createdAt, lastMediaAccessState = lastMediaAccessState, historyMetadata = historyMetadata, - source = source + source = source, + restored = true ) /** - * Creates a list of [TabSessionState]s from a List of [TabSessionState]s. + * Creates a list of [TabSessionState]s from a List of [RecoverableTab]s. */ fun List.toTabSessionStates() = map { it.toTabSessionState() } diff --git a/components/support/webextensions/src/main/java/mozilla/components/support/webextensions/WebExtensionSupport.kt b/components/support/webextensions/src/main/java/mozilla/components/support/webextensions/WebExtensionSupport.kt index 4543779f0fe..730b3b898a2 100644 --- a/components/support/webextensions/src/main/java/mozilla/components/support/webextensions/WebExtensionSupport.kt +++ b/components/support/webextensions/src/main/java/mozilla/components/support/webextensions/WebExtensionSupport.kt @@ -345,7 +345,7 @@ object WebExtensionSupport { // startup and might not be ready yet. var scope: CoroutineScope? = null scope = store.flowScoped { flow -> - flow.map { state -> state.tabs.filter { it.source == SessionState.Source.Internal.Restored }.size } + flow.map { state -> state.tabs.filter { it.restored }.size } .ifChanged() .collect { size -> if (size > 0) { diff --git a/components/support/webextensions/src/test/java/mozilla/components/support/webextensions/WebExtensionSupportTest.kt b/components/support/webextensions/src/test/java/mozilla/components/support/webextensions/WebExtensionSupportTest.kt index 7e0a0f5016a..1dd1440330d 100644 --- a/components/support/webextensions/src/test/java/mozilla/components/support/webextensions/WebExtensionSupportTest.kt +++ b/components/support/webextensions/src/test/java/mozilla/components/support/webextensions/WebExtensionSupportTest.kt @@ -837,9 +837,9 @@ class WebExtensionSupportTest { val store = BrowserStore( BrowserState( tabs = listOf( - createTab(id = "1", url = "https://www.mozilla.org", source = SessionState.Source.Internal.Restored), - createTab(id = "2", url = "moz-extension://1234-5678/test", source = SessionState.Source.Internal.Restored), - createTab(id = "3", url = "moz-extension://1234-5678-9/", source = SessionState.Source.Internal.Restored) + createTab(id = "1", url = "https://www.mozilla.org", restored = true), + createTab(id = "2", url = "moz-extension://1234-5678/test", restored = true), + createTab(id = "3", url = "moz-extension://1234-5678-9/", restored = true) ) ) )