/* 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.browser import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.view.Gravity import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.view.WindowManager import android.widget.Button import android.widget.ImageView import android.widget.PopupWindow import android.widget.RadioButton import androidx.appcompat.widget.AppCompatImageView import androidx.core.content.ContextCompat import androidx.lifecycle.Observer import androidx.transition.TransitionInflater import com.google.android.material.snackbar.Snackbar import kotlinx.android.synthetic.main.fragment_browser.view.browserLayout import kotlinx.android.synthetic.main.fragment_browser.view.readerViewControlsBar import kotlinx.android.synthetic.main.fragment_home.bottom_bar import kotlinx.android.synthetic.main.tracking_protection_onboarding_popup.view.onboarding_message import kotlinx.coroutines.ExperimentalCoroutinesApi import mozilla.components.browser.session.Session import mozilla.components.feature.contextmenu.ContextMenuCandidate import mozilla.components.feature.readerview.ReaderViewFeature import mozilla.components.feature.session.TrackingProtectionUseCases import mozilla.components.feature.sitepermissions.SitePermissions import mozilla.components.lib.state.ext.consumeFrom import mozilla.components.support.base.feature.BackHandler import org.jetbrains.anko.dimen import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R import org.mozilla.fenix.components.FenixSnackbar import org.mozilla.fenix.components.TabCollectionStorage import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.getDimenInDip import org.mozilla.fenix.ext.increaseTapArea import org.mozilla.fenix.ext.nav import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.settings import org.mozilla.fenix.home.sessioncontrol.SessionControlChange import org.mozilla.fenix.home.sessioncontrol.TabCollection import org.mozilla.fenix.mvi.getManagedEmitter /** * Fragment used for browsing the web within the main app. */ @ExperimentalCoroutinesApi @Suppress("TooManyFunctions", "LargeClass") class BrowserFragment : BaseBrowserFragment(), BackHandler { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) postponeEnterTransition() sharedElementEnterTransition = TransitionInflater.from(context).inflateTransition(android.R.transition.move) .setDuration( SHARED_TRANSITION_MS ) } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { val view = super.onCreateView(inflater, container, savedInstanceState) view.browserLayout.transitionName = "$TAB_ITEM_TRANSITION_NAME${getSessionById()?.id}" startPostponedEnterTransition() return view } override fun initializeUI(view: View): Session? { val context = requireContext() val sessionManager = context.components.core.sessionManager return super.initializeUI(view)?.also { readerViewFeature.set( feature = ReaderViewFeature( context, context.components.core.engine, sessionManager, view.readerViewControlsBar ) { available -> if (available) { context.components.analytics.metrics.track(Event.ReaderModeAvailable) } }, owner = this, view = view ) if ((activity as HomeActivity).browsingModeManager.mode.isPrivate) { // We need to update styles for private mode programmatically for now: // https://github.com/mozilla-mobile/android-components/issues/3400 themeReaderViewControlsForPrivateMode(view.readerViewControlsBar) } consumeFrom(browserFragmentStore) { browserToolbarView.update(it) } } } override fun onStart() { super.onStart() subscribeToTabCollections() getSessionById()?.register(toolbarSessionObserver, this, autoPause = true) } private val toolbarSessionObserver = object : Session.Observer { override fun onLoadingStateChanged(session: Session, loading: Boolean) { if (!loading && shouldShowTrackingProtectionOnboarding(session) ) { showTrackingProtectionOnboarding() } } } override fun onResume() { super.onResume() getSessionById()?.let { /** * The session mode may be changed if the user is originally in Normal Mode and then * opens a 3rd party link in Private Browsing Mode. Hence, we update the theme here. * This fixes issue #5254. */ (activity as HomeActivity).updateThemeForSession(it) } requireComponents.core.tabCollectionStorage.register(collectionStorageObserver, this) } override fun onBackPressed(): Boolean { return readerViewFeature.onBackPressed() || super.onBackPressed() } override fun navToQuickSettingsSheet(session: Session, sitePermissions: SitePermissions?) { val directions = BrowserFragmentDirections.actionBrowserFragmentToQuickSettingsSheetDialogFragment( sessionId = session.id, url = session.url, isSecured = session.securityInfo.secure, sitePermissions = sitePermissions, gravity = getAppropriateLayoutGravity() ) nav(R.id.browserFragment, directions) } override fun navToTrackingProtectionPanel(session: Session) { 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() ) nav(R.id.browserFragment, directions) } } override fun getEngineMargins(): Pair { val toolbarSize = resources.getDimensionPixelSize(R.dimen.browser_toolbar_height) return 0 to toolbarSize } override fun getAppropriateLayoutGravity() = Gravity.BOTTOM private fun themeReaderViewControlsForPrivateMode(view: View) = with(view) { listOf( R.id.mozac_feature_readerview_font_size_decrease, R.id.mozac_feature_readerview_font_size_increase ).map { findViewById