Commit 9871cd5d authored by MozLando's avatar MozLando
Browse files

Merge #5479



5479: Closes #5478: Allow AppLinksInterceptor to be a standalone feature r=Amejia481 a=rocketsroger



Co-authored-by: default avatarRoger Yang <royang@mozilla.com>
parents d8b4d677 8bda3124
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import mozilla.components.concept.engine.request.RequestInterceptor
 * of security concerns.
 * @param useCases These use cases allow for the detection of, and opening of links that other apps
 * have registered to open.
 * @param launchFromInterceptor If {true} then the interceptor will launch the link in third-party apps if available.
 */
class AppLinksInterceptor(
    private val context: Context,
@@ -44,7 +45,8 @@ class AppLinksInterceptor(
    private val alwaysAllowedSchemes: Set<String> = setOf("mailto", "market", "sms", "tel"),
    private val alwaysDeniedSchemes: Set<String> = setOf("javascript", "about"),
    private val launchInApp: () -> Boolean = { false },
    private val useCases: AppLinksUseCases = AppLinksUseCases(context, launchInApp)
    private val useCases: AppLinksUseCases = AppLinksUseCases(context, launchInApp),
    private val launchFromInterceptor: Boolean = false
) : RequestInterceptor {

    override fun onLoadRequest(
@@ -60,8 +62,13 @@ class AppLinksInterceptor(
        }

        val redirect = useCases.interceptedAppLinkRedirect(uri)
        val result = handleRedirect(redirect, uri)
        if (redirect.isRedirect()) {
            return handleRedirect(redirect, uri)
            if (launchFromInterceptor && result is RequestInterceptor.InterceptionResponse.AppIntent) {
                useCases.openAppLink(result.appIntent)
            }

            return result
        }

        return null
+1 −1
Original line number Diff line number Diff line
@@ -131,7 +131,7 @@ class AppLinksUseCases(
                intent.addCategory(Intent.CATEGORY_BROWSABLE)
                intent.component = null
                intent.selector = null
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
            }

            val fallbackIntent = intent.getStringExtra(EXTRA_BROWSER_FALLBACK_URL)?.let {
+21 −0
Original line number Diff line number Diff line
@@ -9,12 +9,14 @@ import android.content.Intent
import androidx.test.ext.junit.runners.AndroidJUnit4
import mozilla.components.concept.engine.EngineSession
import mozilla.components.concept.engine.request.RequestInterceptor
import mozilla.components.support.test.any
import mozilla.components.support.test.mock
import mozilla.components.support.test.whenever
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.verify

@RunWith(AndroidJUnit4::class)
class AppLinksInterceptorTest {
@@ -22,6 +24,8 @@ class AppLinksInterceptorTest {
    private lateinit var mockUseCases: AppLinksUseCases
    private lateinit var mockGetRedirect: AppLinksUseCases.GetAppLinkRedirect
    private lateinit var mockEngineSession: EngineSession
    private lateinit var mockOpenRedirect: AppLinksUseCases.OpenAppLinkRedirect

    private lateinit var appLinksInterceptor: AppLinksInterceptor

    private val webUrl = "https://example.com"
@@ -36,7 +40,9 @@ class AppLinksInterceptorTest {
        mockUseCases = mock()
        mockEngineSession = mock()
        mockGetRedirect = mock()
        mockOpenRedirect = mock()
        whenever(mockUseCases.interceptedAppLinkRedirect).thenReturn(mockGetRedirect)
        whenever(mockUseCases.openAppLink).thenReturn(mockOpenRedirect)

        val webRedirect = AppLinkRedirect(null, webUrl, null)
        val appRedirect = AppLinkRedirect(Intent.parseUri(intentUrl, 0), null, null)
@@ -125,4 +131,19 @@ class AppLinksInterceptorTest {
        val response = appLinksInterceptor.onLoadRequest(mockEngineSession, marketplaceUrl, true, false)
        assert(response is RequestInterceptor.InterceptionResponse.AppIntent)
    }

    @Test
    fun `external app is launched when launch from interceptor is set to true`() {
        appLinksInterceptor = AppLinksInterceptor(
            context = mockContext,
            interceptLinkClicks = true,
            launchInApp = { true },
            useCases = mockUseCases,
            launchFromInterceptor = true
        )

        val response = appLinksInterceptor.onLoadRequest(mockEngineSession, webUrlWithAppLink, true, false)
        assert(response is RequestInterceptor.InterceptionResponse.AppIntent)
        verify(mockOpenRedirect).invoke(any(), any())
    }
}
+11 −0
Original line number Diff line number Diff line
@@ -31,6 +31,17 @@ permalink: /changelog/
        and renamed to `PingType.submit()`.
    * Rename `deletion_request` ping to `deletion-request` ping after glean_parser update

* **feature-app-links**
  * AppLinksInterceptor can now be used without the AppLinksFeature. Set the new parameter launchFromInterceptor = true
  ```kotlin
  AppLinksInterceptor(
      applicationContext,
      interceptLinkClicks = true,
      launchInApp = { true },
      launchFromInterceptor = true
  )
  ```

# 27.0.0

* [Commits](https://github.com/mozilla-mobile/android-components/compare/v26.0.0...v27.0.0)
+0 −16
Original line number Diff line number Diff line
@@ -9,13 +9,11 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.annotation.CallSuper
import androidx.fragment.app.Fragment
import kotlinx.android.synthetic.main.fragment_browser.view.*
import mozilla.components.browser.session.SelectionAwareSessionObserver
import mozilla.components.browser.session.Session
import mozilla.components.feature.app.links.AppLinksFeature
import mozilla.components.feature.contextmenu.ContextMenuCandidate
import mozilla.components.feature.contextmenu.ContextMenuFeature
import mozilla.components.feature.downloads.DownloadsFeature
@@ -50,7 +48,6 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler {
    private val findInPageIntegration = ViewBoundFeatureWrapper<FindInPageIntegration>()
    private val sitePermissionsFeature = ViewBoundFeatureWrapper<SitePermissionsFeature>()
    private val swipeRefreshFeature = ViewBoundFeatureWrapper<SwipeRefreshFeature>()
    private val appLinksFeature = ViewBoundFeatureWrapper<AppLinksFeature>()

    protected val sessionId: String?
        get() = arguments?.getString(SESSION_ID_KEY)
@@ -181,19 +178,6 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler {
            secureWindowFeature
        )

        appLinksFeature.set(
            feature = AppLinksFeature(
                context = requireContext(),
                sessionManager = components.sessionManager,
                sessionId = sessionId,
                fragmentManager = requireFragmentManager(),
                launchInApp = { components.preferences.getBoolean(DefaultComponents.PREF_LAUNCH_EXTERNAL_APP, false) },
                failedToLaunchAction = { Toast.makeText(context, "Failed to open in app", Toast.LENGTH_LONG).show() }
            ),
            owner = this,
            view = layout
        )

        return layout
    }

Loading