Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.

Commit 5957e9d

Browse files
committed
Bug 1929028 - Use AppLinksFeature to prompt the user. r=android-reviewers,tthibaud
Differential Revision: https://phabricator.services.mozilla.com/D247410
1 parent 9e25ff9 commit 5957e9d

File tree

23 files changed

+454
-916
lines changed

23 files changed

+454
-916
lines changed

mobile/android/android-components/components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/GeckoEngineSession.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1023,7 +1023,12 @@ class GeckoEngineSession(
10231023
is InterceptionResponse.AppIntent -> {
10241024
appRedirectUrl = lastLoadRequestUri
10251025
notifyObservers {
1026-
onLaunchIntentRequest(url = url, appIntent = appIntent)
1026+
onLaunchIntentRequest(
1027+
url = url,
1028+
appIntent = appIntent,
1029+
fallbackUrl = fallbackUrl,
1030+
appName = appName,
1031+
)
10271032
}
10281033
}
10291034

mobile/android/android-components/components/browser/engine-gecko/src/test/java/mozilla/components/browser/engine/gecko/GeckoEngineSessionTest.kt

Lines changed: 102 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,6 @@ typealias GeckoAntiTracking = ContentBlocking.AntiTracking
112112
typealias GeckoSafeBrowsing = ContentBlocking.SafeBrowsing
113113
typealias GeckoCookieBehavior = ContentBlocking.CookieBehavior
114114

115-
private const val AID = "AID"
116-
117115
@ExperimentalCoroutinesApi
118116
@RunWith(AndroidJUnit4::class)
119117
class GeckoEngineSessionTest {
@@ -3380,6 +3378,8 @@ class GeckoEngineSessionTest {
33803378

33813379
var observedUrl: String? = null
33823380
var observedIntent: Intent? = null
3381+
var observedFallbackUrl: String? = null
3382+
var observedAppName: String? = null
33833383

33843384
var observedLoadUrl: String? = null
33853385
var observedTriggeredByRedirect: Boolean? = null
@@ -3399,7 +3399,7 @@ class GeckoEngineSessionTest {
33993399
isSubframeRequest: Boolean,
34003400
): RequestInterceptor.InterceptionResponse? {
34013401
return when (uri) {
3402-
"sample:about" -> RequestInterceptor.InterceptionResponse.AppIntent(mock(), "result")
3402+
"sample:about" -> RequestInterceptor.InterceptionResponse.AppIntent(mock(), "result", "fallback", "app")
34033403
else -> null
34043404
}
34053405
}
@@ -3410,9 +3410,13 @@ class GeckoEngineSessionTest {
34103410
override fun onLaunchIntentRequest(
34113411
url: String,
34123412
appIntent: Intent?,
3413+
fallbackUrl: String?,
3414+
appName: String?,
34133415
) {
34143416
observedUrl = url
34153417
observedIntent = appIntent
3418+
observedFallbackUrl = fallbackUrl
3419+
observedAppName = appName
34163420
}
34173421

34183422
override fun onLoadRequest(url: String, triggeredByRedirect: Boolean, triggeredByWebContent: Boolean) {
@@ -3436,6 +3440,8 @@ class GeckoEngineSessionTest {
34363440
assertEquals(result!!.poll(0), AllowOrDeny.DENY)
34373441
assertNotNull(observedIntent)
34383442
assertEquals("result", observedUrl)
3443+
assertNotNull(observedFallbackUrl)
3444+
assertNotNull(observedAppName)
34393445
assertNull(observedLoadUrl)
34403446
assertNull(observedTriggeredByRedirect)
34413447
assertNull(observedTriggeredByWebContent)
@@ -3469,6 +3475,8 @@ class GeckoEngineSessionTest {
34693475

34703476
var observedUrl: String? = null
34713477
var observedIntent: Intent? = null
3478+
var observedFallbackUrl: String? = null
3479+
var observedAppName: String? = null
34723480

34733481
var observedLoadUrl: String? = null
34743482
var observedTriggeredByRedirect: Boolean? = null
@@ -3488,7 +3496,7 @@ class GeckoEngineSessionTest {
34883496
isSubframeRequest: Boolean,
34893497
): RequestInterceptor.InterceptionResponse? {
34903498
return when (uri) {
3491-
"sample:about" -> RequestInterceptor.InterceptionResponse.AppIntent(mock(), "result")
3499+
"sample:about" -> RequestInterceptor.InterceptionResponse.AppIntent(mock(), "result", "fallback", "app")
34923500
else -> null
34933501
}
34943502
}
@@ -3499,9 +3507,13 @@ class GeckoEngineSessionTest {
34993507
override fun onLaunchIntentRequest(
35003508
url: String,
35013509
appIntent: Intent?,
3510+
fallbackUrl: String?,
3511+
appName: String?,
35023512
) {
35033513
observedUrl = url
35043514
observedIntent = appIntent
3515+
observedFallbackUrl = fallbackUrl
3516+
observedAppName = appName
35053517
}
35063518

35073519
override fun onLoadRequest(url: String, triggeredByRedirect: Boolean, triggeredByWebContent: Boolean) {
@@ -3526,6 +3538,8 @@ class GeckoEngineSessionTest {
35263538
assertNull(observedIntent)
35273539
assertNull(observedUrl)
35283540
assertNull(observedLoadUrl)
3541+
assertNull(observedFallbackUrl)
3542+
assertNull(observedAppName)
35293543
assertNull(observedTriggeredByRedirect)
35303544
assertNull(observedTriggeredByWebContent)
35313545

@@ -3543,6 +3557,8 @@ class GeckoEngineSessionTest {
35433557
assertNull(observedIntent)
35443558
assertNull(observedUrl)
35453559
assertNull(observedLoadUrl)
3560+
assertNull(observedFallbackUrl)
3561+
assertNull(observedAppName)
35463562
assertNull(observedTriggeredByRedirect)
35473563
assertNull(observedTriggeredByWebContent)
35483564
}
@@ -3574,7 +3590,7 @@ class GeckoEngineSessionTest {
35743590
isSubframeRequest: Boolean,
35753591
): RequestInterceptor.InterceptionResponse? {
35763592
return when (uri) {
3577-
"sample:about" -> RequestInterceptor.InterceptionResponse.AppIntent(mock(), "result")
3593+
"sample:about" -> RequestInterceptor.InterceptionResponse.AppIntent(mock(), "result", null, null)
35783594
else -> null
35793595
}
35803596
}
@@ -3724,29 +3740,37 @@ class GeckoEngineSessionTest {
37243740
isSubframeRequest: Boolean,
37253741
): RequestInterceptor.InterceptionResponse? {
37263742
return when (uri) {
3727-
"sample:triggeredByRedirect" -> RequestInterceptor.InterceptionResponse.AppIntent(mock(), "result1")
3728-
"sample:NotTriggeredByRedirect" -> RequestInterceptor.InterceptionResponse.AppIntent(mock(), "result2")
3729-
"sample:isDirectNavigation" -> RequestInterceptor.InterceptionResponse.AppIntent(mock(), "result3")
3743+
"sample:triggeredByRedirect" -> RequestInterceptor.InterceptionResponse.AppIntent(mock(), "result1", "fallback1", "app1")
3744+
"sample:NotTriggeredByRedirect" -> RequestInterceptor.InterceptionResponse.AppIntent(mock(), "result2", "fallback2", "app2")
3745+
"sample:isDirectNavigation" -> RequestInterceptor.InterceptionResponse.AppIntent(mock(), "result3", "fallback3", "app3")
37303746
else -> null
37313747
}
37323748
}
37333749
}
37343750

37353751
val observer = object : EngineSession.Observer {
3736-
var url: String? = null
3737-
var intent: Intent? = null
3752+
var observedUrl: String? = null
3753+
var observedIntent: Intent? = null
3754+
var observedFallbackUrl: String? = null
3755+
var observedAppName: String? = null
37383756

37393757
override fun onLaunchIntentRequest(
37403758
url: String,
37413759
appIntent: Intent?,
3760+
fallbackUrl: String?,
3761+
appName: String?,
37423762
) {
3743-
this.url = url
3744-
intent = appIntent
3763+
observedUrl = url
3764+
observedIntent = appIntent
3765+
observedFallbackUrl = fallbackUrl
3766+
observedAppName = appName
37453767
}
37463768

37473769
fun reset() {
3748-
url = null
3749-
intent = null
3770+
observedUrl = null
3771+
observedIntent = null
3772+
observedFallbackUrl = null
3773+
observedAppName = null
37503774
}
37513775
}
37523776

@@ -3757,26 +3781,32 @@ class GeckoEngineSessionTest {
37573781
mockLoadRequest("sample:triggeredByRedirect", triggeredByRedirect = true, isDirectNavigation = false),
37583782
)
37593783

3760-
assertNotNull(observer.intent)
3761-
assertEquals("result1", observer.url)
3784+
assertNotNull(observer.observedIntent)
3785+
assertEquals("result1", observer.observedUrl)
3786+
assertEquals("fallback1", observer.observedFallbackUrl)
3787+
assertEquals("app1", observer.observedAppName)
37623788

37633789
observer.reset()
37643790
navigationDelegate.value.onLoadRequest(
37653791
mock(),
37663792
mockLoadRequest("sample:NotTriggeredByRedirect", triggeredByRedirect = false, isDirectNavigation = false),
37673793
)
37683794

3769-
assertNotNull(observer.intent)
3770-
assertEquals("result2", observer.url)
3795+
assertNotNull(observer.observedIntent)
3796+
assertEquals("result2", observer.observedUrl)
3797+
assertEquals("fallback2", observer.observedFallbackUrl)
3798+
assertEquals("app2", observer.observedAppName)
37713799

37723800
observer.reset()
37733801
navigationDelegate.value.onLoadRequest(
37743802
mock(),
37753803
mockLoadRequest("sample:isDirectNavigation", triggeredByRedirect = false, isDirectNavigation = true),
37763804
)
37773805

3778-
assertNull(observer.intent)
3779-
assertNull(observer.url)
3806+
assertNull(observer.observedIntent)
3807+
assertNull(observer.observedUrl)
3808+
assertNull(observer.observedFallbackUrl)
3809+
assertNull(observer.observedAppName)
37803810
}
37813811

37823812
@Test
@@ -3829,6 +3859,8 @@ class GeckoEngineSessionTest {
38293859

38303860
var observedUrl: String? = null
38313861
var observedIntent: Intent? = null
3862+
var observedFallbackUrl: String? = null
3863+
var observedAppName: String? = null
38323864
var observedIsSubframe = false
38333865

38343866
engineSession.settings.requestInterceptor = object : RequestInterceptor {
@@ -3846,7 +3878,7 @@ class GeckoEngineSessionTest {
38463878
): RequestInterceptor.InterceptionResponse? {
38473879
observedIsSubframe = isSubframeRequest
38483880
return when (uri) {
3849-
"sample:about" -> RequestInterceptor.InterceptionResponse.AppIntent(mock(), "result")
3881+
"sample:about" -> RequestInterceptor.InterceptionResponse.AppIntent(mock(), "result", "fallback", "app")
38503882
else -> null
38513883
}
38523884
}
@@ -3857,9 +3889,13 @@ class GeckoEngineSessionTest {
38573889
override fun onLaunchIntentRequest(
38583890
url: String,
38593891
appIntent: Intent?,
3892+
fallbackUrl: String?,
3893+
appName: String?,
38603894
) {
38613895
observedUrl = url
38623896
observedIntent = appIntent
3897+
observedFallbackUrl = fallbackUrl
3898+
observedAppName = appName
38633899
}
38643900
},
38653901
)
@@ -3871,15 +3907,23 @@ class GeckoEngineSessionTest {
38713907

38723908
assertNotNull(observedIntent)
38733909
assertEquals("result", observedUrl)
3910+
assertEquals("fallback", observedFallbackUrl)
3911+
assertEquals("app", observedAppName)
38743912
assertEquals(true, observedIsSubframe)
38753913

3914+
observedUrl = null
3915+
observedIntent = null
3916+
observedFallbackUrl = null
3917+
observedAppName = null
38763918
navigationDelegate.value.onSubframeLoadRequest(
38773919
mock(),
38783920
mockLoadRequest("sample:about", triggeredByRedirect = false),
38793921
)
38803922

38813923
assertNotNull(observedIntent)
38823924
assertEquals("result", observedUrl)
3925+
assertEquals("fallback", observedFallbackUrl)
3926+
assertEquals("app", observedAppName)
38833927
assertEquals(true, observedIsSubframe)
38843928
}
38853929

@@ -3892,8 +3936,10 @@ class GeckoEngineSessionTest {
38923936

38933937
captureDelegates()
38943938

3895-
var observedLaunchIntentUrl: String? = null
3896-
var observedLaunchIntent: Intent? = null
3939+
var observedUrl: String? = null
3940+
var observedIntent: Intent? = null
3941+
var observedFallbackUrl: String? = null
3942+
var observedAppName: String? = null
38973943
var observedOnLoadRequestUrl: String? = null
38983944
var observedTriggeredByRedirect: Boolean? = null
38993945
var observedTriggeredByWebContent: Boolean? = null
@@ -3923,9 +3969,13 @@ class GeckoEngineSessionTest {
39233969
override fun onLaunchIntentRequest(
39243970
url: String,
39253971
appIntent: Intent?,
3972+
fallbackUrl: String?,
3973+
appName: String?,
39263974
) {
3927-
observedLaunchIntentUrl = url
3928-
observedLaunchIntent = appIntent
3975+
observedUrl = url
3976+
observedIntent = appIntent
3977+
observedFallbackUrl = fallbackUrl
3978+
observedAppName = appName
39293979
}
39303980

39313981
override fun onLoadRequest(
@@ -3945,8 +3995,10 @@ class GeckoEngineSessionTest {
39453995
mockLoadRequest("sample:about", triggeredByRedirect = true),
39463996
)
39473997

3948-
assertNull(observedLaunchIntentUrl)
3949-
assertNull(observedLaunchIntent)
3998+
assertNull(observedUrl)
3999+
assertNull(observedIntent)
4000+
assertNull(observedFallbackUrl)
4001+
assertNull(observedAppName)
39504002
assertNull(observedTriggeredByRedirect)
39514003
assertNull(observedTriggeredByWebContent)
39524004
assertNull(observedOnLoadRequestUrl)
@@ -3956,8 +4008,10 @@ class GeckoEngineSessionTest {
39564008
mockLoadRequest("sample:about", triggeredByRedirect = false),
39574009
)
39584010

3959-
assertNull(observedLaunchIntentUrl)
3960-
assertNull(observedLaunchIntent)
4011+
assertNull(observedUrl)
4012+
assertNull(observedIntent)
4013+
assertNull(observedFallbackUrl)
4014+
assertNull(observedAppName)
39614015
assertNull(observedTriggeredByRedirect)
39624016
assertNull(observedTriggeredByWebContent)
39634017
assertNull(observedOnLoadRequestUrl)
@@ -3972,8 +4026,10 @@ class GeckoEngineSessionTest {
39724026

39734027
captureDelegates()
39744028

3975-
var observedLaunchIntentUrl: String? = null
3976-
var observedLaunchIntent: Intent? = null
4029+
var observedUrl: String? = null
4030+
var observedIntent: Intent? = null
4031+
var observedFallbackUrl: String? = null
4032+
var observedAppName: String? = null
39774033
var observedOnLoadRequestUrl: String? = null
39784034
var observedTriggeredByRedirect: Boolean? = null
39794035
var observedTriggeredByWebContent: Boolean? = null
@@ -3984,9 +4040,13 @@ class GeckoEngineSessionTest {
39844040
override fun onLaunchIntentRequest(
39854041
url: String,
39864042
appIntent: Intent?,
4043+
fallbackUrl: String?,
4044+
appName: String?,
39874045
) {
3988-
observedLaunchIntentUrl = url
3989-
observedLaunchIntent = appIntent
4046+
observedUrl = url
4047+
observedIntent = appIntent
4048+
observedFallbackUrl = fallbackUrl
4049+
observedAppName = appName
39904050
}
39914051

39924052
override fun onLoadRequest(
@@ -4006,8 +4066,10 @@ class GeckoEngineSessionTest {
40064066
mockLoadRequest("sample:about", triggeredByRedirect = true),
40074067
)
40084068

4009-
assertNull(observedLaunchIntentUrl)
4010-
assertNull(observedLaunchIntent)
4069+
assertNull(observedUrl)
4070+
assertNull(observedIntent)
4071+
assertNull(observedFallbackUrl)
4072+
assertNull(observedAppName)
40114073
assertNotNull(observedTriggeredByRedirect)
40124074
assertTrue(observedTriggeredByRedirect!!)
40134075
assertNotNull(observedTriggeredByWebContent)
@@ -4019,8 +4081,10 @@ class GeckoEngineSessionTest {
40194081
mockLoadRequest("sample:about", triggeredByRedirect = false),
40204082
)
40214083

4022-
assertNull(observedLaunchIntentUrl)
4023-
assertNull(observedLaunchIntent)
4084+
assertNull(observedUrl)
4085+
assertNull(observedIntent)
4086+
assertNull(observedFallbackUrl)
4087+
assertNull(observedAppName)
40244088
assertNotNull(observedTriggeredByRedirect)
40254089
assertFalse(observedTriggeredByRedirect!!)
40264090
assertNotNull(observedTriggeredByWebContent)
@@ -4054,7 +4118,7 @@ class GeckoEngineSessionTest {
40544118
): RequestInterceptor.InterceptionResponse? {
40554119
return when (uri) {
40564120
fakeUrl -> null
4057-
else -> RequestInterceptor.InterceptionResponse.AppIntent(mock(), fakeUrl)
4121+
else -> RequestInterceptor.InterceptionResponse.AppIntent(mock(), fakeUrl, null, null)
40584122
}
40594123
}
40604124
}

mobile/android/android-components/components/browser/engine-system/src/main/java/mozilla/components/browser/engine/system/SystemEngineView.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,12 @@ class SystemEngineView @JvmOverloads constructor(
266266
is InterceptionResponse.AppIntent -> {
267267
if (request.isForMainFrame) {
268268
session.notifyObservers {
269-
onLaunchIntentRequest(url = url, appIntent = appIntent)
269+
onLaunchIntentRequest(
270+
url = url,
271+
appIntent = appIntent,
272+
fallbackUrl = fallbackUrl,
273+
appName = appName,
274+
)
270275
}
271276
}
272277

0 commit comments

Comments
 (0)