diff --git a/app/src/main/kotlin/io/homeassistant/companion/android/webview/WebViewActivity.kt b/app/src/main/kotlin/io/homeassistant/companion/android/webview/WebViewActivity.kt index 32acf2abf69..0afc0f6a4c1 100644 --- a/app/src/main/kotlin/io/homeassistant/companion/android/webview/WebViewActivity.kt +++ b/app/src/main/kotlin/io/homeassistant/companion/android/webview/WebViewActivity.kt @@ -653,9 +653,12 @@ class WebViewActivity : startActivity(intent) } return true - } else if (!webView.url.toString().contains(it)) { + } + + val targetUrl = it.toUri() + if (shouldOpenInExternalBrowser(currentUrl = webView.url, targetUrl = targetUrl)) { Timber.d("Launching browser") - val browserIntent = Intent(Intent.ACTION_VIEW, it.toUri()) + val browserIntent = Intent(Intent.ACTION_VIEW, targetUrl) startActivity(browserIntent) return true } else { diff --git a/app/src/main/kotlin/io/homeassistant/companion/android/webview/WebViewUrlOverride.kt b/app/src/main/kotlin/io/homeassistant/companion/android/webview/WebViewUrlOverride.kt new file mode 100644 index 00000000000..228f9039f94 --- /dev/null +++ b/app/src/main/kotlin/io/homeassistant/companion/android/webview/WebViewUrlOverride.kt @@ -0,0 +1,15 @@ +package io.homeassistant.companion.android.webview + +import android.net.Uri +import io.homeassistant.companion.android.util.hasSameOrigin + +internal fun shouldOpenInExternalBrowser(currentUrl: String?, targetUrl: Uri): Boolean { + if (!targetUrl.isHttpOrHttpsWithHost()) return true + + return !targetUrl.hasSameOrigin(currentUrl) +} + +private fun Uri.isHttpOrHttpsWithHost(): Boolean { + return host != null && + (scheme.equals("http", ignoreCase = true) || scheme.equals("https", ignoreCase = true)) +} diff --git a/app/src/test/kotlin/io/homeassistant/companion/android/webview/WebViewUrlOverrideTest.kt b/app/src/test/kotlin/io/homeassistant/companion/android/webview/WebViewUrlOverrideTest.kt new file mode 100644 index 00000000000..7e81ba7264a --- /dev/null +++ b/app/src/test/kotlin/io/homeassistant/companion/android/webview/WebViewUrlOverrideTest.kt @@ -0,0 +1,87 @@ +package io.homeassistant.companion.android.webview + +import android.net.Uri +import dagger.hilt.android.testing.HiltTestApplication +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config + +@RunWith(RobolectricTestRunner::class) +@Config(application = HiltTestApplication::class) +class WebViewUrlOverrideTest { + + @Test + fun `Given same origin URL with different path then WebView should handle it`() { + val targetUrl = Uri.parse("http://homeassistant.local:8123/lovelace/default") + + val shouldOpen = shouldOpenInExternalBrowser( + currentUrl = "http://homeassistant.local:8123/", + targetUrl = targetUrl, + ) + + assertFalse(shouldOpen) + } + + @Test + fun `Given different origin URL then external browser should handle it`() { + val targetUrl = Uri.parse("https://www.home-assistant.io/docs") + + val shouldOpen = shouldOpenInExternalBrowser( + currentUrl = "http://homeassistant.local:8123/", + targetUrl = targetUrl, + ) + + assertTrue(shouldOpen) + } + + @Test + fun `Given missing current URL then external browser should handle it`() { + val targetUrl = Uri.parse("http://homeassistant.local:8123/lovelace/default") + + val shouldOpen = shouldOpenInExternalBrowser( + currentUrl = null, + targetUrl = targetUrl, + ) + + assertTrue(shouldOpen) + } + + @Test + fun `Given mail URL then external browser should handle it`() { + val targetUrl = Uri.parse("mailto:user@example.com") + + val shouldOpen = shouldOpenInExternalBrowser( + currentUrl = "http://homeassistant.local:8123/", + targetUrl = targetUrl, + ) + + assertTrue(shouldOpen) + } + + @Test + fun `Given telephone URL then external browser should handle it`() { + val targetUrl = Uri.parse("tel:+15555555555") + + val shouldOpen = shouldOpenInExternalBrowser( + currentUrl = "http://homeassistant.local:8123/", + targetUrl = targetUrl, + ) + + assertTrue(shouldOpen) + } + + @Test + fun `Given relative URL then external browser should handle it`() { + val targetUrl = Uri.parse("/lovelace/default") + + val shouldOpen = shouldOpenInExternalBrowser( + currentUrl = "http://homeassistant.local:8123/", + targetUrl = targetUrl, + ) + + assertTrue(shouldOpen) + } +}