For #12062 - Launch back to browser if we previoulsy had tabs

This commit is contained in:
ekager 2020-10-02 15:39:03 -07:00
parent 4597e0d8ff
commit cbe293d3e4
9 changed files with 135 additions and 8 deletions

View File

@ -39,6 +39,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import mozilla.components.browser.search.SearchEngine
import mozilla.components.browser.session.SessionManager
import mozilla.components.browser.state.selector.getNormalOrPrivateTabs
import mozilla.components.browser.state.state.SessionState
import mozilla.components.browser.state.state.WebExtensionState
import mozilla.components.concept.engine.EngineSession
@ -126,7 +127,8 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
private var isVisuallyComplete = false
private var privateNotificationObserver: PrivateNotificationFeature<PrivateNotificationService>? = null
private var privateNotificationObserver: PrivateNotificationFeature<PrivateNotificationService>? =
null
private var isToolbarInflated = false
@ -192,14 +194,18 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
it.start()
}
if (isActivityColdStarted(intent, savedInstanceState)) {
externalSourceIntentProcessors.any {
if (isActivityColdStarted(
intent,
savedInstanceState
) && !externalSourceIntentProcessors.any {
it.process(
intent,
navHost.navController,
this.intent
)
}
) {
navigateToBrowserOnColdStart()
}
Performance.processIntentIfPerformanceTest(intent, this)
@ -240,7 +246,10 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
StartupTimeline.onActivityCreateEndHome(this) // DO NOT MOVE ANYTHING BELOW HERE.
}
protected open fun startupTelemetryOnCreateCalled(safeIntent: SafeIntent, hasSavedInstanceState: Boolean) {
protected open fun startupTelemetryOnCreateCalled(
safeIntent: SafeIntent,
hasSavedInstanceState: Boolean
) {
components.appStartupTelemetry.onHomeActivityOnCreate(
safeIntent,
hasSavedInstanceState,
@ -322,6 +331,10 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
}
final override fun onPause() {
// We should return to the browser if there were normal tabs when we left the app
settings().shouldReturnToBrowser =
components.core.store.state.getNormalOrPrivateTabs(private = false).isNotEmpty()
if (settings().lastKnownMode.isPrivate) {
window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
}
@ -763,6 +776,14 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
}
}
open fun navigateToBrowserOnColdStart() {
// Normal tabs + cold start -> Should go back to browser if we had any tabs open when we left last
// except for PBM + Cold Start there won't be any tabs since they're evicted so we never will navigate
if (settings().shouldReturnToBrowser && !browsingModeManager.mode.isPrivate) {
openToBrowser(BrowserDirection.FromGlobal, null)
}
}
override fun attachBaseContext(base: Context) {
base.components.strictMode.resetAfter(StrictMode.allowThreadDiskReads()) {
super.attachBaseContext(base)

View File

@ -32,6 +32,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -41,6 +42,7 @@ import mozilla.components.browser.session.SessionManager
import mozilla.components.browser.state.action.ContentAction
import mozilla.components.browser.state.selector.findTab
import mozilla.components.browser.state.selector.findTabOrCustomTabOrSelectedTab
import mozilla.components.browser.state.selector.getNormalOrPrivateTabs
import mozilla.components.browser.state.state.SessionState
import mozilla.components.browser.state.state.content.DownloadState
import mozilla.components.browser.state.store.BrowserStore
@ -189,6 +191,28 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
val view = inflater.inflate(R.layout.fragment_browser, container, false)
val activity = activity as HomeActivity
components = requireComponents
if (customTabSessionId == null) {
// Once tab restoration is complete, if there are no tabs to show in the browser, go home
components.core.store.flowScoped(viewLifecycleOwner) { flow ->
flow.map { state -> state.restoreComplete }
.ifChanged()
.collect { restored ->
if (restored) {
val tabs =
components.core.store.state.getNormalOrPrivateTabs(
activity.browsingModeManager.mode.isPrivate
)
if (tabs.isEmpty()) findNavController().popBackStack(
R.id.homeFragment,
false
)
}
}
}
}
activity.themeManager.applyStatusBarTheme(activity)
browserFragmentStore = StoreProvider.get(this) {
@ -197,8 +221,6 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
)
}
components = requireComponents
return view
}

View File

@ -21,6 +21,7 @@ import mozilla.components.browser.session.SessionManager
import mozilla.components.browser.session.engine.EngineMiddleware
import mozilla.components.browser.session.storage.SessionStorage
import mozilla.components.browser.session.undo.UndoMiddleware
import mozilla.components.browser.state.action.RestoreCompleteAction
import mozilla.components.browser.state.action.RecentlyClosedAction
import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.store.BrowserStore
@ -231,6 +232,8 @@ class Core(
}
}
}
store.dispatch(RestoreCompleteAction)
}
WebNotificationFeature(

View File

@ -46,6 +46,10 @@ open class ExternalAppBrowserActivity : HomeActivity() {
)
}
override fun navigateToBrowserOnColdStart() {
// No-op for external app
}
override fun getNavDirections(
from: BrowserDirection,
customTabSessionId: String?

View File

@ -182,6 +182,11 @@ class Settings(private val appContext: Context) : PreferencesHolder {
true
)
var shouldReturnToBrowser by booleanPreference(
appContext.getString(R.string.pref_key_return_to_browser),
false
)
// If any of the prefs have been modified, quit displaying the fenix moved tip
fun shouldDisplayFenixMovingTip(): Boolean =
preferences.getBoolean(

View File

@ -235,4 +235,6 @@
<string name="pref_key_show_grid_view_tabs_settings" translatable="false">pref_key_show_grid_view_tabs_settings</string>
<string name="pref_key_camera_permissions_needed" translatable="false">pref_key_camera_permissions_needed</string>
<string name="pref_key_return_to_browser" translatable="false">pref_key_return_to_browser</string>
</resources>

View File

@ -7,7 +7,9 @@ package org.mozilla.fenix
import android.content.Intent
import android.os.Bundle
import io.mockk.every
import io.mockk.mockk
import io.mockk.spyk
import io.mockk.verify
import mozilla.components.support.test.robolectric.testContext
import mozilla.components.support.utils.toSafeIntent
import org.junit.Assert.assertEquals
@ -20,9 +22,12 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.HomeActivity.Companion.PRIVATE_BROWSING_MODE
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
import org.mozilla.fenix.utils.Settings
@RunWith(FenixRobolectricTestRunner::class)
class HomeActivityTest {
@ -32,8 +37,6 @@ class HomeActivityTest {
@Before
fun setup() {
activity = spyk(HomeActivity())
every { activity.applicationContext } returns testContext
}
@Test
@ -52,6 +55,7 @@ class HomeActivityTest {
@Test
fun `getModeFromIntentOrLastKnown returns mode from settings when intent does not set`() {
every { activity.applicationContext } returns testContext
testContext.settings().lastKnownMode = BrowsingMode.Private
assertEquals(testContext.settings().lastKnownMode, activity.getModeFromIntentOrLastKnown(null))
@ -87,6 +91,38 @@ class HomeActivityTest {
assertFalse(activity.isActivityColdStarted(startingIntent, null))
}
@Test
fun `navigateToBrowserOnColdStart in normal mode navigates to browser`() {
val browsingModeManager: BrowsingModeManager = mockk()
every { browsingModeManager.mode } returns BrowsingMode.Normal
val settings: Settings = mockk()
every { settings.shouldReturnToBrowser } returns true
every { activity.components.settings.shouldReturnToBrowser } returns true
every { activity.openToBrowser(any(), any()) } returns Unit
activity.browsingModeManager = browsingModeManager
activity.navigateToBrowserOnColdStart()
verify(exactly = 1) { activity.openToBrowser(BrowserDirection.FromGlobal, null) }
}
@Test
fun `navigateToBrowserOnColdStart in private mode does not navigate to browser`() {
val browsingModeManager: BrowsingModeManager = mockk()
every { browsingModeManager.mode } returns BrowsingMode.Private
val settings: Settings = mockk()
every { settings.shouldReturnToBrowser } returns true
every { activity.components.settings.shouldReturnToBrowser } returns true
every { activity.openToBrowser(any(), any()) } returns Unit
activity.browsingModeManager = browsingModeManager
activity.navigateToBrowserOnColdStart()
verify(exactly = 0) { activity.openToBrowser(BrowserDirection.FromGlobal, null) }
}
@Test
fun `isActivityColdStarted returns false for null savedInstanceState and not launched from history`() {
val startingIntent = Intent().apply {

View File

@ -17,7 +17,11 @@ import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Test
import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.utils.Settings
class ExternalAppBrowserActivityTest {
@ -37,6 +41,23 @@ class ExternalAppBrowserActivityTest {
assertEquals(Event.OpenedApp.Source.CUSTOM_TAB, activity.getIntentSource(otherIntent))
}
@Test
fun `navigateToBrowserOnColdStart does nothing for external app browser activity`() {
val activity = spyk(ExternalAppBrowserActivity())
val browsingModeManager: BrowsingModeManager = mockk()
every { browsingModeManager.mode } returns BrowsingMode.Normal
val settings: Settings = mockk()
every { settings.shouldReturnToBrowser } returns true
every { activity.components.settings.shouldReturnToBrowser } returns true
every { activity.openToBrowser(any(), any()) } returns Unit
activity.browsingModeManager = browsingModeManager
activity.navigateToBrowserOnColdStart()
verify(exactly = 0) { activity.openToBrowser(BrowserDirection.FromGlobal, null) }
}
@Test
fun `getNavDirections finishes activity if session ID is null`() {
val activity = spyk(object : ExternalAppBrowserActivity() {

View File

@ -53,6 +53,19 @@ class SettingsTest {
assertTrue(settings.openLinksInAPrivateTab)
}
@Test
fun shouldReturnToBrowser() {
// When just created
// Then
assertFalse(settings.shouldReturnToBrowser)
// When
settings.shouldReturnToBrowser = true
// Then
assertTrue(settings.shouldReturnToBrowser)
}
@Test
fun clearDataOnQuit() {
// When just created