Loading components/feature/app-links/src/main/java/mozilla/components/feature/app/links/AppLinksInterceptor.kt +7 −7 Original line number Diff line number Diff line Loading @@ -57,15 +57,15 @@ class AppLinksInterceptor( isSameDomain: Boolean ): RequestInterceptor.InterceptionResponse? { val uriScheme = Uri.parse(uri).scheme val engineSupportsScheme = engineSupportedSchemes.contains(uriScheme) val doNotIntercept = when { uriScheme == null -> true // If request not from user gesture or if we're already on the site, // and we're clicking around then let's not go to an external app. (!hasUserGesture && engineSupportedSchemes.contains(uriScheme)) || isSameDomain -> true (!hasUserGesture || isSameDomain) && engineSupportsScheme -> true // If scheme not in whitelist then follow user preference (!interceptLinkClicks || !launchInApp()) && engineSupportedSchemes.contains(uriScheme) -> true (!interceptLinkClicks || !launchInApp()) && engineSupportsScheme -> true // Never go to an external app when scheme is in blacklist alwaysDeniedSchemes.contains(uriScheme) -> true else -> false Loading @@ -76,7 +76,8 @@ class AppLinksInterceptor( } val redirect = useCases.interceptedAppLinkRedirect(uri) val result = handleRedirect(redirect, uri, hasUserGesture) val result = handleRedirect(redirect, uri) if (redirect.isRedirect()) { if (launchFromInterceptor && result is RequestInterceptor.InterceptionResponse.AppIntent) { result.appIntent.flags = result.appIntent.flags or Intent.FLAG_ACTIVITY_NEW_TASK Loading @@ -94,8 +95,7 @@ class AppLinksInterceptor( @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) internal fun handleRedirect( redirect: AppLinkRedirect, uri: String, hasUserGesture: Boolean uri: String ): RequestInterceptor.InterceptionResponse? { if (!redirect.hasExternalApp()) { redirect.marketplaceIntent?.let { Loading @@ -109,7 +109,7 @@ class AppLinksInterceptor( return null } if (!hasUserGesture || !launchInApp()) { if (!launchInApp()) { redirect.fallbackUrl?.let { return RequestInterceptor.InterceptionResponse.Url(it) } Loading components/feature/app-links/src/test/java/mozilla/components/feature/app/links/AppLinksInterceptorTest.kt +33 −11 Original line number Diff line number Diff line Loading @@ -31,7 +31,7 @@ class AppLinksInterceptorTest { private val webUrl = "https://example.com" private val webUrlWithAppLink = "https://soundcloud.com" private val intentUrl = "zxing://scan" private val intentUrl = "zxing://scan;S.browser_fallback_url=example.com" private val fallbackUrl = "https://getpocket.com" private val marketplaceUrl = "market://details?id=example.com" Loading Loading @@ -207,6 +207,28 @@ class AppLinksInterceptorTest { assert(response is RequestInterceptor.InterceptionResponse.AppIntent) } @Test fun `not supported schemes request should not use fallback if user preference is launch in app`() { val engineSession: EngineSession = mock() val supportedScheme = "supported" val notSupportedScheme = "not_supported" val blacklistedScheme = "blacklisted" val feature = AppLinksInterceptor( context = mockContext, interceptLinkClicks = false, engineSupportedSchemes = setOf(supportedScheme), alwaysDeniedSchemes = setOf(blacklistedScheme), launchInApp = { true }, useCases = mockUseCases ) val notSupportedUrl = "$notSupportedScheme://example.com" val notSupportedRedirect = AppLinkRedirect(Intent.parseUri(notSupportedUrl, 0), fallbackUrl, null) whenever(mockGetRedirect.invoke(notSupportedUrl)).thenReturn(notSupportedRedirect) val response = feature.onLoadRequest(engineSession, notSupportedUrl, false, false) assert(response is RequestInterceptor.InterceptionResponse.AppIntent) } @Test fun `not supported schemes request uses fallback URL if available and launchInApp is set to false`() { val engineSession: EngineSession = mock() Loading Loading @@ -289,7 +311,7 @@ class AppLinksInterceptorTest { } @Test fun `external app is launched when launch from interceptor is set to true`() { fun `external app is launched when launch in app is set to true and it is user triggered`() { appLinksInterceptor = AppLinksInterceptor( context = mockContext, interceptLinkClicks = true, Loading @@ -314,23 +336,23 @@ class AppLinksInterceptorTest { ) val testRedirect = AppLinkRedirect(Intent.parseUri(intentUrl, 0), fallbackUrl, null) val response = appLinksInterceptor.handleRedirect(testRedirect, intentUrl, true) val response = appLinksInterceptor.handleRedirect(testRedirect, intentUrl) assert(response is RequestInterceptor.InterceptionResponse.Url) } @Test fun `try to use fallback url if not trigger by user gesture`() { fun `external app is launched when url scheme is not supported by the engine`() { appLinksInterceptor = AppLinksInterceptor( context = mockContext, interceptLinkClicks = true, launchInApp = { true }, launchInApp = { false }, useCases = mockUseCases, launchFromInterceptor = true ) val testRedirect = AppLinkRedirect(Intent.parseUri(intentUrl, 0), fallbackUrl, null) val response = appLinksInterceptor.handleRedirect(testRedirect, intentUrl, false) assert(response is RequestInterceptor.InterceptionResponse.Url) val response = appLinksInterceptor.onLoadRequest(mockEngineSession, intentUrl, false, true) assert(response is RequestInterceptor.InterceptionResponse.AppIntent) verify(mockOpenRedirect).invoke(any(), anyBoolean(), any()) } @Test Loading @@ -344,7 +366,7 @@ class AppLinksInterceptorTest { ) val testRedirect = AppLinkRedirect(Intent.parseUri(intentUrl, 0), fallbackUrl, null) val response = appLinksInterceptor.handleRedirect(testRedirect, intentUrl, true) val response = appLinksInterceptor.handleRedirect(testRedirect, intentUrl) assert(response is RequestInterceptor.InterceptionResponse.AppIntent) } Loading @@ -359,7 +381,7 @@ class AppLinksInterceptorTest { ) val testRedirect = AppLinkRedirect(null, fallbackUrl, Intent.parseUri(marketplaceUrl, 0)) val response = appLinksInterceptor.handleRedirect(testRedirect, webUrl, true) val response = appLinksInterceptor.handleRedirect(testRedirect, webUrl) assert(response is RequestInterceptor.InterceptionResponse.AppIntent) } Loading @@ -374,7 +396,7 @@ class AppLinksInterceptorTest { ) val testRedirect = AppLinkRedirect(null, fallbackUrl, null) val response = appLinksInterceptor.handleRedirect(testRedirect, webUrl, true) val response = appLinksInterceptor.handleRedirect(testRedirect, webUrl) assert(response is RequestInterceptor.InterceptionResponse.Url) } } Loading
components/feature/app-links/src/main/java/mozilla/components/feature/app/links/AppLinksInterceptor.kt +7 −7 Original line number Diff line number Diff line Loading @@ -57,15 +57,15 @@ class AppLinksInterceptor( isSameDomain: Boolean ): RequestInterceptor.InterceptionResponse? { val uriScheme = Uri.parse(uri).scheme val engineSupportsScheme = engineSupportedSchemes.contains(uriScheme) val doNotIntercept = when { uriScheme == null -> true // If request not from user gesture or if we're already on the site, // and we're clicking around then let's not go to an external app. (!hasUserGesture && engineSupportedSchemes.contains(uriScheme)) || isSameDomain -> true (!hasUserGesture || isSameDomain) && engineSupportsScheme -> true // If scheme not in whitelist then follow user preference (!interceptLinkClicks || !launchInApp()) && engineSupportedSchemes.contains(uriScheme) -> true (!interceptLinkClicks || !launchInApp()) && engineSupportsScheme -> true // Never go to an external app when scheme is in blacklist alwaysDeniedSchemes.contains(uriScheme) -> true else -> false Loading @@ -76,7 +76,8 @@ class AppLinksInterceptor( } val redirect = useCases.interceptedAppLinkRedirect(uri) val result = handleRedirect(redirect, uri, hasUserGesture) val result = handleRedirect(redirect, uri) if (redirect.isRedirect()) { if (launchFromInterceptor && result is RequestInterceptor.InterceptionResponse.AppIntent) { result.appIntent.flags = result.appIntent.flags or Intent.FLAG_ACTIVITY_NEW_TASK Loading @@ -94,8 +95,7 @@ class AppLinksInterceptor( @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) internal fun handleRedirect( redirect: AppLinkRedirect, uri: String, hasUserGesture: Boolean uri: String ): RequestInterceptor.InterceptionResponse? { if (!redirect.hasExternalApp()) { redirect.marketplaceIntent?.let { Loading @@ -109,7 +109,7 @@ class AppLinksInterceptor( return null } if (!hasUserGesture || !launchInApp()) { if (!launchInApp()) { redirect.fallbackUrl?.let { return RequestInterceptor.InterceptionResponse.Url(it) } Loading
components/feature/app-links/src/test/java/mozilla/components/feature/app/links/AppLinksInterceptorTest.kt +33 −11 Original line number Diff line number Diff line Loading @@ -31,7 +31,7 @@ class AppLinksInterceptorTest { private val webUrl = "https://example.com" private val webUrlWithAppLink = "https://soundcloud.com" private val intentUrl = "zxing://scan" private val intentUrl = "zxing://scan;S.browser_fallback_url=example.com" private val fallbackUrl = "https://getpocket.com" private val marketplaceUrl = "market://details?id=example.com" Loading Loading @@ -207,6 +207,28 @@ class AppLinksInterceptorTest { assert(response is RequestInterceptor.InterceptionResponse.AppIntent) } @Test fun `not supported schemes request should not use fallback if user preference is launch in app`() { val engineSession: EngineSession = mock() val supportedScheme = "supported" val notSupportedScheme = "not_supported" val blacklistedScheme = "blacklisted" val feature = AppLinksInterceptor( context = mockContext, interceptLinkClicks = false, engineSupportedSchemes = setOf(supportedScheme), alwaysDeniedSchemes = setOf(blacklistedScheme), launchInApp = { true }, useCases = mockUseCases ) val notSupportedUrl = "$notSupportedScheme://example.com" val notSupportedRedirect = AppLinkRedirect(Intent.parseUri(notSupportedUrl, 0), fallbackUrl, null) whenever(mockGetRedirect.invoke(notSupportedUrl)).thenReturn(notSupportedRedirect) val response = feature.onLoadRequest(engineSession, notSupportedUrl, false, false) assert(response is RequestInterceptor.InterceptionResponse.AppIntent) } @Test fun `not supported schemes request uses fallback URL if available and launchInApp is set to false`() { val engineSession: EngineSession = mock() Loading Loading @@ -289,7 +311,7 @@ class AppLinksInterceptorTest { } @Test fun `external app is launched when launch from interceptor is set to true`() { fun `external app is launched when launch in app is set to true and it is user triggered`() { appLinksInterceptor = AppLinksInterceptor( context = mockContext, interceptLinkClicks = true, Loading @@ -314,23 +336,23 @@ class AppLinksInterceptorTest { ) val testRedirect = AppLinkRedirect(Intent.parseUri(intentUrl, 0), fallbackUrl, null) val response = appLinksInterceptor.handleRedirect(testRedirect, intentUrl, true) val response = appLinksInterceptor.handleRedirect(testRedirect, intentUrl) assert(response is RequestInterceptor.InterceptionResponse.Url) } @Test fun `try to use fallback url if not trigger by user gesture`() { fun `external app is launched when url scheme is not supported by the engine`() { appLinksInterceptor = AppLinksInterceptor( context = mockContext, interceptLinkClicks = true, launchInApp = { true }, launchInApp = { false }, useCases = mockUseCases, launchFromInterceptor = true ) val testRedirect = AppLinkRedirect(Intent.parseUri(intentUrl, 0), fallbackUrl, null) val response = appLinksInterceptor.handleRedirect(testRedirect, intentUrl, false) assert(response is RequestInterceptor.InterceptionResponse.Url) val response = appLinksInterceptor.onLoadRequest(mockEngineSession, intentUrl, false, true) assert(response is RequestInterceptor.InterceptionResponse.AppIntent) verify(mockOpenRedirect).invoke(any(), anyBoolean(), any()) } @Test Loading @@ -344,7 +366,7 @@ class AppLinksInterceptorTest { ) val testRedirect = AppLinkRedirect(Intent.parseUri(intentUrl, 0), fallbackUrl, null) val response = appLinksInterceptor.handleRedirect(testRedirect, intentUrl, true) val response = appLinksInterceptor.handleRedirect(testRedirect, intentUrl) assert(response is RequestInterceptor.InterceptionResponse.AppIntent) } Loading @@ -359,7 +381,7 @@ class AppLinksInterceptorTest { ) val testRedirect = AppLinkRedirect(null, fallbackUrl, Intent.parseUri(marketplaceUrl, 0)) val response = appLinksInterceptor.handleRedirect(testRedirect, webUrl, true) val response = appLinksInterceptor.handleRedirect(testRedirect, webUrl) assert(response is RequestInterceptor.InterceptionResponse.AppIntent) } Loading @@ -374,7 +396,7 @@ class AppLinksInterceptorTest { ) val testRedirect = AppLinkRedirect(null, fallbackUrl, null) val response = appLinksInterceptor.handleRedirect(testRedirect, webUrl, true) val response = appLinksInterceptor.handleRedirect(testRedirect, webUrl) assert(response is RequestInterceptor.InterceptionResponse.Url) } }