Skip to content

Commit fb51727

Browse files
authored
Use deprecated shouldOverrideUrlLoading in Connection and Webview (#6029)
1 parent 0e3d21f commit fb51727

File tree

3 files changed

+44
-40
lines changed

3 files changed

+44
-40
lines changed

app/src/main/kotlin/io/homeassistant/companion/android/webview/WebViewActivity.kt

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -465,13 +465,17 @@ class WebViewActivity :
465465
resourceURL = url!!
466466
}
467467

468-
override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
469-
request?.url?.let {
468+
// Override deprecated method for backward compatibility with API 23 and below.
469+
// The non-deprecated shouldOverrideUrlLoading(WebView, WebResourceRequest) is not invoked
470+
// on these older Android versions, so this method remains necessary.
471+
@Suppress("DEPRECATION")
472+
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
473+
url?.let {
470474
try {
471-
if (it.toString().startsWith(APP_PREFIX)) {
475+
if (it.startsWith(APP_PREFIX)) {
472476
Timber.d("Launching the app")
473477
val intent = packageManager.getLaunchIntentForPackage(
474-
it.toString().substringAfter(APP_PREFIX),
478+
it.substringAfter(APP_PREFIX),
475479
)
476480
if (intent != null) {
477481
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
@@ -480,14 +484,14 @@ class WebViewActivity :
480484
Timber.w("No intent to launch app found, opening app store")
481485
val marketIntent = Intent(Intent.ACTION_VIEW)
482486
marketIntent.data =
483-
(MARKET_PREFIX + it.toString().substringAfter(APP_PREFIX)).toUri()
487+
(MARKET_PREFIX + it.substringAfter(APP_PREFIX)).toUri()
484488
startActivity(marketIntent)
485489
}
486490
return true
487-
} else if (it.toString().startsWith(INTENT_PREFIX)) {
491+
} else if (it.startsWith(INTENT_PREFIX)) {
488492
Timber.d("Launching the intent")
489493
val intent =
490-
Intent.parseUri(it.toString(), Intent.URI_INTENT_SCHEME)
494+
Intent.parseUri(it, Intent.URI_INTENT_SCHEME)
491495
val intentPackage = intent.`package`?.let { it1 ->
492496
packageManager.getLaunchIntentForPackage(
493497
it1,
@@ -503,9 +507,9 @@ class WebViewActivity :
503507
startActivity(intent)
504508
}
505509
return true
506-
} else if (!webView.url.toString().contains(it.toString())) {
510+
} else if (!webView.url.toString().contains(it)) {
507511
Timber.d("Launching browser")
508-
val browserIntent = Intent(Intent.ACTION_VIEW, it)
512+
val browserIntent = Intent(Intent.ACTION_VIEW, it.toUri())
509513
startActivity(browserIntent)
510514
return true
511515
} else {

onboarding/src/main/kotlin/io/homeassistant/companion/android/onboarding/connection/ConnectionViewModel.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,12 @@ internal class ConnectionViewModel @VisibleForTesting constructor(
134134
_isLoadingFlow.update { false }
135135
}
136136

137-
override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
138-
return request?.url?.let { interceptRedirectIfRequired(it) } ?: false
137+
// Override deprecated method for backward compatibility with API 23 and below.
138+
// The non-deprecated shouldOverrideUrlLoading(WebView, WebResourceRequest) is not invoked
139+
// on these older Android versions, so this method remains necessary.
140+
@Suppress("DEPRECATION")
141+
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
142+
return url?.toUri()?.let { interceptRedirectIfRequired(it) } ?: false
139143
}
140144

141145
private fun errorDetails(context: Context?, code: Int?, description: String?): String {

onboarding/src/test/kotlin/io/homeassistant/companion/android/onboarding/connection/ConnectionViewModelTest.kt

Lines changed: 25 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ class ConnectionViewModelTest {
5151
fun setup() {
5252
Timber.plant(ConsoleLogTree)
5353
ConsoleLogTree.verbose = true
54+
55+
mockkStatic(Uri::class)
5456
}
5557

5658
@ParameterizedTest
@@ -127,11 +129,7 @@ class ConnectionViewModelTest {
127129
@ValueSource(booleans = [true, false])
128130
fun `Given auth callback uri with code when shouldRedirect then emits Authenticated event with mTLS status and returns true`(requireMTLS: Boolean) = runTest {
129131
val authCode = "test_auth_code"
130-
val callbackUri = mockk<Uri> {
131-
every { scheme } returns "homeassistant"
132-
every { host } returns "auth-callback"
133-
every { getQueryParameter("code") } returns authCode
134-
}
132+
val stringUri = mockAuthCodeUri(scheme = "homeassistant", host = "auth-callback", authCode = authCode)
135133

136134
val viewModel = ConnectionViewModel("http://homeassistant.local:8123", keyChainRepository)
137135

@@ -145,9 +143,7 @@ class ConnectionViewModelTest {
145143

146144
val result = viewModel.webViewClient.shouldOverrideUrlLoading(
147145
null,
148-
mockk<WebResourceRequest> {
149-
every { url } returns callbackUri
150-
},
146+
stringUri,
151147
)
152148

153149
assertTrue(result)
@@ -162,13 +158,7 @@ class ConnectionViewModelTest {
162158

163159
@Test
164160
fun `Given auth callback uri without code when shouldRedirect then no event and returns false`() = runTest {
165-
val callbackUri = mockk<Uri> {
166-
every { scheme } returns "homeassistant"
167-
every { host } returns "auth-callback"
168-
every { getQueryParameter("code") } returns null
169-
}
170-
171-
mockUriParse()
161+
val stringUri = mockAuthCodeUri(scheme = "homeassistant", host = "auth-callback", authCode = null)
172162

173163
val viewModel = ConnectionViewModel("http://homeassistant.local:8123", keyChainRepository)
174164

@@ -180,9 +170,7 @@ class ConnectionViewModelTest {
180170

181171
val result = viewModel.webViewClient.shouldOverrideUrlLoading(
182172
null,
183-
mockk<WebResourceRequest> {
184-
every { url } returns callbackUri
185-
},
173+
stringUri,
186174
)
187175

188176
assertFalse(result)
@@ -193,15 +181,12 @@ class ConnectionViewModelTest {
193181

194182
@Test
195183
fun `Given unmatching uri and webview not null when shouldRedirect is invoked then open in external browser and return true`() = runTest {
196-
val callbackUri = mockk<Uri> {
197-
every { scheme } returns "http"
198-
every { host } returns "google"
199-
every { getQueryParameter("code") } returns "not_related_code"
200-
}
184+
val viewModel = ConnectionViewModel("http://homeassistant.local:8123", keyChainRepository)
201185

186+
// Used to parse the rawUrl given in the constructor of ConnectionViewModel
202187
mockUriParse()
203188

204-
val viewModel = ConnectionViewModel("http://homeassistant.local:8123", keyChainRepository)
189+
val stringUri = mockAuthCodeUri(scheme = "http", host = "google", authCode = "not_related_code")
205190

206191
turbineScope {
207192
val navigationEventsFlow = viewModel.navigationEventsFlow.testIn(backgroundScope)
@@ -211,15 +196,13 @@ class ConnectionViewModelTest {
211196

212197
val result = viewModel.webViewClient.shouldOverrideUrlLoading(
213198
null,
214-
mockk<WebResourceRequest> {
215-
every { url } returns callbackUri
216-
},
199+
stringUri,
217200
)
218201

219202
assertTrue(result)
220203
val event = navigationEventsFlow.awaitItem()
221204
assertTrue(event is ConnectionNavigationEvent.OpenExternalLink)
222-
assertEquals(callbackUri, (event as ConnectionNavigationEvent.OpenExternalLink).url)
205+
assertEquals(stringUri, (event as ConnectionNavigationEvent.OpenExternalLink).url.toString())
223206

224207
navigationEventsFlow.expectNoEvents()
225208
errorFlow.expectNoEvents()
@@ -427,8 +410,21 @@ class ConnectionViewModelTest {
427410
assertEquals(errorClass.toString(), error.rawErrorType)
428411
}
429412

413+
private fun mockAuthCodeUri(scheme: String, host: String, authCode: String?): String {
414+
val stringUri = "$scheme://$host${authCode?.let { "?code=$authCode" } ?: ""}"
415+
every { Uri.parse(stringUri) } answers {
416+
val uriString = firstArg<String>()
417+
return@answers mockk<Uri> {
418+
every { this@mockk.toString() } returns uriString
419+
every { this@mockk.scheme } returns scheme
420+
every { this@mockk.host } returns host
421+
every { getQueryParameter("code") } returns authCode
422+
}
423+
}
424+
return stringUri
425+
}
426+
430427
private fun mockUriParse() {
431-
mockkStatic(Uri::class)
432428
every { Uri.parse(any()) } answers {
433429
val uriString = firstArg<String>()
434430
val javaURL = URL(uriString)

0 commit comments

Comments
 (0)