Skip to content

Commit efadb74

Browse files
authored
Cache assets path loading (#5142)
Task/Issue URL: https://app.asana.com/0/1202552961248957/1208539373099857/f ### Description ### Steps to test this PR _Feature 1_ - Smoke test Duck Player and navigation ### UI changes | Before | After | | ------ | ----- | !(Upload before screenshot)|(Upload after screenshot)|
1 parent 57356a3 commit efadb74

File tree

6 files changed

+45
-19
lines changed

6 files changed

+45
-19
lines changed

app/src/main/java/com/duckduckgo/app/browser/SpecialUrlDetector.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import android.net.Uri
2626
import androidx.core.net.toUri
2727
import com.duckduckgo.app.browser.SpecialUrlDetector.UrlType
2828
import com.duckduckgo.app.browser.applinks.ExternalAppIntentFlagsFeature
29+
import com.duckduckgo.common.utils.DispatcherProvider
2930
import com.duckduckgo.duckplayer.api.DuckPlayer
3031
import com.duckduckgo.privacy.config.api.AmpLinkType
3132
import com.duckduckgo.privacy.config.api.AmpLinks
@@ -45,6 +46,7 @@ class SpecialUrlDetectorImpl(
4546
private val externalAppIntentFlagsFeature: ExternalAppIntentFlagsFeature,
4647
private val duckPlayer: DuckPlayer,
4748
private val scope: CoroutineScope,
49+
private val dispatcherProvider: DispatcherProvider,
4850
) : SpecialUrlDetector {
4951

5052
override fun determineType(initiatingUrl: String?, uri: Uri): UrlType {
@@ -90,9 +92,9 @@ class SpecialUrlDetectorImpl(
9092

9193
val uri = uriString.toUri()
9294

93-
val willNavigateToDuckPlayerDeferred = scope.async { duckPlayer.willNavigateToDuckPlayer(uri) }
95+
val willNavigateToDuckPlayerDeferred = scope.async(dispatcherProvider.io()) { duckPlayer.willNavigateToDuckPlayer(uri) }
9496

95-
val willNavigateToDuckPlayer = runBlocking { willNavigateToDuckPlayerDeferred.await() }
97+
val willNavigateToDuckPlayer = runBlocking(dispatcherProvider.io()) { willNavigateToDuckPlayerDeferred.await() }
9698

9799
if (willNavigateToDuckPlayer) {
98100
return UrlType.ShouldLaunchDuckPlayerLink(url = uri)

app/src/main/java/com/duckduckgo/app/browser/di/BrowserModule.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ class BrowserModule {
189189
externalAppIntentFlagsFeature: ExternalAppIntentFlagsFeature,
190190
duckPlayer: DuckPlayer,
191191
@AppCoroutineScope appCoroutineScope: CoroutineScope,
192+
dispatcherProvider: DispatcherProvider,
192193
): SpecialUrlDetector = SpecialUrlDetectorImpl(
193194
packageManager,
194195
ampLinks,
@@ -197,6 +198,7 @@ class BrowserModule {
197198
externalAppIntentFlagsFeature,
198199
duckPlayer,
199200
appCoroutineScope,
201+
dispatcherProvider = dispatcherProvider,
200202
)
201203

202204
@Provides

app/src/test/java/com/duckduckgo/app/browser/SpecialUrlDetectorImplTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ class SpecialUrlDetectorImplTest {
8080
externalAppIntentFlagsFeature = externalAppIntentFlagsFeature,
8181
duckPlayer = mockDuckPlayer,
8282
scope = coroutineRule.testScope,
83+
dispatcherProvider = coroutineRule.testDispatcherProvider,
8384
)
8485
whenever(mockPackageManager.queryIntentActivities(any(), anyInt())).thenReturn(emptyList())
8586
whenever(mockDuckPlayer.willNavigateToDuckPlayer(any())).thenReturn(false)

duckplayer/duckplayer-impl/src/main/java/com/duckduckgo/duckplayer/impl/DuckPlayerLocalFilesPath.kt

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,39 @@
1717
package com.duckduckgo.duckplayer.impl
1818

1919
import android.content.res.AssetManager
20+
import com.duckduckgo.app.di.AppCoroutineScope
21+
import com.duckduckgo.common.utils.DispatcherProvider
2022
import com.duckduckgo.di.scopes.AppScope
2123
import com.squareup.anvil.annotations.ContributesBinding
24+
import dagger.SingleInstanceIn
2225
import java.io.IOException
2326
import javax.inject.Inject
27+
import kotlinx.coroutines.CoroutineScope
28+
import kotlinx.coroutines.Deferred
29+
import kotlinx.coroutines.async
30+
import kotlinx.coroutines.withContext
2431

2532
interface DuckPlayerLocalFilesPath {
26-
val assetsPath: List<String>
33+
suspend fun assetsPath(): List<String>
2734
}
2835

2936
@ContributesBinding(AppScope::class)
30-
class RealDuckPlayerLocalFilesPath @Inject constructor(private val assetManager: AssetManager) : DuckPlayerLocalFilesPath {
37+
@SingleInstanceIn(AppScope::class)
38+
class RealDuckPlayerLocalFilesPath @Inject constructor(
39+
private val assetManager: AssetManager,
40+
@AppCoroutineScope appCoroutineScope: CoroutineScope,
41+
private val dispatcherProvider: DispatcherProvider,
42+
) : DuckPlayerLocalFilesPath {
3143

32-
override val assetsPath: List<String> = getAllAssetFilePaths("duckplayer")
44+
private val assetsPathDeferred: Deferred<List<String>> = appCoroutineScope.async(dispatcherProvider.io()) {
45+
getAllAssetFilePaths("duckplayer")
46+
}
47+
48+
override suspend fun assetsPath(): List<String> {
49+
return withContext(dispatcherProvider.io()) {
50+
assetsPathDeferred.await()
51+
}
52+
}
3353

3454
private fun getAllAssetFilePaths(directory: String): List<String> {
3555
val filePaths = mutableListOf<String>()

duckplayer/duckplayer-impl/src/main/java/com/duckduckgo/duckplayer/impl/RealDuckPlayer.kt

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ class RealDuckPlayer @Inject constructor(
223223
}
224224

225225
override suspend fun isSimulatedYoutubeNoCookie(uri: Uri): Boolean {
226-
val validPaths = duckPlayerLocalFilesPath.assetsPath
226+
val validPaths = duckPlayerLocalFilesPath.assetsPath()
227227
val embedUrl = duckPlayerFeatureRepository.getYouTubeEmbedUrl()
228228
return (
229229
uri.host?.removePrefix("www.") ==
@@ -353,15 +353,8 @@ class RealDuckPlayer @Inject constructor(
353353
}
354354

355355
private suspend fun doesYoutubeUrlComeFromDuckPlayer(url: Uri, request: WebResourceRequest? = null): Boolean {
356-
val referer = request?.requestHeaders?.keys?.firstOrNull { it in duckPlayerFeatureRepository.getYouTubeReferrerHeaders() }
357-
?.let { url.getQueryParameter(it) }
358-
val previousUrl = duckPlayerFeatureRepository.getYouTubeReferrerQueryParams()
359-
.firstOrNull { url.getQueryParameter(it) != null }
360-
?.let { url.getQueryParameter(it) }
361-
362356
val videoIdQueryParam = duckPlayerFeatureRepository.getVideoIDQueryParam()
363357
val requestedVideoId = url.getQueryParameter(videoIdQueryParam)
364-
365358
val isSimulated: suspend (String?) -> Boolean = { uri ->
366359
uri?.let { isSimulatedYoutubeNoCookie(it.toUri()) } == true
367360
}
@@ -370,8 +363,16 @@ class RealDuckPlayer @Inject constructor(
370363
uri?.toUri()?.getQueryParameter(DUCK_PLAYER_VIDEO_ID_QUERY_PARAM) == requestedVideoId
371364
}
372365

373-
return isSimulated(referer) && isMatchingVideoId(referer) ||
374-
isSimulated(previousUrl) && isMatchingVideoId(previousUrl)
366+
val referer = request?.requestHeaders?.keys?.firstOrNull { it in duckPlayerFeatureRepository.getYouTubeReferrerHeaders() }
367+
?.let { url.getQueryParameter(it) }
368+
369+
if (isSimulated(referer) && isMatchingVideoId(referer)) return true
370+
371+
val previousUrl = duckPlayerFeatureRepository.getYouTubeReferrerQueryParams()
372+
.firstOrNull { url.getQueryParameter(it) != null }
373+
?.let { url.getQueryParameter(it) }
374+
375+
return isSimulated(previousUrl) && isMatchingVideoId(previousUrl)
375376
}
376377

377378
private suspend fun processDuckPlayerUri(
@@ -424,8 +425,8 @@ class RealDuckPlayer @Inject constructor(
424425
): Boolean {
425426
return (
426427
isFeatureEnabled &&
427-
isYoutubeWatchUrl(destinationUrl) &&
428428
getUserPreferences().privatePlayerMode == Enabled &&
429+
isYoutubeWatchUrl(destinationUrl) &&
429430
!(shouldForceYTNavigation || doesYoutubeUrlComeFromDuckPlayer(destinationUrl))
430431
)
431432
}

duckplayer/duckplayer-impl/src/test/kotlin/com/duckduckgo/duckplayer/impl/RealDuckPlayerTest.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ class RealDuckPlayerTest {
370370

371371
@Test
372372
fun whenUrHostIsEmbedAndFileIsAvailableLocally_isSimulatedYoutubeNoCookieReturnsTrue() = runTest {
373-
whenever(mockDuckPlayerLocalFilesPath.assetsPath).thenReturn(listOf("js/duckplayer.js"))
373+
whenever(mockDuckPlayerLocalFilesPath.assetsPath()).thenReturn(listOf("js/duckplayer.js"))
374374
val uri = "https://www.youtube-nocookie.com/js/duckplayer.js".toUri()
375375

376376
val result = testee.isSimulatedYoutubeNoCookie(uri)
@@ -380,7 +380,7 @@ class RealDuckPlayerTest {
380380

381381
@Test
382382
fun whenUrHostIsEmbedAndFileIsNotAvailableLocally_isSimulatedYoutubeNoCookieReturnsFalse() = runTest {
383-
whenever(mockDuckPlayerLocalFilesPath.assetsPath).thenReturn(listOf("css/duckplayer.css"))
383+
whenever(mockDuckPlayerLocalFilesPath.assetsPath()).thenReturn(listOf("css/duckplayer.css"))
384384
val uri = "https://www.youtube-nocookie.com/js/duckplayer.js".toUri()
385385

386386
val result = testee.isSimulatedYoutubeNoCookie(uri)
@@ -390,7 +390,7 @@ class RealDuckPlayerTest {
390390

391391
@Test
392392
fun whenUrHostIsEmbedAndPathContainsEmbed_isSimulatedYoutubeNoCookieReturnsFalse() = runTest {
393-
whenever(mockDuckPlayerLocalFilesPath.assetsPath).thenReturn(listOf())
393+
whenever(mockDuckPlayerLocalFilesPath.assetsPath()).thenReturn(listOf())
394394
val uri = "https://www.youtube-nocookie.com/embed/js/duckplayer.js".toUri()
395395

396396
val result = testee.isSimulatedYoutubeNoCookie(uri)

0 commit comments

Comments
 (0)