diff --git a/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt b/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt index 817a5ba2b8..c90ca97f46 100644 --- a/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt @@ -70,7 +70,6 @@ import mozilla.components.feature.session.FullScreenFeature import mozilla.components.feature.session.PictureInPictureFeature import mozilla.components.feature.session.SessionFeature import mozilla.components.feature.session.SwipeRefreshFeature -import mozilla.components.feature.session.behavior.EngineViewBottomBehavior import mozilla.components.feature.sitepermissions.SitePermissions import mozilla.components.feature.sitepermissions.SitePermissionsFeature import mozilla.components.lib.state.ext.consumeFlow @@ -103,9 +102,7 @@ import org.mozilla.fenix.components.toolbar.BrowserToolbarView import org.mozilla.fenix.components.toolbar.BrowserToolbarViewInteractor import org.mozilla.fenix.components.toolbar.DefaultBrowserToolbarController import org.mozilla.fenix.components.toolbar.DefaultBrowserToolbarMenuController -import org.mozilla.fenix.components.toolbar.SwipeRefreshScrollingViewBehavior import org.mozilla.fenix.components.toolbar.ToolbarIntegration -import org.mozilla.fenix.components.toolbar.ToolbarPosition import org.mozilla.fenix.downloads.DownloadService import org.mozilla.fenix.downloads.DynamicDownloadDialog import org.mozilla.fenix.ext.accessibilityManager @@ -128,9 +125,11 @@ import org.mozilla.fenix.utils.allowUndo import org.mozilla.fenix.wifi.SitePermissionsWifiIntegration import java.lang.ref.WeakReference import mozilla.components.feature.media.fullscreen.MediaFullscreenOrientationFeature +import mozilla.components.feature.session.behavior.EngineViewBrowserToolbarBehavior import mozilla.components.feature.webauthn.WebAuthnFeature import mozilla.components.support.base.feature.ActivityResultHandler import org.mozilla.fenix.FeatureFlags.newMediaSessionApi +import mozilla.components.feature.session.behavior.ToolbarPosition as MozacToolbarPosition /** * Base fragment extended by [BrowserFragment]. @@ -838,34 +837,42 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Activit !inFullScreen } - private fun initializeEngineView(toolbarHeight: Int) { + @VisibleForTesting + internal fun initializeEngineView(toolbarHeight: Int) { val context = requireContext() - if (context.settings().isDynamicToolbarEnabled) { - engineView.setDynamicToolbarMaxHeight(toolbarHeight) + // If there is an a11y service enabled and the user hasn't explicitly set bottom toolbar + val isTopToolbarForced = + !context.settings().shouldUseBottomToolbar && + context.settings().shouldUseFixedTopToolbar + + if (!isTopToolbarForced && context.settings().isDynamicToolbarEnabled) { + getEngineView().setDynamicToolbarMaxHeight(toolbarHeight) - val behavior = when (context.settings().toolbarPosition) { - // Set engineView dynamic vertical clipping depending on the toolbar position. - ToolbarPosition.BOTTOM -> EngineViewBottomBehavior(context, null) - // Set scroll flags depending on if if the browser or the website is doing the scroll. - ToolbarPosition.TOP -> SwipeRefreshScrollingViewBehavior( + val toolbarPosition = if (context.settings().shouldUseBottomToolbar) { + MozacToolbarPosition.BOTTOM + } else { + MozacToolbarPosition.TOP + } + (getSwipeRefreshLayout().layoutParams as CoordinatorLayout.LayoutParams).behavior = + EngineViewBrowserToolbarBehavior( context, null, - engineView, - browserToolbarView + getSwipeRefreshLayout(), + toolbarHeight, + toolbarPosition ) - } - - (swipeRefresh.layoutParams as CoordinatorLayout.LayoutParams).behavior = behavior } else { // Ensure webpage's bottom elements are aligned to the very bottom of the engineView. - engineView.setDynamicToolbarMaxHeight(0) + getEngineView().setDynamicToolbarMaxHeight(0) - // Effectively place the engineView on top of the toolbar if that is not dynamic. + // Effectively place the engineView on top/below of the toolbar if that is not dynamic. + val swipeRefreshParams = + getSwipeRefreshLayout().layoutParams as CoordinatorLayout.LayoutParams if (context.settings().shouldUseBottomToolbar) { - val browserEngine = swipeRefresh.layoutParams as CoordinatorLayout.LayoutParams - browserEngine.bottomMargin = - requireContext().resources.getDimensionPixelSize(R.dimen.browser_toolbar_height) + swipeRefreshParams.bottomMargin = toolbarHeight + } else { + swipeRefreshParams.topMargin = toolbarHeight } } } @@ -1251,6 +1258,8 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Activit browserToolbarView.view.isVisible = false val browserEngine = swipeRefresh.layoutParams as CoordinatorLayout.LayoutParams browserEngine.bottomMargin = 0 + browserEngine.topMargin = 0 + swipeRefresh.translationY = 0f engineView.setDynamicToolbarMaxHeight(0) browserToolbarView.expand() @@ -1330,7 +1339,7 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Activit override fun onAccessibilityStateChanged(enabled: Boolean) { if (_browserToolbarView != null) { - browserToolbarView.setScrollFlags(enabled) + browserToolbarView.setToolbarBehavior(enabled) } } @@ -1352,4 +1361,16 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Activit } } } + + /** + * Convenience method for replacing EngineView (id/engineView) in unit tests. + */ + @VisibleForTesting + internal fun getEngineView() = engineView + + /** + * Convenience method for replacing SwipeRefreshLayout (id/swipeRefresh) in unit tests. + */ + @VisibleForTesting + internal fun getSwipeRefreshLayout() = swipeRefresh } diff --git a/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarView.kt b/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarView.kt index aff4b03d2c..af57953a5f 100644 --- a/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarView.kt +++ b/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarView.kt @@ -9,25 +9,18 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.annotation.LayoutRes +import androidx.annotation.VisibleForTesting import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.content.ContextCompat -import androidx.core.view.updateLayoutParams import androidx.lifecycle.LifecycleOwner -import com.google.android.material.appbar.AppBarLayout -import com.google.android.material.appbar.AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS -import com.google.android.material.appbar.AppBarLayout.LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED -import com.google.android.material.appbar.AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL -import com.google.android.material.appbar.AppBarLayout.LayoutParams.SCROLL_FLAG_SNAP import kotlinx.android.extensions.LayoutContainer -import kotlinx.android.synthetic.main.component_browser_top_toolbar.* -import kotlinx.android.synthetic.main.component_browser_top_toolbar.view.* import kotlinx.coroutines.ExperimentalCoroutinesApi import mozilla.components.browser.domains.autocomplete.ShippedDomainsProvider import mozilla.components.browser.session.Session import mozilla.components.browser.state.selector.selectedTab import mozilla.components.browser.state.state.ExternalAppType import mozilla.components.browser.toolbar.BrowserToolbar -import mozilla.components.browser.toolbar.behavior.BrowserToolbarBottomBehavior +import mozilla.components.browser.toolbar.behavior.BrowserToolbarBehavior import mozilla.components.browser.toolbar.display.DisplayToolbar import mozilla.components.support.utils.URLStringUtils import mozilla.components.ui.tabcounter.TabCounterMenu @@ -40,6 +33,7 @@ import org.mozilla.fenix.ext.settings import org.mozilla.fenix.theme.ThemeManager import org.mozilla.fenix.utils.ToolbarPopupWindow import java.lang.ref.WeakReference +import mozilla.components.browser.toolbar.behavior.ToolbarPosition as MozacToolbarPosition interface BrowserToolbarViewInteractor { fun onBrowserToolbarPaste(text: String) @@ -76,12 +70,14 @@ class BrowserToolbarView( private val layout = LayoutInflater.from(container.context) .inflate(toolbarLayout, container, true) - val view: BrowserToolbar = layout + @VisibleForTesting + internal var view: BrowserToolbar = layout .findViewById(R.id.toolbar) val toolbarIntegration: ToolbarIntegration - private val isPwaTabOrTwaTab: Boolean + @VisibleForTesting + internal val isPwaTabOrTwaTab: Boolean get() = customTabSession?.customTabConfig?.externalAppType == ExternalAppType.PROGRESSIVE_WEB_APP || customTabSession?.customTabConfig?.externalAppType == ExternalAppType.TRUSTED_WEB_ACTIVITY @@ -101,17 +97,8 @@ class BrowserToolbarView( with(container.context) { val isPinningSupported = components.useCases.webAppUseCases.isPinningSupported() - if (toolbarPosition == ToolbarPosition.TOP) { - val offsetChangedListener = - AppBarLayout.OnOffsetChangedListener { _: AppBarLayout?, verticalOffset: Int -> - interactor.onScrolled(verticalOffset) - } - - app_bar.addOnOffsetChangedListener(offsetChangedListener) - } - view.apply { - setScrollFlags() + setToolbarBehavior() elevation = resources.getDimension(R.dimen.browser_fragment_toolbar_elevation) @@ -222,16 +209,9 @@ class BrowserToolbarView( if (isPwaTabOrTwaTab) { return } - when (settings.toolbarPosition) { - ToolbarPosition.BOTTOM -> { - (view.layoutParams as? CoordinatorLayout.LayoutParams)?.apply { - // behavior can be null if the "Scroll to hide toolbar" setting is toggled off. - (behavior as? BrowserToolbarBottomBehavior)?.forceExpand(view) - } - } - ToolbarPosition.TOP -> { - layout.app_bar?.setExpanded(true) - } + + (view.layoutParams as? CoordinatorLayout.LayoutParams)?.apply { + (behavior as? BrowserToolbarBehavior)?.forceExpand(view) } } @@ -240,41 +220,54 @@ class BrowserToolbarView( } /** - * Dynamically sets scroll flags for the toolbar when the user does not have a screen reader enabled - * Note that the toolbar will have the flags set and be able to be hidden - * only if the user didn't disabled this behavior in app's settings. + * Sets whether the toolbar will have a dynamic behavior (to be scrolled) or not. + * + * This will intrinsically check and disable the dynamic behavior if + * - this is disabled in app settings + * - toolbar is placed at the bottom and tab shows a PWA or TWA + * + * Also if the user has not explicitly set a toolbar position and has a screen reader enabled + * the toolbar will be placed at the top and in a fixed position. + * + * @param shouldDisableScroll force disable of the dynamic behavior irrespective of the intrinsic checks. */ - fun setScrollFlags(shouldDisableScroll: Boolean = false) { + fun setToolbarBehavior(shouldDisableScroll: Boolean = false) { when (settings.toolbarPosition) { ToolbarPosition.BOTTOM -> { if (settings.isDynamicToolbarEnabled && !isPwaTabOrTwaTab) { - (view.layoutParams as? CoordinatorLayout.LayoutParams)?.apply { - behavior = BrowserToolbarBottomBehavior(view.context, null) - } + setDynamicToolbarBehavior(MozacToolbarPosition.BOTTOM) } else { - expand() + expandToolbarAndMakeItFixed() } } ToolbarPosition.TOP -> { - view.updateLayoutParams { - scrollFlags = - if (settings.shouldUseFixedTopToolbar || - !settings.isDynamicToolbarEnabled || - shouldDisableScroll) { - // Force expand the toolbar so the user is not stuck with a hidden toolbar - expand() - 0 - } else { - SCROLL_FLAG_SCROLL or - SCROLL_FLAG_ENTER_ALWAYS or - SCROLL_FLAG_SNAP or - SCROLL_FLAG_EXIT_UNTIL_COLLAPSED - } + if (settings.shouldUseFixedTopToolbar || + !settings.isDynamicToolbarEnabled || + shouldDisableScroll + ) { + expandToolbarAndMakeItFixed() + } else { + setDynamicToolbarBehavior(MozacToolbarPosition.TOP) } } } } + @VisibleForTesting + internal fun expandToolbarAndMakeItFixed() { + expand() + (view.layoutParams as? CoordinatorLayout.LayoutParams)?.apply { + behavior = null + } + } + + @VisibleForTesting + internal fun setDynamicToolbarBehavior(toolbarPosition: MozacToolbarPosition) { + (view.layoutParams as? CoordinatorLayout.LayoutParams)?.apply { + behavior = BrowserToolbarBehavior(view.context, null, toolbarPosition) + } + } + @Suppress("ComplexCondition") private fun ToolbarMenu.Item.performHapticIfNeeded(view: View) { if (this is ToolbarMenu.Item.Reload && this.bypassCache || diff --git a/app/src/main/java/org/mozilla/fenix/components/toolbar/SwipeRefreshScrollingViewBehavior.kt b/app/src/main/java/org/mozilla/fenix/components/toolbar/SwipeRefreshScrollingViewBehavior.kt deleted file mode 100644 index b69bc0f943..0000000000 --- a/app/src/main/java/org/mozilla/fenix/components/toolbar/SwipeRefreshScrollingViewBehavior.kt +++ /dev/null @@ -1,50 +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.components.toolbar - -import android.content.Context -import android.util.AttributeSet -import android.view.View -import androidx.coordinatorlayout.widget.CoordinatorLayout -import com.google.android.material.appbar.AppBarLayout -import kotlinx.coroutines.ExperimentalCoroutinesApi -import mozilla.components.concept.engine.EngineView -import mozilla.components.concept.engine.EngineView.InputResult.INPUT_RESULT_UNHANDLED -import org.mozilla.fenix.ext.settings - -/** - * ScrollingViewBehavior that will setScrollFlags on BrowserToolbar based on EngineView touch handling - */ -@ExperimentalCoroutinesApi -class SwipeRefreshScrollingViewBehavior( - context: Context, - attrs: AttributeSet?, - private val engineView: EngineView, - private val browserToolbarView: BrowserToolbarView -) : AppBarLayout.ScrollingViewBehavior(context, attrs) { - override fun onStartNestedScroll( - coordinatorLayout: CoordinatorLayout, - child: View, - directTargetChild: View, - target: View, - axes: Int, - type: Int - ): Boolean { - - if (!browserToolbarView.view.context.settings().shouldUseBottomToolbar) { - val shouldDisable = engineView.getInputResult() == INPUT_RESULT_UNHANDLED - browserToolbarView.setScrollFlags(shouldDisable) - } - - return super.onStartNestedScroll( - coordinatorLayout, - child, - directTargetChild, - target, - axes, - type - ) - } -} diff --git a/app/src/main/res/layout/component_browser_top_toolbar.xml b/app/src/main/res/layout/component_browser_top_toolbar.xml index 479bc9dd91..77f460296b 100644 --- a/app/src/main/res/layout/component_browser_top_toolbar.xml +++ b/app/src/main/res/layout/component_browser_top_toolbar.xml @@ -2,12 +2,9 @@ - + - - diff --git a/app/src/main/res/layout/fragment_browser.xml b/app/src/main/res/layout/fragment_browser.xml index 63150e569b..32d2bd4c4e 100644 --- a/app/src/main/res/layout/fragment_browser.xml +++ b/app/src/main/res/layout/fragment_browser.xml @@ -25,8 +25,7 @@ + android:layout_height="match_parent"> (relaxed = true) + } + + @Test + fun `initializeEngineView should setDynamicToolbarMaxHeight to 0 if top toolbar is forced for a11y`() { + every { testContext.settings().shouldUseBottomToolbar } returns false + every { testContext.settings().shouldUseFixedTopToolbar } returns true + + fragment.initializeEngineView(13) + + verify { engineView.setDynamicToolbarMaxHeight(0) } + } + + @Test + fun `initializeEngineView should setDynamicToolbarMaxHeight to toolbar height if dynamic toolbar is enabled`() { + every { testContext.settings().shouldUseFixedTopToolbar } returns false + every { testContext.settings().isDynamicToolbarEnabled } returns true + + fragment.initializeEngineView(13) + + verify { engineView.setDynamicToolbarMaxHeight(13) } + } + + @Test + fun `initializeEngineView should setDynamicToolbarMaxHeight to 0 if dynamic toolbar is disabled`() { + every { testContext.settings().shouldUseFixedTopToolbar } returns false + every { testContext.settings().isDynamicToolbarEnabled } returns false + + fragment.initializeEngineView(13) + + verify { engineView.setDynamicToolbarMaxHeight(0) } + } + + @Test + fun `initializeEngineView should set EngineViewBrowserToolbarBehavior when dynamic toolbar is enabled`() { + every { testContext.settings().shouldUseFixedTopToolbar } returns false + every { testContext.settings().isDynamicToolbarEnabled } returns true + val params: CoordinatorLayout.LayoutParams = mockk(relaxed = true) + every { params.behavior } returns mockk(relaxed = true) + every { swipeRefreshLayout.layoutParams } returns params + val behavior = slot() + + fragment.initializeEngineView(13) + + // EngineViewBrowserToolbarBehavior constructor parameters are not properties, we cannot check them. + // Ensure just that the right behavior is set. + verify { params.behavior = capture(behavior) } + } + + @Test + fun `initializeEngineView should set toolbar height as EngineView parent's bottom margin when using bottom toolbar`() { + every { testContext.settings().isDynamicToolbarEnabled } returns false + every { testContext.settings().shouldUseBottomToolbar } returns true + + fragment.initializeEngineView(13) + + verify { (swipeRefreshLayout.layoutParams as CoordinatorLayout.LayoutParams).bottomMargin = 13 } + } + + @Test + fun `initializeEngineView should set toolbar height as EngineView parent's bottom margin if top toolbar is forced for a11y`() { + every { testContext.settings().shouldUseBottomToolbar } returns false + every { testContext.settings().shouldUseFixedTopToolbar } returns true + + fragment.initializeEngineView(13) + + verify { (swipeRefreshLayout.layoutParams as CoordinatorLayout.LayoutParams).bottomMargin = 13 } + } +} + +@ExperimentalCoroutinesApi +private class TestBaseBrowserFragment : BaseBrowserFragment() { + override fun getContextMenuCandidates( + context: Context, + view: View + ): List { + // no-op + return emptyList() + } + + override fun navToQuickSettingsSheet(tab: SessionState, sitePermissions: SitePermissions?) { + // no-op + } + + override fun navToTrackingProtectionPanel(tab: SessionState) { + // no-op + } +} diff --git a/app/src/test/java/org/mozilla/fenix/components/toolbar/BrowserToolbarViewTest.kt b/app/src/test/java/org/mozilla/fenix/components/toolbar/BrowserToolbarViewTest.kt new file mode 100644 index 0000000000..f75b1d448f --- /dev/null +++ b/app/src/test/java/org/mozilla/fenix/components/toolbar/BrowserToolbarViewTest.kt @@ -0,0 +1,196 @@ +/* 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.components.toolbar + +import androidx.coordinatorlayout.widget.CoordinatorLayout + +import io.mockk.every +import io.mockk.mockk +import io.mockk.spyk +import io.mockk.verify +import kotlinx.coroutines.ExperimentalCoroutinesApi +import mozilla.components.support.test.robolectric.testContext +import org.junit.Test +import org.junit.runner.RunWith +import mozilla.components.browser.toolbar.BrowserToolbar +import mozilla.components.browser.toolbar.behavior.BrowserToolbarBehavior +import org.junit.Assert.assertNotNull +import org.junit.Assert.assertNull +import org.junit.Before +import org.mozilla.fenix.ext.settings +import org.mozilla.fenix.helpers.FenixRobolectricTestRunner +import mozilla.components.browser.toolbar.behavior.ToolbarPosition as MozacToolbarPosition + +@ExperimentalCoroutinesApi +@RunWith(FenixRobolectricTestRunner::class) +class BrowserToolbarViewTest { + private lateinit var toolbarView: BrowserToolbarView + private lateinit var toolbar: BrowserToolbar + private lateinit var behavior: BrowserToolbarBehavior + + @Before + fun `setup`() { + toolbar = BrowserToolbar(testContext) + toolbar.layoutParams = CoordinatorLayout.LayoutParams(100, 100) + behavior = spyk(BrowserToolbarBehavior(testContext, null, MozacToolbarPosition.BOTTOM)) + (toolbar.layoutParams as CoordinatorLayout.LayoutParams).behavior = behavior + + toolbarView = BrowserToolbarView( + container = CoordinatorLayout(testContext), + toolbarPosition = ToolbarPosition.BOTTOM, + interactor = mockk(), + customTabSession = mockk(relaxed = true), + lifecycleOwner = mockk() + ) + + toolbarView.view = toolbar + } + + @Test + fun `setToolbarBehavior(false) should setDynamicToolbarBehavior if bottom toolbar is dynamic and the tab is not for a PWA or TWA`() { + val toolbarViewSpy = spyk(toolbarView) + every { testContext.settings().toolbarPosition } returns ToolbarPosition.BOTTOM + every { testContext.settings().isDynamicToolbarEnabled } returns true + every { toolbarViewSpy.isPwaTabOrTwaTab } returns false + + toolbarViewSpy.setToolbarBehavior(false) + + verify { toolbarViewSpy.setDynamicToolbarBehavior(MozacToolbarPosition.BOTTOM) } + } + + @Test + fun `setToolbarBehavior(false) should expandToolbarAndMakeItFixed if bottom toolbar is not set as dynamic`() { + val toolbarViewSpy = spyk(toolbarView) + every { testContext.settings().toolbarPosition } returns ToolbarPosition.BOTTOM + every { testContext.settings().isDynamicToolbarEnabled } returns false + + toolbarViewSpy.setToolbarBehavior(false) + + verify { toolbarViewSpy.expandToolbarAndMakeItFixed() } + } + + @Test + fun `setToolbarBehavior(false) should expandToolbarAndMakeItFixed if bottom toolbar is dynamic but the tab is for a PWA or TWA`() { + val toolbarViewSpy = spyk(toolbarView) + every { testContext.settings().toolbarPosition } returns ToolbarPosition.BOTTOM + every { testContext.settings().isDynamicToolbarEnabled } returns true + every { toolbarViewSpy.isPwaTabOrTwaTab } returns true + + toolbarViewSpy.setToolbarBehavior(false) + + verify { toolbarViewSpy.expandToolbarAndMakeItFixed() } + } + + @Test + fun `setToolbarBehavior(true) should setDynamicToolbarBehavior if bottom toolbar is dynamic and the tab is not for a PWA or TWA`() { + val toolbarViewSpy = spyk(toolbarView) + every { testContext.settings().toolbarPosition } returns ToolbarPosition.BOTTOM + every { testContext.settings().isDynamicToolbarEnabled } returns true + every { toolbarViewSpy.isPwaTabOrTwaTab } returns false + + toolbarViewSpy.setToolbarBehavior(false) + + verify { toolbarViewSpy.setDynamicToolbarBehavior(MozacToolbarPosition.BOTTOM) } + } + + @Test + fun `setToolbarBehavior(true) should expandToolbarAndMakeItFixed if bottom toolbar is not set as dynamic`() { + val toolbarViewSpy = spyk(toolbarView) + every { testContext.settings().toolbarPosition } returns ToolbarPosition.BOTTOM + every { testContext.settings().isDynamicToolbarEnabled } returns false + + toolbarViewSpy.setToolbarBehavior(false) + + verify { toolbarViewSpy.expandToolbarAndMakeItFixed() } + } + + @Test + fun `setToolbarBehavior(true) should expandToolbarAndMakeItFixed if bottom toolbar is dynamic but the tab is for a PWA or TWA`() { + val toolbarViewSpy = spyk(toolbarView) + every { testContext.settings().toolbarPosition } returns ToolbarPosition.BOTTOM + every { testContext.settings().isDynamicToolbarEnabled } returns true + every { toolbarViewSpy.isPwaTabOrTwaTab } returns true + + toolbarViewSpy.setToolbarBehavior(false) + + verify { toolbarViewSpy.expandToolbarAndMakeItFixed() } + } + + @Test + fun `setToolbarBehavior(true) should expandToolbarAndMakeItFixed for top toolbar if shouldUseFixedTopToolbar`() { + val toolbarViewSpy = spyk(toolbarView) + every { testContext.settings().toolbarPosition } returns ToolbarPosition.TOP + every { testContext.settings().shouldUseFixedTopToolbar } returns true + + toolbarViewSpy.setToolbarBehavior(true) + + verify { toolbarViewSpy.expandToolbarAndMakeItFixed() } + } + + @Test + fun `setToolbarBehavior(true) should expandToolbarAndMakeItFixed for top toolbar if it is not dynamic`() { + val toolbarViewSpy = spyk(toolbarView) + every { testContext.settings().toolbarPosition } returns ToolbarPosition.TOP + every { testContext.settings().isDynamicToolbarEnabled } returns false + + toolbarViewSpy.setToolbarBehavior(true) + + verify { toolbarViewSpy.expandToolbarAndMakeItFixed() } + } + + @Test + fun `setToolbarBehavior(true) should expandToolbarAndMakeItFixed for top toolbar if shouldDisableScroll`() { + val toolbarViewSpy = spyk(toolbarView) + every { testContext.settings().toolbarPosition } returns ToolbarPosition.TOP + + toolbarViewSpy.setToolbarBehavior(true) + + verify { toolbarViewSpy.expandToolbarAndMakeItFixed() } + } + + @Test + fun `setToolbarBehavior(false) should setDynamicToolbarBehavior for top toolbar`() { + val toolbarViewSpy = spyk(toolbarView) + every { testContext.settings().toolbarPosition } returns ToolbarPosition.TOP + every { testContext.settings().shouldUseFixedTopToolbar } returns true + every { testContext.settings().isDynamicToolbarEnabled } returns true + + toolbarViewSpy.setToolbarBehavior(true) + + verify { toolbarViewSpy.expandToolbarAndMakeItFixed() } + } + + @Test + fun `expandToolbarAndMakeItFixed should expand the toolbar and and disable the dynamic behavior`() { + val toolbarViewSpy = spyk(toolbarView) + + assertNotNull((toolbar.layoutParams as CoordinatorLayout.LayoutParams).behavior) + + toolbarViewSpy.expandToolbarAndMakeItFixed() + + verify { toolbarViewSpy.expand() } + assertNull((toolbar.layoutParams as CoordinatorLayout.LayoutParams).behavior) + } + + @Test + fun `setDynamicToolbarBehavior should set a BrowserToolbarBehavior for the bottom toolbar`() { + val toolbarViewSpy = spyk(toolbarView) + (toolbar.layoutParams as CoordinatorLayout.LayoutParams).behavior = null + + toolbarViewSpy.setDynamicToolbarBehavior(MozacToolbarPosition.BOTTOM) + + assertNotNull((toolbar.layoutParams as CoordinatorLayout.LayoutParams).behavior) + } + + @Test + fun `setDynamicToolbarBehavior should set a BrowserToolbarBehavior for the top toolbar`() { + val toolbarViewSpy = spyk(toolbarView) + (toolbar.layoutParams as CoordinatorLayout.LayoutParams).behavior = null + + toolbarViewSpy.setDynamicToolbarBehavior(MozacToolbarPosition.TOP) + + assertNotNull((toolbar.layoutParams as CoordinatorLayout.LayoutParams).behavior) + } +}