2019-01-15 02:42:58 +01:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
2019-07-12 20:38:15 +02:00
|
|
|
* 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/. */
|
2019-01-29 20:20:29 +01:00
|
|
|
|
2019-01-15 02:42:58 +01:00
|
|
|
package org.mozilla.fenix.browser
|
|
|
|
|
2019-10-25 06:38:15 +02:00
|
|
|
import android.content.Context
|
2019-01-15 02:42:58 +01:00
|
|
|
import android.os.Bundle
|
2020-06-21 23:54:49 +02:00
|
|
|
import android.os.StrictMode
|
2019-01-15 02:42:58 +01:00
|
|
|
import android.view.LayoutInflater
|
|
|
|
import android.view.View
|
|
|
|
import android.view.ViewGroup
|
2020-06-09 23:22:01 +02:00
|
|
|
import androidx.appcompat.content.res.AppCompatResources
|
2020-06-04 22:21:20 +02:00
|
|
|
import androidx.core.content.ContextCompat
|
2020-05-07 09:52:34 +02:00
|
|
|
import androidx.lifecycle.Observer
|
2020-04-02 04:56:12 +02:00
|
|
|
import androidx.navigation.fragment.findNavController
|
2019-03-04 11:42:35 +01:00
|
|
|
import com.google.android.material.snackbar.Snackbar
|
2019-11-14 21:02:27 +01:00
|
|
|
import kotlinx.android.synthetic.main.fragment_browser.view.*
|
2019-08-07 23:00:53 +02:00
|
|
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
2019-04-04 16:50:16 +02:00
|
|
|
import mozilla.components.browser.session.Session
|
2020-06-04 22:21:20 +02:00
|
|
|
import mozilla.components.browser.state.selector.findTab
|
|
|
|
import mozilla.components.browser.toolbar.BrowserToolbar
|
2020-04-22 21:54:01 +02:00
|
|
|
import mozilla.components.feature.app.links.AppLinksUseCases
|
2019-10-25 06:38:15 +02:00
|
|
|
import mozilla.components.feature.contextmenu.ContextMenuCandidate
|
2019-05-03 23:01:45 +02:00
|
|
|
import mozilla.components.feature.readerview.ReaderViewFeature
|
2020-02-18 04:20:35 +01:00
|
|
|
import mozilla.components.feature.search.SearchFeature
|
2019-10-02 06:45:04 +02:00
|
|
|
import mozilla.components.feature.session.TrackingProtectionUseCases
|
2019-08-12 18:31:59 +02:00
|
|
|
import mozilla.components.feature.sitepermissions.SitePermissions
|
2019-12-05 04:06:05 +01:00
|
|
|
import mozilla.components.feature.tab.collections.TabCollection
|
2019-11-14 21:02:27 +01:00
|
|
|
import mozilla.components.feature.tabs.WindowFeature
|
2019-11-28 00:02:47 +01:00
|
|
|
import mozilla.components.support.base.feature.UserInteractionHandler
|
2019-11-14 21:02:27 +01:00
|
|
|
import mozilla.components.support.base.feature.ViewBoundFeatureWrapper
|
2020-02-25 22:49:42 +01:00
|
|
|
import org.mozilla.fenix.HomeActivity
|
2019-02-08 16:19:46 +01:00
|
|
|
import org.mozilla.fenix.R
|
2020-04-06 23:18:41 +02:00
|
|
|
import org.mozilla.fenix.addons.runIfFragmentIsAttached
|
2020-01-02 23:31:52 +01:00
|
|
|
import org.mozilla.fenix.components.FenixSnackbar
|
2019-06-15 00:03:52 +02:00
|
|
|
import org.mozilla.fenix.components.TabCollectionStorage
|
2019-03-18 22:54:36 +01:00
|
|
|
import org.mozilla.fenix.components.metrics.Event
|
2019-08-30 19:10:58 +02:00
|
|
|
import org.mozilla.fenix.ext.components
|
2019-06-06 21:40:10 +02:00
|
|
|
import org.mozilla.fenix.ext.nav
|
2020-05-05 09:51:13 +02:00
|
|
|
import org.mozilla.fenix.ext.navigateSafe
|
2019-02-17 02:04:32 +01:00
|
|
|
import org.mozilla.fenix.ext.requireComponents
|
2019-09-10 22:29:21 +02:00
|
|
|
import org.mozilla.fenix.ext.settings
|
2020-06-21 23:54:49 +02:00
|
|
|
import org.mozilla.fenix.ext.resetPoliciesAfter
|
2020-04-02 04:56:12 +02:00
|
|
|
import org.mozilla.fenix.shortcut.FirstTimePwaObserver
|
2019-11-21 23:23:35 +01:00
|
|
|
import org.mozilla.fenix.trackingprotection.TrackingProtectionOverlay
|
2019-01-15 02:42:58 +01:00
|
|
|
|
2019-08-06 16:55:56 +02:00
|
|
|
/**
|
2019-08-12 18:31:59 +02:00
|
|
|
* Fragment used for browsing the web within the main app.
|
2019-08-06 16:55:56 +02:00
|
|
|
*/
|
2019-08-08 18:05:01 +02:00
|
|
|
@ExperimentalCoroutinesApi
|
2019-11-26 01:43:32 +01:00
|
|
|
@Suppress("TooManyFunctions", "LargeClass")
|
2019-11-28 00:02:47 +01:00
|
|
|
class BrowserFragment : BaseBrowserFragment(), UserInteractionHandler {
|
2019-03-15 18:51:04 +01:00
|
|
|
|
2019-11-14 21:02:27 +01:00
|
|
|
private val windowFeature = ViewBoundFeatureWrapper<WindowFeature>()
|
2020-02-18 04:20:35 +01:00
|
|
|
private val searchFeature = ViewBoundFeatureWrapper<SearchFeature>()
|
2019-11-14 21:02:27 +01:00
|
|
|
|
2020-06-04 22:21:20 +02:00
|
|
|
private var readerModeAvailable = false
|
|
|
|
|
2019-08-08 00:41:52 +02:00
|
|
|
override fun onCreateView(
|
|
|
|
inflater: LayoutInflater,
|
|
|
|
container: ViewGroup?,
|
|
|
|
savedInstanceState: Bundle?
|
|
|
|
): View {
|
2019-08-06 16:55:56 +02:00
|
|
|
val view = super.onCreateView(inflater, container, savedInstanceState)
|
2020-02-27 22:29:47 +01:00
|
|
|
|
2020-02-25 20:53:48 +01:00
|
|
|
startPostponedEnterTransition()
|
2019-02-05 00:41:26 +01:00
|
|
|
return view
|
2019-01-15 02:42:58 +01:00
|
|
|
}
|
2019-01-19 00:33:40 +01:00
|
|
|
|
2019-08-08 18:05:01 +02:00
|
|
|
override fun initializeUI(view: View): Session? {
|
2019-08-30 19:10:58 +02:00
|
|
|
val context = requireContext()
|
2020-02-18 04:20:35 +01:00
|
|
|
val components = context.components
|
2019-07-29 21:39:36 +02:00
|
|
|
|
2019-08-19 17:28:33 +02:00
|
|
|
return super.initializeUI(view)?.also {
|
2020-06-04 22:21:20 +02:00
|
|
|
val readerModeAction =
|
|
|
|
BrowserToolbar.ToggleButton(
|
|
|
|
image = ContextCompat.getDrawable(requireContext(), R.drawable.ic_readermode)!!,
|
2020-06-09 23:22:01 +02:00
|
|
|
imageSelected =
|
|
|
|
AppCompatResources.getDrawable(requireContext(), R.drawable.ic_readermode_selected)!!,
|
2020-06-04 22:21:20 +02:00
|
|
|
contentDescription = requireContext().getString(R.string.browser_menu_read),
|
|
|
|
contentDescriptionSelected = requireContext().getString(R.string.browser_menu_read_close),
|
|
|
|
visible = {
|
|
|
|
readerModeAvailable
|
|
|
|
},
|
|
|
|
selected = getSessionById()?.let {
|
|
|
|
activity?.components?.core?.store?.state?.findTab(it.id)?.readerState?.active
|
|
|
|
} ?: false,
|
|
|
|
listener = browserInteractor::onReaderModePressed
|
|
|
|
)
|
|
|
|
|
|
|
|
browserToolbarView.view.addPageAction(readerModeAction)
|
|
|
|
|
2019-08-08 18:05:01 +02:00
|
|
|
readerViewFeature.set(
|
2020-06-21 23:54:49 +02:00
|
|
|
feature = StrictMode.allowThreadDiskReads().resetPoliciesAfter {
|
|
|
|
ReaderViewFeature(
|
|
|
|
context,
|
|
|
|
components.core.engine,
|
|
|
|
components.core.store,
|
|
|
|
view.readerViewControlsBar
|
|
|
|
) { available, active ->
|
|
|
|
if (available) {
|
|
|
|
components.analytics.metrics.track(Event.ReaderModeAvailable)
|
|
|
|
}
|
2020-06-04 22:21:20 +02:00
|
|
|
|
2020-06-21 23:54:49 +02:00
|
|
|
readerModeAvailable = available
|
|
|
|
readerModeAction.setSelected(active)
|
2020-06-04 22:21:20 +02:00
|
|
|
|
2020-06-21 23:54:49 +02:00
|
|
|
runIfFragmentIsAttached {
|
|
|
|
browserToolbarView.view.invalidateActions()
|
|
|
|
browserToolbarView.toolbarIntegration.invalidateMenu()
|
|
|
|
}
|
2020-04-06 23:18:41 +02:00
|
|
|
}
|
2019-08-08 18:05:01 +02:00
|
|
|
},
|
|
|
|
owner = this,
|
|
|
|
view = view
|
|
|
|
)
|
|
|
|
|
2019-11-14 21:02:27 +01:00
|
|
|
windowFeature.set(
|
|
|
|
feature = WindowFeature(
|
2020-02-18 04:20:35 +01:00
|
|
|
store = components.core.store,
|
|
|
|
tabsUseCases = components.useCases.tabsUseCases
|
2019-11-14 21:02:27 +01:00
|
|
|
),
|
|
|
|
owner = this,
|
|
|
|
view = view
|
|
|
|
)
|
2020-02-18 04:20:35 +01:00
|
|
|
searchFeature.set(
|
|
|
|
feature = SearchFeature(components.core.store) {
|
|
|
|
if (it.isPrivate) {
|
|
|
|
components.useCases.searchUseCases.newPrivateTabSearch.invoke(it.query)
|
|
|
|
} else {
|
|
|
|
components.useCases.searchUseCases.newTabSearch.invoke(it.query)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
owner = this,
|
|
|
|
view = view
|
|
|
|
)
|
2019-07-29 21:39:36 +02:00
|
|
|
}
|
2019-06-01 00:38:54 +02:00
|
|
|
}
|
|
|
|
|
2019-08-01 18:56:51 +02:00
|
|
|
override fun onStart() {
|
|
|
|
super.onStart()
|
2020-04-02 04:56:12 +02:00
|
|
|
val context = requireContext()
|
|
|
|
val settings = context.settings()
|
|
|
|
val session = getSessionById()
|
|
|
|
|
2019-11-26 01:43:32 +01:00
|
|
|
val toolbarSessionObserver = TrackingProtectionOverlay(
|
2020-04-02 04:56:12 +02:00
|
|
|
context = context,
|
|
|
|
settings = settings
|
2019-11-26 01:43:32 +01:00
|
|
|
) {
|
|
|
|
browserToolbarView.view
|
|
|
|
}
|
2020-06-09 21:12:53 +02:00
|
|
|
session?.register(toolbarSessionObserver, viewLifecycleOwner, autoPause = true)
|
2020-04-02 04:56:12 +02:00
|
|
|
|
|
|
|
if (settings.shouldShowFirstTimePwaFragment) {
|
|
|
|
session?.register(
|
|
|
|
FirstTimePwaObserver(
|
|
|
|
navController = findNavController(),
|
|
|
|
settings = settings,
|
|
|
|
webAppUseCases = context.components.useCases.webAppUseCases
|
|
|
|
),
|
|
|
|
owner = this,
|
|
|
|
autoPause = true
|
|
|
|
)
|
|
|
|
}
|
2020-05-07 09:52:34 +02:00
|
|
|
|
|
|
|
subscribeToTabCollections()
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun subscribeToTabCollections() {
|
|
|
|
Observer<List<TabCollection>> {
|
|
|
|
requireComponents.core.tabCollectionStorage.cachedTabCollections = it
|
|
|
|
}.also { observer ->
|
|
|
|
requireComponents.core.tabCollectionStorage.getCollections()
|
|
|
|
.observe(viewLifecycleOwner, observer)
|
|
|
|
}
|
2019-11-26 01:43:32 +01:00
|
|
|
}
|
|
|
|
|
2019-02-25 20:37:20 +01:00
|
|
|
override fun onResume() {
|
2019-06-28 21:40:38 +02:00
|
|
|
super.onResume()
|
2020-02-25 22:49:42 +01:00
|
|
|
getSessionById()?.let {
|
|
|
|
(activity as HomeActivity).updateThemeForSession(it)
|
|
|
|
}
|
2019-06-15 00:03:52 +02:00
|
|
|
requireComponents.core.tabCollectionStorage.register(collectionStorageObserver, this)
|
2019-08-06 16:55:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
override fun onBackPressed(): Boolean {
|
|
|
|
return readerViewFeature.onBackPressed() || super.onBackPressed()
|
|
|
|
}
|
|
|
|
|
2019-08-12 18:31:59 +02:00
|
|
|
override fun navToQuickSettingsSheet(session: Session, sitePermissions: SitePermissions?) {
|
2019-09-10 22:29:21 +02:00
|
|
|
val directions =
|
|
|
|
BrowserFragmentDirections.actionBrowserFragmentToQuickSettingsSheetDialogFragment(
|
|
|
|
sessionId = session.id,
|
|
|
|
url = session.url,
|
2020-01-30 20:24:53 +01:00
|
|
|
title = session.title,
|
2019-09-10 22:29:21 +02:00
|
|
|
isSecured = session.securityInfo.secure,
|
|
|
|
sitePermissions = sitePermissions,
|
2020-01-31 13:27:48 +01:00
|
|
|
gravity = getAppropriateLayoutGravity(),
|
|
|
|
certificateName = session.securityInfo.issuer
|
2019-09-10 22:29:21 +02:00
|
|
|
)
|
|
|
|
nav(R.id.browserFragment, directions)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun navToTrackingProtectionPanel(session: Session) {
|
2020-05-05 09:51:13 +02:00
|
|
|
val navController = findNavController()
|
|
|
|
|
2019-10-02 06:45:04 +02:00
|
|
|
val useCase = TrackingProtectionUseCases(
|
|
|
|
sessionManager = requireComponents.core.sessionManager,
|
|
|
|
engine = requireComponents.core.engine
|
|
|
|
)
|
|
|
|
useCase.containsException(session) { contains ->
|
|
|
|
val isEnabled = session.trackerBlockingEnabled && !contains
|
|
|
|
val directions =
|
|
|
|
BrowserFragmentDirections.actionBrowserFragmentToTrackingProtectionPanelDialogFragment(
|
|
|
|
sessionId = session.id,
|
|
|
|
url = session.url,
|
|
|
|
trackingProtectionEnabled = isEnabled,
|
|
|
|
gravity = getAppropriateLayoutGravity()
|
|
|
|
)
|
2020-05-05 09:51:13 +02:00
|
|
|
navController.navigateSafe(R.id.browserFragment, directions)
|
2019-10-02 06:45:04 +02:00
|
|
|
}
|
2019-08-12 18:31:59 +02:00
|
|
|
}
|
2019-08-06 16:55:56 +02:00
|
|
|
|
2019-06-15 00:03:52 +02:00
|
|
|
private val collectionStorageObserver = object : TabCollectionStorage.Observer {
|
|
|
|
override fun onCollectionCreated(title: String, sessions: List<Session>) {
|
|
|
|
showTabSavedToCollectionSnackbar()
|
|
|
|
}
|
|
|
|
|
2019-07-23 23:15:46 +02:00
|
|
|
override fun onTabsAdded(tabCollection: TabCollection, sessions: List<Session>) {
|
2019-06-15 00:03:52 +02:00
|
|
|
showTabSavedToCollectionSnackbar()
|
|
|
|
}
|
|
|
|
|
2019-08-19 17:28:33 +02:00
|
|
|
private fun showTabSavedToCollectionSnackbar() {
|
|
|
|
view?.let { view ->
|
2020-04-02 21:30:13 +02:00
|
|
|
FenixSnackbar.make(
|
|
|
|
view = view,
|
|
|
|
duration = Snackbar.LENGTH_SHORT,
|
2020-04-13 21:16:01 +02:00
|
|
|
isDisplayedWithBrowserToolbar = true
|
2020-04-02 21:30:13 +02:00
|
|
|
)
|
2020-01-02 23:31:52 +01:00
|
|
|
.setText(view.context.getString(R.string.create_collection_tab_saved))
|
|
|
|
.show()
|
2019-08-19 17:28:33 +02:00
|
|
|
}
|
2019-06-15 00:03:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-25 06:38:15 +02:00
|
|
|
override fun getContextMenuCandidates(
|
|
|
|
context: Context,
|
|
|
|
view: View
|
2020-04-22 21:54:01 +02:00
|
|
|
): List<ContextMenuCandidate> {
|
|
|
|
val contextMenuCandidateAppLinksUseCases = AppLinksUseCases(
|
|
|
|
requireContext(),
|
|
|
|
{ true }
|
|
|
|
)
|
|
|
|
|
|
|
|
return ContextMenuCandidate.defaultCandidates(
|
|
|
|
context,
|
|
|
|
context.components.useCases.tabsUseCases,
|
|
|
|
context.components.useCases.contextMenuUseCases,
|
|
|
|
view,
|
|
|
|
FenixSnackbarDelegate(view)
|
|
|
|
) + ContextMenuCandidate.createOpenInExternalAppCandidate(requireContext(),
|
|
|
|
contextMenuCandidateAppLinksUseCases)
|
|
|
|
}
|
2019-10-25 06:38:15 +02:00
|
|
|
|
2019-01-28 22:26:28 +01:00
|
|
|
companion object {
|
2019-05-30 22:44:22 +02:00
|
|
|
private const val SHARED_TRANSITION_MS = 200L
|
2019-05-22 20:46:31 +02:00
|
|
|
private const val TAB_ITEM_TRANSITION_NAME = "tab_item"
|
2019-01-19 00:33:40 +01:00
|
|
|
}
|
2019-01-15 02:42:58 +01:00
|
|
|
}
|