diff --git a/app/src/main/java/org/mozilla/fenix/HomeActivity.kt b/app/src/main/java/org/mozilla/fenix/HomeActivity.kt index be42e5de5..81e4d5569 100644 --- a/app/src/main/java/org/mozilla/fenix/HomeActivity.kt +++ b/app/src/main/java/org/mozilla/fenix/HomeActivity.kt @@ -200,50 +200,39 @@ open class HomeActivity : AppCompatActivity(), ShareFragment.TabsSharedCallback load(searchTermOrURL, newTab, engine, forceSearch) } - @Suppress("ComplexMethod") fun openToBrowser(from: BrowserDirection, customTabSessionId: String? = null) { if (sessionObserver == null) sessionObserver = subscribeToSessions() if (navHost.navController.alreadyOnDestination(R.id.browserFragment)) return @IdRes val fragmentId = if (from.fragmentId != 0) from.fragmentId else null - val directions = when (from) { - BrowserDirection.FromGlobal -> { - NavGraphDirections.actionGlobalBrowser(customTabSessionId) - } - BrowserDirection.FromHome -> { - HomeFragmentDirections.actionHomeFragmentToBrowserFragment(customTabSessionId) - } - BrowserDirection.FromSearch -> { - SearchFragmentDirections.actionSearchFragmentToBrowserFragment( - customTabSessionId - ) - } - BrowserDirection.FromSettings -> { - SettingsFragmentDirections.actionSettingsFragmentToBrowserFragment( - customTabSessionId - ) - } - BrowserDirection.FromBookmarks -> { - BookmarkFragmentDirections.actionBookmarkFragmentToBrowserFragment( - customTabSessionId - ) - } - BrowserDirection.FromHistory -> { - HistoryFragmentDirections.actionHistoryFragmentToBrowserFragment( - customTabSessionId - ) - } - BrowserDirection.FromExceptions -> { - ExceptionsFragmentDirections.actionExceptionsFragmentToBrowserFragment( - customTabSessionId - ) - } - } + val directions = getNavDirections(from, customTabSessionId) navHost.navController.nav(fragmentId, directions) } + protected open fun getNavDirections( + from: BrowserDirection, + customTabSessionId: String? + ) = when (from) { + BrowserDirection.FromGlobal -> + NavGraphDirections.actionGlobalBrowser(customTabSessionId) + BrowserDirection.FromHome -> + HomeFragmentDirections.actionHomeFragmentToBrowserFragment(customTabSessionId) + BrowserDirection.FromSearch -> + SearchFragmentDirections.actionSearchFragmentToBrowserFragment(customTabSessionId) + BrowserDirection.FromSettings -> + SettingsFragmentDirections.actionSettingsFragmentToBrowserFragment(customTabSessionId) + BrowserDirection.FromBookmarks -> + BookmarkFragmentDirections.actionBookmarkFragmentToBrowserFragment(customTabSessionId) + BrowserDirection.FromHistory -> + HistoryFragmentDirections.actionHistoryFragmentToBrowserFragment(customTabSessionId) + BrowserDirection.FromExceptions -> + ExceptionsFragmentDirections.actionExceptionsFragmentToBrowserFragment( + customTabSessionId + ) + } + private fun load( searchTermOrURL: String, newTab: Boolean, 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 99338e606..366791e03 100644 --- a/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt @@ -57,18 +57,17 @@ import org.mozilla.fenix.collections.CreateCollectionViewModel import org.mozilla.fenix.components.FenixSnackbar import org.mozilla.fenix.components.FindInPageIntegration import org.mozilla.fenix.components.StoreProvider -import org.mozilla.fenix.components.toolbar.BrowserInteractor import org.mozilla.fenix.components.toolbar.BrowserState import org.mozilla.fenix.components.toolbar.BrowserStore import org.mozilla.fenix.components.toolbar.BrowserToolbarController 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.QuickActionSheetState import org.mozilla.fenix.components.toolbar.ToolbarIntegration import org.mozilla.fenix.downloads.DownloadService import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.enterToImmersiveMode -import org.mozilla.fenix.ext.nav import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.quickactionsheet.QuickActionSheetBehavior import org.mozilla.fenix.settings.SupportUtils @@ -82,7 +81,7 @@ import org.mozilla.fenix.utils.Settings @Suppress("TooManyFunctions", "LargeClass") abstract class BaseBrowserFragment : Fragment(), BackHandler, SessionManager.Observer { protected lateinit var browserStore: BrowserStore - protected lateinit var browserInteractor: BrowserInteractor + protected lateinit var browserInteractor: BrowserToolbarViewInteractor protected lateinit var browserToolbarView: BrowserToolbarView private val sessionFeature = ViewBoundFeatureWrapper() @@ -139,8 +138,7 @@ abstract class BaseBrowserFragment : Fragment(), BackHandler, SessionManager.Obs return view } - @CallSuper - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + final override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) browserInitialized = initializeUI(view) != null } @@ -476,7 +474,9 @@ abstract class BaseBrowserFragment : Fragment(), BackHandler, SessionManager.Obs protected abstract fun createBrowserToolbarViewInteractor( browserToolbarController: BrowserToolbarController, session: Session? - ): BrowserInteractor + ): BrowserToolbarViewInteractor + + protected abstract fun navToQuickSettingsSheet(session: Session, sitePermissions: SitePermissions?) /** * Returns the top and bottom margins. @@ -516,16 +516,7 @@ abstract class BaseBrowserFragment : Fragment(), BackHandler, SessionManager.Obs } view?.let { - val directions = - BrowserFragmentDirections.actionBrowserFragmentToQuickSettingsSheetDialogFragment( - sessionId = session.id, - url = session.url, - isSecured = session.securityInfo.secure, - isTrackingProtectionOn = session.trackerBlockingEnabled, - sitePermissions = sitePermissions, - gravity = getAppropriateLayoutGravity() - ) - nav(R.id.browserFragment, directions) + navToQuickSettingsSheet(session, sitePermissions) } } } diff --git a/app/src/main/java/org/mozilla/fenix/browser/BrowserFragment.kt b/app/src/main/java/org/mozilla/fenix/browser/BrowserFragment.kt index a203f1f8a..79eb039ec 100644 --- a/app/src/main/java/org/mozilla/fenix/browser/BrowserFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/browser/BrowserFragment.kt @@ -17,7 +17,6 @@ import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import androidx.transition.TransitionInflater import com.google.android.material.snackbar.Snackbar -import kotlinx.android.synthetic.main.component_search.* import kotlinx.android.synthetic.main.fragment_browser.view.* import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.Main @@ -29,6 +28,7 @@ import mozilla.appservices.places.BookmarkRoot import mozilla.components.browser.session.Session import mozilla.components.feature.readerview.ReaderViewFeature import mozilla.components.feature.session.ThumbnailsFeature +import mozilla.components.feature.sitepermissions.SitePermissions import mozilla.components.lib.state.ext.consumeFrom import mozilla.components.support.base.feature.BackHandler import mozilla.components.support.base.feature.ViewBoundFeatureWrapper @@ -40,8 +40,8 @@ import org.mozilla.fenix.components.TabCollectionStorage import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.toolbar.BrowserInteractor import org.mozilla.fenix.components.toolbar.BrowserToolbarController +import org.mozilla.fenix.components.toolbar.BrowserToolbarViewInteractor import org.mozilla.fenix.components.toolbar.QuickActionSheetAction -import org.mozilla.fenix.customtabs.CustomTabsIntegration import org.mozilla.fenix.ext.nav import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.home.sessioncontrol.SessionControlChange @@ -52,7 +52,7 @@ import org.mozilla.fenix.quickactionsheet.QuickActionSheetSessionObserver import org.mozilla.fenix.quickactionsheet.QuickActionSheetView /** - * Fragment used for browsing the web within the main app and external apps. + * Fragment used for browsing the web within the main app. */ @ObsoleteCoroutinesApi @ExperimentalCoroutinesApi @@ -63,7 +63,6 @@ class BrowserFragment : BaseBrowserFragment(), BackHandler { private val readerViewFeature = ViewBoundFeatureWrapper() private val thumbnailsFeature = ViewBoundFeatureWrapper() - private val customTabsIntegration = ViewBoundFeatureWrapper() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -93,25 +92,6 @@ class BrowserFragment : BaseBrowserFragment(), BackHandler { return super.initializeUI(view)?.also { - quickActionSheetView = - QuickActionSheetView(view.nestedScrollQuickAction, browserInteractor) - - customTabSessionId?.let { customTabSessionId -> - customTabsIntegration.set( - feature = CustomTabsIntegration( - requireContext(), - requireComponents.core.sessionManager, - toolbar, - customTabSessionId, - activity, - view.nestedScrollQuickAction, - view.swipeRefresh, - onItemTapped = { browserInteractor.onBrowserToolbarMenuItemTapped(it) } - ), - owner = this, - view = view) - } - thumbnailsFeature.set( feature = ThumbnailsFeature( requireContext(), @@ -181,46 +161,51 @@ class BrowserFragment : BaseBrowserFragment(), BackHandler { return readerViewFeature.onBackPressed() || super.onBackPressed() } - override fun removeSessionIfNeeded(): Boolean { - if (customTabsIntegration.onBackPressed()) return true - - getSessionById()?.let { session -> - if (session.source == Session.Source.ACTION_VIEW) requireComponents.core.sessionManager.remove( - session - ) - } - return false - } - override fun createBrowserToolbarViewInteractor( browserToolbarController: BrowserToolbarController, session: Session? - ) = BrowserInteractor( - context = context!!, - store = browserStore, - browserToolbarController = browserToolbarController, - quickActionSheetController = DefaultQuickActionSheetController( + ): BrowserToolbarViewInteractor { + val interactor = BrowserInteractor( context = context!!, - navController = findNavController(), - currentSession = getSessionById() - ?: requireComponents.core.sessionManager.selectedSessionOrThrow, - appLinksUseCases = requireComponents.useCases.appLinksUseCases, - bookmarkTapped = { - lifecycleScope.launch { bookmarkTapped(it) } - } - ), - readerModeController = DefaultReaderModeController(readerViewFeature), - customTabSession = customTabSessionId?.let { requireComponents.core.sessionManager.findSessionById(it) } - ) + store = browserStore, + browserToolbarController = browserToolbarController, + quickActionSheetController = DefaultQuickActionSheetController( + context = context!!, + navController = findNavController(), + currentSession = getSessionById() + ?: requireComponents.core.sessionManager.selectedSessionOrThrow, + appLinksUseCases = requireComponents.useCases.appLinksUseCases, + bookmarkTapped = { + lifecycleScope.launch { bookmarkTapped(it) } + } + ), + readerModeController = DefaultReaderModeController(readerViewFeature), + currentSession = session + ) + + quickActionSheetView = QuickActionSheetView(view!!.nestedScrollQuickAction, interactor) + + return interactor + } + + override fun navToQuickSettingsSheet(session: Session, sitePermissions: SitePermissions?) { + val directions = BrowserFragmentDirections.actionBrowserFragmentToQuickSettingsSheetDialogFragment( + sessionId = session.id, + url = session.url, + isSecured = session.securityInfo.secure, + isTrackingProtectionOn = session.trackerBlockingEnabled, + sitePermissions = sitePermissions, + gravity = getAppropriateLayoutGravity() + ) + nav(R.id.browserFragment, directions) + } override fun getEngineMargins(): Pair { val toolbarAndQASSize = resources.getDimensionPixelSize(R.dimen.toolbar_and_qab_height) - val toolbarSize = resources.getDimensionPixelSize(R.dimen.browser_toolbar_height) - return if (customTabSessionId != null) Pair(toolbarSize, 0) else Pair(0, toolbarAndQASSize) + return 0 to toolbarAndQASSize } - override fun getAppropriateLayoutGravity() = - if (customTabSessionId != null) Gravity.TOP else Gravity.BOTTOM + override fun getAppropriateLayoutGravity() = Gravity.BOTTOM private fun themeReaderViewControlsForPrivateMode(view: View) = with(view) { listOf( diff --git a/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserInteractor.kt b/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserInteractor.kt index f41b5a078..fe4b758ad 100644 --- a/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserInteractor.kt +++ b/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserInteractor.kt @@ -13,14 +13,9 @@ import org.mozilla.fenix.ext.metrics import org.mozilla.fenix.quickactionsheet.QuickActionSheetController import org.mozilla.fenix.quickactionsheet.QuickActionSheetViewInteractor -class BrowserInteractor( - private val context: Context, - private val store: BrowserStore, - private val browserToolbarController: BrowserToolbarController, - private val quickActionSheetController: QuickActionSheetController, - private val readerModeController: ReaderModeController, - private val customTabSession: Session? -) : BrowserToolbarViewInteractor, QuickActionSheetViewInteractor { +open class BrowserToolbarInteractor( + private val browserToolbarController: BrowserToolbarController +) : BrowserToolbarViewInteractor { override fun onBrowserToolbarClicked() { browserToolbarController.handleToolbarClick() @@ -29,6 +24,16 @@ class BrowserInteractor( override fun onBrowserToolbarMenuItemTapped(item: ToolbarMenu.Item) { browserToolbarController.handleToolbarItemInteraction(item) } +} + +class BrowserInteractor( + private val context: Context, + private val store: BrowserStore, + browserToolbarController: BrowserToolbarController, + private val quickActionSheetController: QuickActionSheetController, + private val readerModeController: ReaderModeController, + private val currentSession: Session? +) : BrowserToolbarInteractor(browserToolbarController), QuickActionSheetViewInteractor { override fun onQuickActionSheetOpened() { context.metrics.track(Event.QuickActionSheetOpened) @@ -52,7 +57,7 @@ class BrowserInteractor( override fun onQuickActionSheetReadPressed() { val enabled = - customTabSession?.readerMode ?: context.components.core.sessionManager.selectedSession?.readerMode ?: false + currentSession?.readerMode ?: context.components.core.sessionManager.selectedSession?.readerMode ?: false if (enabled) { context.metrics.track(Event.QuickActionSheetClosed) diff --git a/app/src/main/java/org/mozilla/fenix/customtabs/CustomTabActivity.kt b/app/src/main/java/org/mozilla/fenix/customtabs/CustomTabActivity.kt index af50522ee..05ff3ea9a 100644 --- a/app/src/main/java/org/mozilla/fenix/customtabs/CustomTabActivity.kt +++ b/app/src/main/java/org/mozilla/fenix/customtabs/CustomTabActivity.kt @@ -7,10 +7,13 @@ package org.mozilla.fenix.customtabs import androidx.navigation.NavDestination import mozilla.components.browser.session.intent.getSessionId import mozilla.components.support.utils.SafeIntent -import org.mozilla.fenix.browser.browsingmode.CustomTabBrowsingModeManager -import org.mozilla.fenix.theme.CustomTabThemeManager +import org.mozilla.fenix.BrowserDirection import org.mozilla.fenix.HomeActivity +import org.mozilla.fenix.NavGraphDirections +import org.mozilla.fenix.browser.browsingmode.CustomTabBrowsingModeManager import org.mozilla.fenix.components.metrics.Event +import org.mozilla.fenix.theme.CustomTabThemeManager +import java.security.InvalidParameterException open class CustomTabActivity : HomeActivity() { final override fun getSentryBreadcrumbMessage(destination: NavDestination): String { @@ -22,6 +25,17 @@ open class CustomTabActivity : HomeActivity() { final override fun getIntentSessionId(intent: SafeIntent) = intent.getSessionId() + override fun getNavDirections( + from: BrowserDirection, + customTabSessionId: String? + ) = when (from) { + BrowserDirection.FromGlobal -> + NavGraphDirections.actionGlobalExternalAppBrowser(customTabSessionId) + else -> throw InvalidParameterException( + "Tried to navigate to ExternalAppBrowserFragment from $from" + ) + } + final override fun createBrowsingModeManager() = CustomTabBrowsingModeManager() diff --git a/app/src/main/java/org/mozilla/fenix/customtabs/ExternalAppBrowserFragment.kt b/app/src/main/java/org/mozilla/fenix/customtabs/ExternalAppBrowserFragment.kt new file mode 100644 index 000000000..b20c42139 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/customtabs/ExternalAppBrowserFragment.kt @@ -0,0 +1,92 @@ +/* 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.customtabs + +import android.view.Gravity +import android.view.View +import kotlinx.android.synthetic.main.component_search.* +import kotlinx.android.synthetic.main.fragment_browser.view.* +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.ObsoleteCoroutinesApi +import mozilla.components.browser.session.Session +import mozilla.components.feature.sitepermissions.SitePermissions +import mozilla.components.lib.state.ext.consumeFrom +import mozilla.components.support.base.feature.BackHandler +import mozilla.components.support.base.feature.ViewBoundFeatureWrapper +import org.mozilla.fenix.R +import org.mozilla.fenix.browser.BaseBrowserFragment +import org.mozilla.fenix.components.toolbar.BrowserToolbarController +import org.mozilla.fenix.components.toolbar.BrowserToolbarInteractor +import org.mozilla.fenix.ext.nav +import org.mozilla.fenix.ext.requireComponents + +/** + * Fragment used for browsing the web within external apps. + */ +@ObsoleteCoroutinesApi +@ExperimentalCoroutinesApi +class ExternalAppBrowserFragment : BaseBrowserFragment(), BackHandler { + + private val customTabsIntegration = ViewBoundFeatureWrapper() + + override fun initializeUI(view: View): Session? { + return super.initializeUI(view)?.also { + + customTabSessionId?.let { customTabSessionId -> + customTabsIntegration.set( + feature = CustomTabsIntegration( + requireContext(), + requireComponents.core.sessionManager, + toolbar, + customTabSessionId, + activity, + view.nestedScrollQuickAction, + view.swipeRefresh, + onItemTapped = { browserInteractor.onBrowserToolbarMenuItemTapped(it) } + ), + owner = this, + view = view) + } + + consumeFrom(browserStore) { + browserToolbarView.update(it) + } + } + } + + override fun removeSessionIfNeeded(): Boolean { + return customTabsIntegration.onBackPressed() || super.removeSessionIfNeeded() + } + + override fun createBrowserToolbarViewInteractor( + browserToolbarController: BrowserToolbarController, + session: Session? + ) = BrowserToolbarInteractor(browserToolbarController) + + override fun navToQuickSettingsSheet(session: Session, sitePermissions: SitePermissions?) { + val directions = ExternalAppBrowserFragmentDirections + .actionExternalAppBrowserFragmentToQuickSettingsSheetDialogFragment( + sessionId = session.id, + url = session.url, + isSecured = session.securityInfo.secure, + isTrackingProtectionOn = session.trackerBlockingEnabled, + sitePermissions = sitePermissions, + gravity = getAppropriateLayoutGravity() + ) + nav(R.id.externalAppBrowserFragment, directions) + } + + override fun getEngineMargins(): Pair { + val toolbarSize = resources.getDimensionPixelSize(R.dimen.browser_toolbar_height) + return toolbarSize to 0 + } + + override fun getAppropriateLayoutGravity() = Gravity.TOP + + companion object { + private const val SHARED_TRANSITION_MS = 200L + private const val TAB_ITEM_TRANSITION_NAME = "tab_item" + } +} diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml index 2be36c775..bfd262cdd 100644 --- a/app/src/main/res/navigation/nav_graph.xml +++ b/app/src/main/res/navigation/nav_graph.xml @@ -11,6 +11,12 @@ app:popUpTo="@id/nav_graph" app:popUpToInclusive="true" /> + + + + + + + + + + + + + + + + + + - - - - - - \ No newline at end of file +