Revert "Bug 1861459 - Remove Home Screen usages of BrowsingModeManager"

This reverts commit 86e0f3c0ef1dd3a16194eeaff330c8517d18b49f.
fenix/123.0
Matthew Tighe 4 months ago committed by mergify[bot]
parent d080cf6e70
commit 452f7147d0

@ -1,56 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.fenix
import android.view.Window
import android.view.WindowManager
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChangedBy
import kotlinx.coroutines.withContext
import mozilla.components.lib.state.helpers.AbstractBinding
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
import org.mozilla.fenix.components.AppStore
import org.mozilla.fenix.components.appstate.AppState
import org.mozilla.fenix.theme.ThemeManager
import org.mozilla.fenix.utils.Settings
/**
* Binding to react to Private Browsing Mode changes in AppState.
*
* @param appStore AppStore to observe state changes from.
* @param themeManager Theme will be updated based on state changes.
* @param retrieveWindow Get window to update privacy flags for.
* @param settings Determine user settings for privacy features.
* @param ioDispatcher Dispatcher to launch disk reads. Exposed for test.
*/
class BrowsingModeBinding(
appStore: AppStore,
private val themeManager: ThemeManager,
private val retrieveWindow: () -> Window,
private val settings: Settings,
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO,
) : AbstractBinding<AppState>(appStore) {
override suspend fun onState(flow: Flow<AppState>) {
flow.distinctUntilChangedBy { it.mode }.collect {
themeManager.currentTheme = it.mode
setWindowPrivacy(it.mode)
}
}
private suspend fun setWindowPrivacy(mode: BrowsingMode) {
if (mode == BrowsingMode.Private) {
val allowScreenshots = withContext(ioDispatcher) {
settings.allowScreenshotsInPrivateMode
}
if (!allowScreenshots) {
retrieveWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE)
}
} else {
retrieveWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
}
}
}

@ -1,49 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.fenix
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import mozilla.components.lib.state.Middleware
import mozilla.components.lib.state.MiddlewareContext
import org.mozilla.fenix.components.appstate.AppAction
import org.mozilla.fenix.components.appstate.AppState
import org.mozilla.fenix.utils.Settings
/**
* Middleware for controlling side-effects relating to Private Browsing Mode.
*
* @param settings Used to update disk-cache related PBM data.
* @param scope Scope used for disk writes and reads. Exposed for test overrides.
*/
class BrowsingModePersistenceMiddleware(
private val settings: Settings,
private val scope: CoroutineScope = CoroutineScope(Dispatchers.IO),
) : Middleware<AppState, AppAction> {
override fun invoke(
context: MiddlewareContext<AppState, AppAction>,
next: (AppAction) -> Unit,
action: AppAction,
) {
val initialMode = context.state.mode
next(action)
val updatedMode = context.state.mode
if (initialMode != context.state.mode) {
scope.launch {
settings.lastKnownMode = updatedMode
}
}
when (action) {
is AppAction.Init -> {
scope.launch {
val mode = settings.lastKnownMode
context.store.dispatch(AppAction.BrowsingModeLoaded(mode))
}
}
else -> Unit
}
}
}

