diff --git a/app/src/androidTest/java/au/com/shiftyjelly/pocketcasts/deeplink/DeepLinkFactoryTest.kt b/app/src/androidTest/java/au/com/shiftyjelly/pocketcasts/deeplink/DeepLinkFactoryTest.kt index 12520b5975..72eaad3a16 100644 --- a/app/src/androidTest/java/au/com/shiftyjelly/pocketcasts/deeplink/DeepLinkFactoryTest.kt +++ b/app/src/androidTest/java/au/com/shiftyjelly/pocketcasts/deeplink/DeepLinkFactoryTest.kt @@ -247,4 +247,81 @@ class DeepLinkFactoryTest { assertEquals(PocketCastsWebsiteDeepLink, deepLink) } + + @Test + fun podloveHttps() { + val intent = Intent() + .setAction(ACTION_VIEW) + .setData(Uri.parse("pktc://subscribehttps/mypodcast.com/rss/123")) + + val deepLink = factory.create(intent) + + assertEquals(ShowPodcastFromUrlDeepLink("https://mypodcast.com/rss/123"), deepLink) + } + + @Test + fun podloveHttpsWithParams() { + val intent = Intent() + .setAction(ACTION_VIEW) + .setData(Uri.parse("pktc://subscribehttps/mypodcast.com/rss/123?someKey=someValue")) + + val deepLink = factory.create(intent) + + assertEquals(ShowPodcastFromUrlDeepLink("https://mypodcast.com/rss/123?someKey=someValue"), deepLink) + } + + @Test + fun podloveHttp() { + val intent = Intent() + .setAction(ACTION_VIEW) + .setData(Uri.parse("pktc://subscribe/mypodcast.com/rss/123")) + + val deepLink = factory.create(intent) + + assertEquals(ShowPodcastFromUrlDeepLink("http://mypodcast.com/rss/123"), deepLink) + } + + @Test + fun podloveHttpWithParams() { + val intent = Intent() + .setAction(ACTION_VIEW) + .setData(Uri.parse("pktc://subscribe/mypodcast.com/rss/123?someKey=someValue")) + + val deepLink = factory.create(intent) + + assertEquals(ShowPodcastFromUrlDeepLink("http://mypodcast.com/rss/123?someKey=someValue"), deepLink) + } + + @Test + fun podloveWithWrongScheme() { + val intent = Intent() + .setAction(ACTION_VIEW) + .setData(Uri.parse("https://subscribehttps/mypodcast.com/rss/123")) + + val deepLink = factory.create(intent) + + assertNull(deepLink) + } + + @Test + fun podloveWithWrongHost() { + val intent = Intent() + .setAction(ACTION_VIEW) + .setData(Uri.parse("pktc://subscribehttp/mypodcast.com/rss/123")) + + val deepLink = factory.create(intent) + + assertNull(deepLink) + } + + @Test + fun podloveWithShortPath() { + val intent = Intent() + .setAction(ACTION_VIEW) + .setData(Uri.parse("pktc://subscribe/aa")) + + val deepLink = factory.create(intent) + + assertNull(deepLink) + } } diff --git a/app/src/androidTest/java/au/com/shiftyjelly/pocketcasts/views/helper/IntentUtilTest.kt b/app/src/androidTest/java/au/com/shiftyjelly/pocketcasts/views/helper/IntentUtilTest.kt index 4a9558f6f2..7b8248668c 100644 --- a/app/src/androidTest/java/au/com/shiftyjelly/pocketcasts/views/helper/IntentUtilTest.kt +++ b/app/src/androidTest/java/au/com/shiftyjelly/pocketcasts/views/helper/IntentUtilTest.kt @@ -1,7 +1,6 @@ package au.com.shiftyjelly.pocketcasts.views.helper import android.content.Intent -import android.net.Uri import org.junit.Assert.assertEquals import org.junit.Test @@ -22,44 +21,4 @@ class IntentUtilTest { assertEquals("http", intent.data?.scheme) assertEquals("www.google.com", intent.data?.host) } - - @Test - fun testSubscribeUrlWithParams() { - val intent = Intent(Intent.ACTION_VIEW) - val url = "pktc://subscribe/mypodcast.memberfulcontent.com/rss/6618?someKey=someValue" - intent.data = Uri.parse(url) - - val parsed = IntentUtil.getPodloveUrl(intent) - assertEquals("http://mypodcast.memberfulcontent.com/rss/6618?someKey=someValue", parsed) - } - - @Test - fun testSubscribeUrlWithoutParams() { - val intent = Intent(Intent.ACTION_VIEW) - val url = "pktc://subscribe/mypodcast.com/rss/123" - intent.data = Uri.parse(url) - - val parsed = IntentUtil.getPodloveUrl(intent) - assertEquals("http://mypodcast.com/rss/123", parsed) - } - - @Test - fun testSubscribeUrlWithParamsHttps() { - val intent = Intent(Intent.ACTION_VIEW) - val url = "pktc://subscribehttps/mypodcast.memberfulcontent.com/rss/6618?someKey=someValue" - intent.data = Uri.parse(url) - - val parsed = IntentUtil.getPodloveUrl(intent) - assertEquals("https://mypodcast.memberfulcontent.com/rss/6618?someKey=someValue", parsed) - } - - @Test - fun testSubscribeUrlWithoutParamsHttps() { - val intent = Intent(Intent.ACTION_VIEW) - val url = "pktc://subscribehttps/mypodcast.com/rss/123" - intent.data = Uri.parse(url) - - val parsed = IntentUtil.getPodloveUrl(intent) - assertEquals("https://mypodcast.com/rss/123", parsed) - } } diff --git a/app/src/main/java/au/com/shiftyjelly/pocketcasts/ui/MainActivity.kt b/app/src/main/java/au/com/shiftyjelly/pocketcasts/ui/MainActivity.kt index a5b6de036a..dd55794f5e 100644 --- a/app/src/main/java/au/com/shiftyjelly/pocketcasts/ui/MainActivity.kt +++ b/app/src/main/java/au/com/shiftyjelly/pocketcasts/ui/MainActivity.kt @@ -61,6 +61,7 @@ import au.com.shiftyjelly.pocketcasts.deeplink.ShowDiscoverDeepLink import au.com.shiftyjelly.pocketcasts.deeplink.ShowEpisodeDeepLink import au.com.shiftyjelly.pocketcasts.deeplink.ShowFilterDeepLink import au.com.shiftyjelly.pocketcasts.deeplink.ShowPodcastDeepLink +import au.com.shiftyjelly.pocketcasts.deeplink.ShowPodcastFromUrlDeepLink import au.com.shiftyjelly.pocketcasts.deeplink.ShowPodcastsDeepLink import au.com.shiftyjelly.pocketcasts.deeplink.ShowUpNextDeepLink import au.com.shiftyjelly.pocketcasts.discover.view.DiscoverFragment @@ -1295,12 +1296,12 @@ class MainActivity : is PocketCastsWebsiteDeepLink -> { // Do nothing when the user goes to https://pocketcasts.com/get it should either open the play store or the user's app } + is ShowPodcastFromUrlDeepLink -> { + openPodcastUrl(deepLink.url) + } } } else if (action == Intent.ACTION_VIEW) { - if (IntentUtil.isPodloveUrl(intent)) { - openPodcastUrl(IntentUtil.getPodloveUrl(intent)) - return - } else if (IntentUtil.isSonosAppLinkUrl(intent)) { + if (IntentUtil.isSonosAppLinkUrl(intent)) { startActivityForResult( SonosAppLinkActivity.buildIntent(intent, this), SonosAppLinkActivity.SONOS_APP_ACTIVITY_RESULT, diff --git a/modules/services/deeplink/src/main/kotlin/au/com/shiftyjelly/pocketcasts/deeplink/DeepLink.kt b/modules/services/deeplink/src/main/kotlin/au/com/shiftyjelly/pocketcasts/deeplink/DeepLink.kt index ce74e98fe1..250b68cac2 100644 --- a/modules/services/deeplink/src/main/kotlin/au/com/shiftyjelly/pocketcasts/deeplink/DeepLink.kt +++ b/modules/services/deeplink/src/main/kotlin/au/com/shiftyjelly/pocketcasts/deeplink/DeepLink.kt @@ -134,6 +134,10 @@ data class ShowFilterDeepLink( data object PocketCastsWebsiteDeepLink : DeepLink +data class ShowPodcastFromUrlDeepLink( + val url: String, +) : DeepLink + private val Context.launcherIntent get() = requireNotNull(packageManager.getLaunchIntentForPackage(packageName)) { "Missing launcher intent for $packageName" } diff --git a/modules/services/deeplink/src/main/kotlin/au/com/shiftyjelly/pocketcasts/deeplink/DeepLinkFactory.kt b/modules/services/deeplink/src/main/kotlin/au/com/shiftyjelly/pocketcasts/deeplink/DeepLinkFactory.kt index ce9b10f3e4..7763bdb484 100644 --- a/modules/services/deeplink/src/main/kotlin/au/com/shiftyjelly/pocketcasts/deeplink/DeepLinkFactory.kt +++ b/modules/services/deeplink/src/main/kotlin/au/com/shiftyjelly/pocketcasts/deeplink/DeepLinkFactory.kt @@ -31,6 +31,7 @@ class DeepLinkFactory( ShowEpisodeAdapter(), ShowPageAdapter(), PocketCastsWebsiteAdapter(webBaseHost), + PodloveAdapter(), ) fun create(intent: Intent): DeepLink? { @@ -157,3 +158,21 @@ private class PocketCastsWebsiteAdapter( null } } + +private class PodloveAdapter : DeepLinkAdapter { + override fun create(intent: Intent): DeepLink? { + val uriData = intent.dataString.orEmpty() + val groupValues = PODLOVE_REGEX.matchEntire(uriData)?.groupValues + + return if (intent.action == ACTION_VIEW && groupValues != null) { + val scheme = if (groupValues[1] == "subscribe") "http" else "https" + ShowPodcastFromUrlDeepLink("$scheme://${groupValues[2]}") + } else { + null + } + } + + private companion object { + private val PODLOVE_REGEX = """^pktc://(subscribe|subscribehttps)/(.{3,})$""".toRegex() + } +} diff --git a/modules/services/views/src/main/java/au/com/shiftyjelly/pocketcasts/views/helper/IntentUtil.kt b/modules/services/views/src/main/java/au/com/shiftyjelly/pocketcasts/views/helper/IntentUtil.kt index f3f23e7740..a99defb785 100644 --- a/modules/services/views/src/main/java/au/com/shiftyjelly/pocketcasts/views/helper/IntentUtil.kt +++ b/modules/services/views/src/main/java/au/com/shiftyjelly/pocketcasts/views/helper/IntentUtil.kt @@ -18,16 +18,6 @@ import timber.log.Timber object IntentUtil { - fun isPodloveUrl(intent: Intent): Boolean { - val scheme = intent.scheme - if (scheme == null || scheme != "pktc" || intent.data == null || intent.data?.host == null) { - return false - } - - val host = intent.data?.host - return host == "subscribe" || host == "subscribehttps" - } - fun isSonosAppLinkUrl(intent: Intent): Boolean { val scheme = intent.scheme if (scheme == null || scheme != "pktc" || intent.data == null || intent.data?.host == null) { @@ -38,20 +28,6 @@ object IntentUtil { return host == "applink" } - fun getPodloveUrl(intent: Intent): String? { - val uri = intent.data ?: return null - var path = uri.path ?: return null - if (path.startsWith("/")) { - path = path.replaceFirst(Matcher.quoteReplacement("/").toRegex(), "") - } - if (path.length < 3) { - return null - } - val host = uri.host - val params = uri.encodedQuery - return (if (host == "subscribehttps") "https" else "http") + "://" + path + if (!params.isNullOrEmpty()) "?${uri.encodedQuery}" else "" - } - fun isShareLink(intent: Intent): Boolean { val scheme = intent.scheme return scheme != null && scheme == "pktc" && intent.data != null && intent.data?.path != null