diff --git a/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/AppRequestInterceptor.kt b/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/AppRequestInterceptor.kt deleted file mode 100644 index 1333c39e75917..0000000000000 --- a/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/AppRequestInterceptor.kt +++ /dev/null @@ -1,239 +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.content.Context -import android.net.ConnectivityManager -import androidx.annotation.VisibleForTesting -import androidx.core.content.getSystemService -import androidx.core.net.toUri -import androidx.navigation.NavController -import java.lang.ref.WeakReference -import mozilla.components.browser.errorpages.ErrorPages -import mozilla.components.browser.state.state.selectedOrDefaultSearchEngine -import mozilla.components.concept.engine.EngineSession -import mozilla.components.concept.engine.request.ErrorType -import mozilla.components.concept.engine.request.RequestInterceptor -import mozilla.components.feature.search.ext.buildSearchUrl -import org.mozilla.fenix.GleanMetrics.ErrorPage -import org.mozilla.fenix.ext.components -import org.mozilla.fenix.ext.isOnline -import org.mozilla.fenix.helpers.TestHelper.appContext - -/** - * This class overrides the application's request interceptor to deactivate the FxA web channel which is not supported - * on the staging servers. - */ -class AppRequestInterceptor( - private val context: Context, - private val isPrivateForSession: (EngineSession) -> Boolean = { false }, -) : RequestInterceptor { - - private var navController: WeakReference? = null - - fun setNavigationController(navController: NavController) { - this.navController = WeakReference(navController) - } - - override fun onLoadRequest( - engineSession: EngineSession, - uri: String, - lastUri: String?, - hasUserGesture: Boolean, - isSameDomain: Boolean, - isRedirect: Boolean, - isDirectNavigation: Boolean, - isSubframeRequest: Boolean, - ): RequestInterceptor.InterceptionResponse? { - interceptErrorPageAction(uri)?.let { - return it - } - - interceptFxaRequest( - engineSession, - uri, - lastUri, - hasUserGesture, - isSameDomain, - isRedirect, - isDirectNavigation, - isSubframeRequest, - ) - ?.let { response -> - return response - } - return context.components.services.appLinksInterceptor.onLoadRequest( - engineSession, - uri, - lastUri, - hasUserGesture, - isSameDomain, - isRedirect, - isDirectNavigation, - isSubframeRequest, - ) - } - - override fun onErrorRequest( - session: EngineSession, - errorType: ErrorType, - uri: String?, - ): RequestInterceptor.ErrorResponse? { - val improvedErrorType = improveErrorType(errorType) - val riskLevel = getRiskLevel(improvedErrorType) - - ErrorPage.visitedError.record(ErrorPage.VisitedErrorExtra(improvedErrorType.name)) - - val isPrivate = isPrivateForSession(session) - val archiveActionEnabled = context.components.settings.isWaybackMachineEnabled - - val errorPageUri = - ErrorPages.createUrlEncodedErrorPage( - context = context, - errorType = improvedErrorType, - uri = uri, - htmlResource = riskLevel.htmlRes, - errorStringsProvider = FenixErrorStringsProvider(), - isPrivate = isPrivate, - archiveActionEnabled = archiveActionEnabled, - ) - - return RequestInterceptor.ErrorResponse(errorPageUri) - } - - // This method is the only difference from the production code. - // Otherwise the code should be kept identical - @Suppress("LongParameterList") // Mirrors the production RequestInterceptor.onLoadRequest signature. - private fun interceptFxaRequest( - engineSession: EngineSession, - uri: String, - lastUri: String?, - hasUserGesture: Boolean, - isSameDomain: Boolean, - isRedirect: Boolean, - isDirectNavigation: Boolean, - isSubframeRequest: Boolean, - ): RequestInterceptor.InterceptionResponse? { - return appContext.components.services.accountsAuthFeature.interceptor.onLoadRequest( - engineSession, - uri, - lastUri, - hasUserGesture, - isSameDomain, - isRedirect, - isDirectNavigation, - isSubframeRequest, - ) - } - - /** - * Intercepts navigations the error page makes to the [ERROR_PAGE_ACTION_SCHEME] sentinel scheme to hand archive - * actions back to native code: searching the web for the failed page with the user's default search engine, or - * opening a located archived copy. Returns `null` for any other [uri] so normal navigation proceeds. - */ - private fun interceptErrorPageAction(uri: String): RequestInterceptor.InterceptionResponse? { - if (!uri.startsWith("$ERROR_PAGE_ACTION_SCHEME://")) { - return null - } - - val parsed = uri.toUri() - return when (parsed.host) { - ERROR_PAGE_ACTION_ATTEMPT -> { - ErrorPage.archiveButtonClicked.record() - RequestInterceptor.InterceptionResponse.Deny - } - - ERROR_PAGE_ACTION_SEARCH -> { - val query = parsed.getQueryParameter("q").orEmpty() - val searchEngine = context.components.core.store.state.search.selectedOrDefaultSearchEngine - if (query.isEmpty() || searchEngine == null) { - RequestInterceptor.InterceptionResponse.Deny - } else { - ErrorPage.archiveSearchWebSelected.record() - RequestInterceptor.InterceptionResponse.Url(searchEngine.buildSearchUrl(query)) - } - } - - ERROR_PAGE_ACTION_OPEN -> { - val archiveUrl = parsed.getQueryParameter("url").orEmpty() - if (archiveUrl.isEmpty()) { - RequestInterceptor.InterceptionResponse.Deny - } else { - ErrorPage.archivedVersionOpened.record() - RequestInterceptor.InterceptionResponse.Url(archiveUrl) - } - } - - else -> RequestInterceptor.InterceptionResponse.Deny - } - } - - /** Where possible, this will make the error type more accurate by including information not available to AC. */ - private fun improveErrorType(errorType: ErrorType): ErrorType { - // This is not an ideal solution. For context, see: - // https://github.com/mozilla-mobile/android-components/pull/5068#issuecomment-558415367 - - val isConnected: Boolean = context.getSystemService()!!.isOnline() - - return when { - errorType == ErrorType.ERROR_UNKNOWN_HOST && !isConnected -> ErrorType.ERROR_NO_INTERNET - errorType == ErrorType.ERROR_HTTPS_ONLY -> ErrorType.ERROR_HTTPS_ONLY - else -> errorType - } - } - - private fun getRiskLevel(errorType: ErrorType): RiskLevel = - when (errorType) { - ErrorType.UNKNOWN, - ErrorType.ERROR_NET_INTERRUPT, - ErrorType.ERROR_NET_TIMEOUT, - ErrorType.ERROR_CONNECTION_REFUSED, - ErrorType.ERROR_LOCAL_NETWORK_ACCESS_DENIED, - ErrorType.ERROR_UNKNOWN_SOCKET_TYPE, - ErrorType.ERROR_REDIRECT_LOOP, - ErrorType.ERROR_OFFLINE, - ErrorType.ERROR_NET_RESET, - ErrorType.ERROR_UNSAFE_CONTENT_TYPE, - ErrorType.ERROR_CORRUPTED_CONTENT, - ErrorType.ERROR_CONTENT_CRASHED, - ErrorType.ERROR_INVALID_CONTENT_ENCODING, - ErrorType.ERROR_UNKNOWN_HOST, - ErrorType.ERROR_MALFORMED_URI, - ErrorType.ERROR_FILE_NOT_FOUND, - ErrorType.ERROR_FILE_ACCESS_DENIED, - ErrorType.ERROR_PROXY_CONNECTION_REFUSED, - ErrorType.ERROR_UNKNOWN_PROXY_HOST, - ErrorType.ERROR_NO_INTERNET, - ErrorType.ERROR_HTTPS_ONLY, - ErrorType.ERROR_BAD_HSTS_CERT, - ErrorType.ERROR_UNKNOWN_PROTOCOL -> RiskLevel.Low - - ErrorType.ERROR_SECURITY_BAD_CERT, - ErrorType.ERROR_SECURITY_SSL, - ErrorType.ERROR_PORT_BLOCKED -> RiskLevel.Medium - - ErrorType.ERROR_SAFEBROWSING_HARMFUL_URI, - ErrorType.ERROR_SAFEBROWSING_MALWARE_URI, - ErrorType.ERROR_SAFEBROWSING_PHISHING_URI, - ErrorType.ERROR_SAFEBROWSING_UNWANTED_URI, - ErrorType.ERROR_HARMFULADDON_URI -> RiskLevel.High - } - - internal enum class RiskLevel(val htmlRes: String) { - Low(LOW_AND_MEDIUM_RISK_ERROR_PAGES), - Medium(LOW_AND_MEDIUM_RISK_ERROR_PAGES), - High(HIGH_RISK_ERROR_PAGES), - } - - companion object { - internal const val LOW_AND_MEDIUM_RISK_ERROR_PAGES = "low_and_medium_risk_error_pages.html" - internal const val HIGH_RISK_ERROR_PAGES = "high_risk_error_pages.html" - - @VisibleForTesting internal const val ERROR_PAGE_ACTION_SCHEME = "firefox-error-action" - private const val ERROR_PAGE_ACTION_ATTEMPT = "attempt" - private const val ERROR_PAGE_ACTION_SEARCH = "search" - private const val ERROR_PAGE_ACTION_OPEN = "open" - } -} diff --git a/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/components/FxaServer.kt b/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/components/FxaServer.kt deleted file mode 100644 index ad0661e208a47..0000000000000 --- a/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/components/FxaServer.kt +++ /dev/null @@ -1,20 +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 - -import android.content.Context -import mozilla.appservices.fxaclient.FxaConfig -import mozilla.appservices.fxaclient.FxaServer - -/** Utility to configure Firefox Account stage servers. */ -object FxaServer { - private const val CLIENT_ID = "a2270f727f45f648" - private const val REDIRECT_URL = "urn:ietf:wg:oauth:2.0:oob:oauth-redirect-webchannel" - - @Suppress("UNUSED_PARAMETER") - fun config(context: Context): FxaConfig { - return FxaConfig(FxaServer.Stage, CLIENT_ID, REDIRECT_URL) - } -} diff --git a/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/MainMenuTest.kt b/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/MainMenuTest.kt index 9333e1abc97f0..1564b9f14d733 100644 --- a/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/MainMenuTest.kt +++ b/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/MainMenuTest.kt @@ -132,6 +132,7 @@ class MainMenuTest { navigationToolbar(composeTestRule) {} .enterURLAndEnterToBrowser(pdfPage.url) { + clickPageObject(composeTestRule, itemContainingText("Stay in")) waitForPageToLoad() verifyPageContent(pdfPage.content) } @@ -604,6 +605,7 @@ class MainMenuTest { navigationToolbar(composeTestRule) {} .enterURLAndEnterToBrowser(youtubeURL) { + clickPageObject(composeTestRule, itemContainingText("Stay in")) waitForPageToLoad(waitingTime) } .openThreeDotMenu { @@ -1669,6 +1671,7 @@ class MainMenuTest { ) browserScreen(composeTestRule) { + clickPageObject(composeTestRule, itemContainingText("Stay in")) verifyPageContent(customTabPDF.content) }