@ -24,6 +24,7 @@ import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.ViewConfiguration
import android.view.WindowManager.LayoutParams.FLAG_SECURE
import androidx.annotation.CallSuper
import androidx.annotation.IdRes
import androidx.annotation.RequiresApi
@ -89,6 +90,8 @@ import org.mozilla.fenix.GleanMetrics.StartOnHome
import org.mozilla.fenix.addons.ExtensionsProcessDisabledBackgroundController
import org.mozilla.fenix.addons.ExtensionsProcessDisabledForegroundController
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager
import org.mozilla.fenix.browser.browsingmode.DefaultBrowsingModeManager
import org.mozilla.fenix.components.appstate.AppAction
import org.mozilla.fenix.components.appstate.bindings.BrowserStoreBinding
import org.mozilla.fenix.components.metrics.BreadcrumbsRecorder
@ -160,9 +163,8 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
protected val homeActivityInitTimeStampNanoSeconds = SystemClock.elapsedRealtimeNanos()
private lateinit var binding: ActivityHomeBinding
val themeManager by lazy {
createThemeManager()
}
lateinit var themeManager: ThemeManager
lateinit var browsingModeManager: BrowsingModeManager
private var isVisuallyComplete = false
@ -240,11 +242,12 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
maybeShowSplashScreen()
setModeFromIntent(intent)
// Theme setup should always be called before super.onCreate
themeManager.setActivityTheme(this)
themeManager.applyStatusBarTheme(this)
super.onCreate(savedInstanceState)
// There is disk read violations on some devices such as samsung and pixel for android 9/10
components.strictMode.resetAfter(StrictMode.allowThreadDiskReads()) {
// Theme setup should always be called before super.onCreate
setupThemeAndBrowsingMode(getModeFromIntentOrLastKnown(intent))
super.onCreate(savedInstanceState)
}
// Checks if Activity is currently in PiP mode if launched from external intents, then exits it
checkAndExitPiP()
@ -377,12 +380,6 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
serviceWorkerSupport,
webExtensionPromptFeature,
BrowserStoreBinding(components.core.store, components.appStore),
BrowsingModeBinding(
components.appStore,
themeManager,
{ window },
components.settings,
),
)
if (shouldAddToRecentsScreen(intent)) {
@ -713,7 +710,7 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
) + externalSourceIntentProcessors
val intentHandled =
intentProcessors.any { it.process(intent, navHost.navController, this.intent) }
setModeFromIntent(intent)
browsingModeManager.mode = getModeFromIntentOrLastKnown(intent)
if (intentHandled) {
supportFragmentManager
@ -884,18 +881,14 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
* private mode directly before the content view is created. Returns the mode set by the intent
* otherwise falls back to the last known mode.
*/
internal fun setModeFromIntent(intent: Intent?) {
internal fun getModeFromIntentOrLastKnown(intent: Intent?): BrowsingMode {
intent?.toSafeIntent()?.let {
if (it.hasExtra(PRIVATE_BROWSING_MODE)) {
val startPrivateMode = it.getBooleanExtra(PRIVATE_BROWSING_MODE, false)
// Since the mode is initially set from settings during AppAction.Init, this action
// will overwrite the state once the action is processed in the queue if called from
// onCreate.
if (startPrivateMode) {
components.appStore.dispatch(AppAction.IntentAction.EnterPrivateBrowsing)
}
return BrowsingMode.fromBoolean(isPrivate = startPrivateMode)
}
}
return settings().lastKnownMode
}
/**
@ -911,6 +904,14 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
return false
}
private fun setupThemeAndBrowsingMode(mode: BrowsingMode) {
settings().lastKnownMode = mode
browsingModeManager = createBrowsingModeManager(mode)
themeManager = createThemeManager()
themeManager.setActivityTheme(this)
themeManager.applyStatusBarTheme(this)
}
// Stop active media when activity is destroyed.
private fun stopMediaSession() {
if (isFinishing) {
@ -1034,7 +1035,7 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
additionalHeaders: Map<String, String>? = null,
) {
val startTime = components.core.engine.profiler?.getProfilerTime()
val mode = components.appStore.state.mode
val mode = browsingModeManager.mode
val private = when (mode) {
BrowsingMode.Private -> true
@ -1115,7 +1116,7 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
// 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 && !components.appStore.state.mode.isPrivate) {
if (settings().shouldReturnToBrowser && !browsingModeManager.mode.isPrivate) {
// Navigate to home first (without rendering it) to add it to the back stack.
openToBrowser(BrowserDirection.FromGlobal, null)
}
@ -1150,8 +1151,25 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
return super.getSystemService(name)
}
protected open fun createBrowsingModeManager(initialMode: BrowsingMode): BrowsingModeManager {
return DefaultBrowsingModeManager(initialMode, components.settings) { newMode ->
updateSecureWindowFlags(newMode)
themeManager.currentTheme = newMode
}.also {
updateSecureWindowFlags(initialMode)
}
}
private fun updateSecureWindowFlags(mode: BrowsingMode = browsingModeManager.mode) {
if (mode == BrowsingMode.Private && !settings().allowScreenshotsInPrivateMode) {
window.addFlags(FLAG_SECURE)
} else {
window.clearFlags(FLAG_SECURE)
}
}
protected open fun createThemeManager(): ThemeManager {
return DefaultThemeManager(components.appStore.state.mode, this)
return DefaultThemeManager(browsingModeManager.mode, this)
}
private fun openPopup(webExtensionState: WebExtensionState) {

@ -17,11 +17,6 @@ enum class BrowsingMode {
*/
val isPrivate get() = this == Private
val inverted get() = when (this) {
Private -> Normal
Normal -> Private
}
companion object {
/**

@ -19,8 +19,4 @@ import org.mozilla.fenix.components.appstate.AppStoreReducer
class AppStore(
initialState: AppState = AppState(),
middlewares: List<Middleware<AppState, AppAction>> = emptyList(),
) : Store<AppState, AppAction>(initialState, AppStoreReducer::reduce, middlewares) {
init {
dispatch(AppAction.Init)
}
}
) : Store<AppState, AppAction>(initialState, AppStoreReducer::reduce, middlewares)

@ -19,7 +19,6 @@ import mozilla.components.feature.autofill.AutofillConfiguration
import mozilla.components.lib.publicsuffixlist.PublicSuffixList
import mozilla.components.support.base.android.NotificationsDelegate
import mozilla.components.support.base.worker.Frequency
import org.mozilla.fenix.BrowsingModePersistenceMiddleware
import org.mozilla.fenix.BuildConfig
import org.mozilla.fenix.Config
import org.mozilla.fenix.FeatureFlags
@ -224,9 +223,6 @@ class Components(private val context: Context) {
messagingStorage = analytics.messagingStorage,
),
MetricsMiddleware(metrics = analytics.metrics),
BrowsingModePersistenceMiddleware(
settings = settings,
),
),
)
}

@ -32,13 +32,6 @@ import org.mozilla.fenix.wallpapers.Wallpaper
* [Action] implementation related to [AppStore].
*/
sealed class AppAction : Action {
/**
* [AppAction] dispatched to indicate that the store is initialized and
* ready to use. This action is dispatched automatically before any other
* action is processed. Its main purpose is to trigger initialization logic
* in middlewares. The action itself should have no effect on the [AppState].
*/
object Init : AppAction()
/**
* NOTE: This action is not yet functional and will require https://bugzilla.mozilla.org/show_bug.cgi?id=1845409
@ -48,12 +41,6 @@ sealed class AppAction : Action {
* @property mode Which [BrowsingMode] the tab should be opened in.
*/
data class OpenTabInBrowser(val mode: BrowsingMode) : AppAction()
/**
* The browsing [mode] has been loaded from a persistence layer.
*/
data class BrowsingModeLoaded(val mode: BrowsingMode) : AppAction()
data class UpdateInactiveExpanded(val expanded: Boolean) : AppAction()
/**

@ -27,9 +27,7 @@ import org.mozilla.fenix.messaging.state.MessagingReducer
internal object AppStoreReducer {
@Suppress("LongMethod")
fun reduce(state: AppState, action: AppAction): AppState = when (action) {
is AppAction.Init -> state
is AppAction.OpenTabInBrowser -> state.copy(mode = action.mode)
is AppAction.BrowsingModeLoaded -> state.copy(mode = action.mode)
is AppAction.UpdateInactiveExpanded ->
state.copy(inactiveTabsExpanded = action.expanded)
is AppAction.UpdateFirstFrameDrawn -> {

@ -157,6 +157,8 @@ class HomeFragment : Fragment() {
)
}
private val browsingModeManager get() = (activity as HomeActivity).browsingModeManager
private val collectionStorageObserver = object : TabCollectionStorage.Observer {
@SuppressLint("NotifyDataSetChanged")
override fun onCollectionRenamed(tabCollection: TabCollection, title: String) {
@ -248,6 +250,8 @@ class HomeFragment : Fragment() {
val currentWallpaperName = requireContext().settings().currentWallpaperName
applyWallpaper(wallpaperName = currentWallpaperName, orientationChange = false)
components.appStore.dispatch(AppAction.ModeChange(browsingModeManager.mode))
lifecycleScope.launch(IO) {
if (requireContext().settings().showPocketRecommendationsFeature) {
val categories = components.core.pocketStoriesService.getStories()
@ -504,8 +508,16 @@ class HomeFragment : Fragment() {
* doesn't get run right away which means that we won't draw on the first layout pass.
*/
private fun updateSessionControlView() {
binding.root.consumeFrom(requireContext().components.appStore, viewLifecycleOwner) {
sessionControlView?.update(it, shouldReportMetrics = it.mode != BrowsingMode.Private)
if (browsingModeManager.mode == BrowsingMode.Private) {
binding.root.consumeFrom(requireContext().components.appStore, viewLifecycleOwner) {
sessionControlView?.update(it)
}
} else {
sessionControlView?.update(requireContext().components.appStore.state)
binding.root.consumeFrom(requireContext().components.appStore, viewLifecycleOwner) {
sessionControlView?.update(it, shouldReportMetrics = true)
}
}
}
@ -533,7 +545,7 @@ class HomeFragment : Fragment() {
super.onViewCreated(view, savedInstanceState)
HomeScreen.homeScreenDisplayed.record(NoExtras())
HomeScreen.homeScreenViewCount.add()
if (!requireComponents.appStore.state.mode.isPrivate) {
if (!browsingModeManager.mode.isPrivate) {
HomeScreen.standardHomepageViewCount.add()
}
@ -562,10 +574,7 @@ class HomeFragment : Fragment() {
toolbarView?.build()
PrivateBrowsingButtonView(
button = binding.privateBrowsingButton,
mode = requireComponents.appStore.state.mode,
) { newMode ->
PrivateBrowsingButtonView(binding.privateBrowsingButton, browsingModeManager) { newMode ->
sessionControlInteractor.onPrivateModeButtonClicked(newMode)
Homepage.privateModeIconTapped.record(mozilla.telemetry.glean.private.NoExtras())
}
@ -770,7 +779,7 @@ class HomeFragment : Fragment() {
)
}
if (requireComponents.appStore.state.mode.isPrivate &&
if (browsingModeManager.mode.isPrivate &&
// We will be showing the search dialog and don't want to show the CFR while the dialog shows
!bundleArgs.getBoolean(FOCUS_ON_ADDRESS_BAR) &&
context.settings().shouldShowPrivateModeCfr
@ -809,7 +818,7 @@ class HomeFragment : Fragment() {
override fun onResume() {
super.onResume()
if (requireComponents.appStore.state.mode == BrowsingMode.Private) {
if (browsingModeManager.mode == BrowsingMode.Private) {
activity?.window?.setBackgroundDrawableResource(R.drawable.private_home_background_gradient)
}
@ -825,7 +834,7 @@ class HomeFragment : Fragment() {
override fun onPause() {
super.onPause()
if (requireComponents.appStore.state.mode == BrowsingMode.Private) {
if (browsingModeManager.mode == BrowsingMode.Private) {
activity?.window?.setBackgroundDrawable(
ColorDrawable(
ContextCompat.getColor(
@ -979,7 +988,7 @@ class HomeFragment : Fragment() {
}
private fun showCollectionsPlaceholder(browserState: BrowserState) {
val tabCount = if (requireComponents.appStore.state.mode.isPrivate) {
val tabCount = if (browsingModeManager.mode.isPrivate) {
browserState.privateTabs.size
} else {
browserState.normalTabs.size

@ -8,22 +8,19 @@ import android.view.View
import androidx.annotation.StringRes
import org.mozilla.fenix.R
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager
/**
* Sets up the private browsing toggle button on the [HomeFragment].
*
* @param button The button to bind content descriptions and click listeners to.
* @param mode The current [BrowsingMode].
* @param onClick Click handler for the button.
*/
class PrivateBrowsingButtonView(
button: View,
private val mode: BrowsingMode,
private val browsingModeManager: BrowsingModeManager,
private val onClick: (BrowsingMode) -> Unit,
) : View.OnClickListener {
init {
button.contentDescription = button.context.getString(getContentDescription(mode))
button.contentDescription = button.context.getString(getContentDescription(browsingModeManager.mode))
button.setOnClickListener(this)
}
@ -31,7 +28,10 @@ class PrivateBrowsingButtonView(
* Calls [onClick] with the new [BrowsingMode] and updates the [browsingModeManager].
*/
override fun onClick(v: View) {
onClick(mode.inverted)
val invertedMode = BrowsingMode.fromBoolean(!browsingModeManager.mode.isPrivate)
onClick(invertedMode)
browsingModeManager.mode = invertedMode
}
companion object {

@ -1,101 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.fenix
import android.view.Window
import android.view.WindowManager
import kotlinx.coroutines.test.runTest
import mozilla.components.support.test.ext.joinBlocking
import mozilla.components.support.test.libstate.ext.waitUntilIdle
import mozilla.components.support.test.mock
import mozilla.components.support.test.rule.MainCoroutineRule
import mozilla.components.support.test.rule.runTestOnMain
import mozilla.components.support.test.whenever
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mockito.Mockito.anyInt
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
import org.mozilla.fenix.components.AppStore
import org.mozilla.fenix.components.appstate.AppAction
import org.mozilla.fenix.theme.ThemeManager
import org.mozilla.fenix.utils.Settings
class BrowsingModeBindingTest {
@get:Rule
val coroutinesTestRule = MainCoroutineRule()
private lateinit var themeManager: ThemeManager
private lateinit var window: Window
private lateinit var settings: Settings
private val retrieveWindow = { window }
private lateinit var appStore: AppStore
private lateinit var binding: BrowsingModeBinding
@Before
fun setup() {
themeManager = mock()
window = mock()
settings = mock()
whenever(window.clearFlags(anyInt())).then { }
appStore = AppStore()
// wait for Init action
appStore.waitUntilIdle()
binding = BrowsingModeBinding(
appStore,
themeManager,
retrieveWindow,
settings,
coroutinesTestRule.testDispatcher,
)
binding.start()
}
@After
fun teardown() {
binding.stop()
}
@Test
fun `WHEN mode updated THEN theme manager is also updated`() = runTest {
appStore.dispatch(AppAction.ModeChange(BrowsingMode.Private)).joinBlocking()
verify(themeManager).currentTheme = BrowsingMode.Private
}
@Test
fun `GIVEN screenshots not allowed in private mode WHEN mode changes to private THEN secure flag added to window`() = runTestOnMain {
whenever(window.addFlags(anyInt())).then { }
whenever(settings.allowScreenshotsInPrivateMode).thenReturn(false)
appStore.dispatch(AppAction.ModeChange(BrowsingMode.Private)).joinBlocking()
verify(window).addFlags(WindowManager.LayoutParams.FLAG_SECURE)
}
@Test
fun `GIVEN screenshots allowed in private mode when mode changes to private THEN secure flag not added to window`() = runTest {
whenever(settings.allowScreenshotsInPrivateMode).thenReturn(true)
appStore.dispatch(AppAction.ModeChange(BrowsingMode.Private)).joinBlocking()
verify(window, never()).addFlags(WindowManager.LayoutParams.FLAG_SECURE)
}
@Test
fun `WHEN mode changed to normal THEN secure flag cleared from window`() {
appStore.dispatch(AppAction.ModeChange(BrowsingMode.Private)).joinBlocking()
appStore.dispatch(AppAction.ModeChange(BrowsingMode.Normal)).joinBlocking()
verify(window, times(2)).clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
}
}

@ -1,65 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.fenix
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
import mozilla.components.support.test.ext.joinBlocking
import mozilla.components.support.test.libstate.ext.waitUntilIdle
import mozilla.components.support.test.mock
import mozilla.components.support.test.rule.MainCoroutineRule
import mozilla.components.support.test.whenever
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mockito.Mockito.verify
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
import org.mozilla.fenix.components.AppStore
import org.mozilla.fenix.components.appstate.AppAction
import org.mozilla.fenix.utils.Settings
class BrowsingModePersistenceMiddlewareTest {
@get:Rule
val coroutinesTestRule = MainCoroutineRule()
private lateinit var settings: Settings
@Before
fun setup() {
settings = mock()
}
@Test
fun `WHEN store initialization intercepted THEN mode read from settings and update dispatched`() = runTest {
val cachedMode = BrowsingMode.Private
whenever(settings.lastKnownMode).thenReturn(cachedMode)
val middleware = BrowsingModePersistenceMiddleware(settings, this)
val store = AppStore(middlewares = listOf(middleware))
// Wait for Init action
store.waitUntilIdle()
// Wait for middleware launched coroutine
this.advanceUntilIdle()
// Wait for ModeChange action
store.waitUntilIdle()
assertEquals(cachedMode, store.state.mode)
}
@Test
fun `WHEN mode change THEN mode updated on disk`() = runTest {
val cachedMode = BrowsingMode.Normal
whenever(settings.lastKnownMode).thenReturn(cachedMode)
val updatedMode = BrowsingMode.Private
val middleware = BrowsingModePersistenceMiddleware(settings, this)
val store = AppStore(middlewares = listOf(middleware))
store.dispatch(AppAction.ModeChange(updatedMode)).joinBlocking()
this.advanceUntilIdle()
verify(settings).lastKnownMode = updatedMode
}
}

@ -10,11 +10,11 @@ import io.mockk.every
import io.mockk.mockk
import io.mockk.spyk
import io.mockk.verify
import mozilla.components.support.test.libstate.ext.waitUntilIdle
import mozilla.components.support.test.robolectric.testContext
import mozilla.components.support.utils.toSafeIntent
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotEquals
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Before
@ -22,8 +22,7 @@ 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.components.AppStore
import org.mozilla.fenix.components.appstate.AppState
import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.getIntentSource
import org.mozilla.fenix.ext.settings
@ -34,13 +33,11 @@ import org.mozilla.fenix.utils.Settings
@RunWith(FenixRobolectricTestRunner::class)
class HomeActivityTest {
private var appStore = AppStore()
private lateinit var activity: HomeActivity
@Before
fun setup() {
activity = spyk(HomeActivity())
every { activity.components.appStore } returns appStore
}
@Test
@ -58,29 +55,24 @@ class HomeActivityTest {
}
@Test
fun `GIVEN intent not set WHEN setModeFromIntent THEN mode not updated`() {
fun `getModeFromIntentOrLastKnown returns mode from settings when intent does not set`() {
every { testContext.settings() } returns Settings(testContext)
every { activity.applicationContext } returns testContext
testContext.settings().lastKnownMode = BrowsingMode.Normal
activity.setModeFromIntent(null)
testContext.settings().lastKnownMode = BrowsingMode.Private
assertEquals(BrowsingMode.Normal, appStore.state.mode)
assertEquals(testContext.settings().lastKnownMode, activity.getModeFromIntentOrLastKnown(null))
}
@Test
fun `GIVEN intent set WHEN setModeFromIntent THEN mode updated`() {
fun `getModeFromIntentOrLastKnown returns mode from intent when set`() {
every { testContext.settings() } returns Settings(testContext)
every { testContext.components.appStore } returns appStore
every { activity.applicationContext } returns testContext
testContext.settings().lastKnownMode = BrowsingMode.Normal
val intent = Intent()
intent.putExtra(PRIVATE_BROWSING_MODE, true)
activity.setModeFromIntent(intent)
appStore.waitUntilIdle()
assertEquals(BrowsingMode.Private, appStore.state.mode)
assertNotEquals(testContext.settings().lastKnownMode, activity.getModeFromIntentOrLastKnown(intent))
assertEquals(BrowsingMode.Private, activity.getModeFromIntentOrLastKnown(intent))
}
@Test
@ -104,11 +96,15 @@ class HomeActivityTest {
@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 } returns settings
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) }
@ -116,13 +112,15 @@ class HomeActivityTest {
@Test
fun `navigateToBrowserOnColdStart in private mode does not navigate to browser`() {
val privateAppStore = AppStore(AppState(mode = BrowsingMode.Private))
val browsingModeManager: BrowsingModeManager = mockk()
every { browsingModeManager.mode } returns BrowsingMode.Private
val settings: Settings = mockk()
every { settings.shouldReturnToBrowser } returns true
every { activity.components.appStore } returns privateAppStore
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) }

@ -13,6 +13,7 @@ import org.junit.Before
import org.junit.Test
import org.mozilla.fenix.R
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager
class PrivateBrowsingButtonViewTest {
@ -20,23 +21,27 @@ class PrivateBrowsingButtonViewTest {
private val disable = "Disable private browsing"
private lateinit var button: View
private lateinit var browsingModeManager: BrowsingModeManager
@Before
fun setup() {
button = mockk(relaxed = true)
browsingModeManager = mockk(relaxed = true)
every { button.context.getString(R.string.content_description_private_browsing_button) } returns enable
every { button.context.getString(R.string.content_description_disable_private_browsing_button) } returns disable
every { browsingModeManager.mode } returns BrowsingMode.Normal
}
@Test
fun `constructor sets contentDescription and click listener`() {
val view = PrivateBrowsingButtonView(button, BrowsingMode.Normal) {}
val view = PrivateBrowsingButtonView(button, browsingModeManager) {}
verify { button.context.getString(R.string.content_description_private_browsing_button) }
verify { button.contentDescription = enable }
verify { button.setOnClickListener(view) }
val privateView = PrivateBrowsingButtonView(button, BrowsingMode.Private) {}
every { browsingModeManager.mode } returns BrowsingMode.Private
val privateView = PrivateBrowsingButtonView(button, browsingModeManager) {}
verify { button.context.getString(R.string.content_description_disable_private_browsing_button) }
verify { button.contentDescription = disable }
verify { button.setOnClickListener(privateView) }
@ -44,21 +49,25 @@ class PrivateBrowsingButtonViewTest {
@Test
fun `click listener calls onClick with inverted mode from normal mode`() {
var mode = BrowsingMode.Normal
val view = PrivateBrowsingButtonView(button, mode) { mode = it }
every { browsingModeManager.mode } returns BrowsingMode.Normal
var mode: BrowsingMode? = null
val view = PrivateBrowsingButtonView(button, browsingModeManager) { mode = it }
view.onClick(button)
assertEquals(BrowsingMode.Private, mode)
verify { browsingModeManager.mode = BrowsingMode.Private }
}
@Test
fun `click listener calls onClick with inverted mode from private mode`() {
var mode = BrowsingMode.Private
val view = PrivateBrowsingButtonView(button, mode) { mode = it }
every { browsingModeManager.mode } returns BrowsingMode.Private
var mode: BrowsingMode? = null
val view = PrivateBrowsingButtonView(button, browsingModeManager) { mode = it }
view.onClick(button)
assertEquals(BrowsingMode.Normal, mode)
verify { browsingModeManager.mode = BrowsingMode.Normal }
}
}

@ -26,6 +26,7 @@ import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.BuildConfig.DEEP_LINK_SCHEME
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.NavGraphDirections
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
import org.mozilla.fenix.components.AppStore
import org.mozilla.fenix.components.accounts.FenixFxAEntryPoint
import org.mozilla.fenix.components.appstate.AppAction

@ -13,6 +13,7 @@ import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
class DownloadControllerTest {
private val downloadItem = DownloadItem(

@ -795,6 +795,7 @@ class AwesomeBarViewTest {
val settings: Settings = mockk(relaxed = true)
val url = Uri.parse("https://www.test.com")
every { activity.settings() } returns settings
every { activity.browsingModeManager.mode } returns BrowsingMode.Normal
val state = getSearchProviderState(
showSessionSuggestionsForCurrentEngine = false,
searchEngineSource = SearchEngineSource.Shortcut(
@ -835,10 +836,10 @@ class AwesomeBarViewTest {
@Test
fun `GIVEN private browsing mode and needing to show tabs suggestions WHEN configuring providers THEN don't add the tabs provider`() {
val privateAppStore = AppStore(AppState(mode = BrowsingMode.Private))
val appStore = AppStore(AppState(mode = BrowsingMode.Private))
val settings: Settings = mockk(relaxed = true)
every { activity.settings() } returns settings
every { any<Activity>().components.appStore } returns privateAppStore
every { any<Activity>().components.appStore } returns appStore
val state = getSearchProviderState(
searchEngineSource = SearchEngineSource.Shortcut(mockk(relaxed = true)),
)
@ -897,6 +898,7 @@ class AwesomeBarViewTest {
val settings: Settings = mockk(relaxed = true)
val url = Uri.parse("https://www.test.com")
every { activity.settings() } returns settings
every { activity.browsingModeManager.mode } returns BrowsingMode.Normal
val state = getSearchProviderState(
showSyncedTabsSuggestionsForCurrentEngine = false,
searchEngineSource = SearchEngineSource.Shortcut(
@ -941,6 +943,7 @@ class AwesomeBarViewTest {
val settings: Settings = mockk(relaxed = true)
val url = Uri.parse("https://www.test.com")
every { activity.settings() } returns settings
every { activity.browsingModeManager.mode } returns BrowsingMode.Normal
val state = getSearchProviderState(
showBookmarksSuggestionsForCurrentEngine = false,
searchEngineSource = SearchEngineSource.Shortcut(
@ -1034,6 +1037,7 @@ class AwesomeBarViewTest {
val settings: Settings = mockk(relaxed = true)
val url = Uri.parse("https://www.test.com")
every { activity.settings() } returns settings
every { activity.browsingModeManager.mode } returns BrowsingMode.Normal
val state = getSearchProviderState(
searchEngineSource = SearchEngineSource.Default(
mockk(relaxed = true) {

Loading…
Cancel
Save