Skip to content

Commit ec5d4b5

Browse files
authored
Move getHeaders checks to io (#7225)
Task/Issue URL: https://app.asana.com/1/137249556945/project/488551667048375/task/1212150079356362?focus=true ### Description Make methods in `CustomHeadersProvider` suspend, and ensure RC flag checks are done in io. Similarly, move some dataStore queries to io as well: * Note, this is a LHF approach, and therefore I haven't migrated anything that's also used synchronously from other parts of the code ### Steps to test this PR - [x] [E2E Maestro tests](https://github.com/duckduckgo/Android/actions/runs/19707333960) passed _Feature 1_ - [ ] - [ ] ### UI changes | Before | After | | ------ | ----- | !(Upload before screenshot)|(Upload after screenshot)|
1 parent c7859a7 commit ec5d4b5

File tree

21 files changed

+132
-72
lines changed

21 files changed

+132
-72
lines changed

app/src/androidTest/java/com/duckduckgo/app/browser/BrowserTabViewModelTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8160,7 +8160,7 @@ class BrowserTabViewModelTest {
81608160
class FakeCustomHeadersProvider(
81618161
var headers: Map<String, String>,
81628162
) : CustomHeadersProvider {
8163-
override fun getCustomHeaders(url: String): Map<String, String> = headers
8163+
override suspend fun getCustomHeaders(url: String): Map<String, String> = headers
81648164
}
81658165

81668166
class FakeContentScopeScriptsSubscriptionEventPlugin(

app/src/androidTest/java/com/duckduckgo/app/browser/BrowserWebViewClientTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ class BrowserWebViewClientTest {
167167
mockAndroidBrowserConfigFeature,
168168
mockFeaturesHeaderProvider,
169169
mock(),
170+
coroutinesTestRule.testDispatcherProvider,
170171
)
171172
private val mockDuckChat: DuckChat = mock()
172173

app/src/androidTest/java/com/duckduckgo/app/browser/WebViewRequestInterceptorTest.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,12 @@ class WebViewRequestInterceptorTest {
109109

110110
@UiThreadTest
111111
@Before
112-
fun setup() {
112+
fun setup() = runTest {
113113
configureUserAgent()
114114
configureStack()
115+
whenever(mockGpc.canUrlAddHeaders(anyString(), anyMap<String, String>())).thenReturn(false)
116+
whenever(mockRequest.requestHeaders).thenReturn(mutableMapOf())
117+
whenever(mockGpc.getHeaders(anyString())).thenReturn(mapOf())
115118

116119
testee = WebViewRequestInterceptor(
117120
trackerDetector = mockTrackerDetector,

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,7 +1194,9 @@ class BrowserTabViewModel @Inject constructor(
11941194
}
11951195

11961196
site?.nextUrl = urlToNavigate
1197-
command.value = NavigationCommand.Navigate(urlToNavigate, getUrlHeaders(urlToNavigate))
1197+
viewModelScope.launch {
1198+
command.value = NavigationCommand.Navigate(urlToNavigate, getUrlHeaders(urlToNavigate))
1199+
}
11981200
}
11991201
}
12001202

@@ -1219,7 +1221,7 @@ class BrowserTabViewModel @Inject constructor(
12191221
currentAutoCompleteViewState().copy(showSuggestions = false, showFavorites = false, searchResults = AutoCompleteResult("", emptyList()))
12201222
}
12211223

1222-
private fun getUrlHeaders(url: String?): Map<String, String> = url?.let { customHeadersProvider.getCustomHeaders(it) } ?: emptyMap()
1224+
private suspend fun getUrlHeaders(url: String?): Map<String, String> = url?.let { customHeadersProvider.getCustomHeaders(it) } ?: emptyMap()
12231225

12241226
private fun extractVerticalParameter(currentUrl: String?): String? {
12251227
val url = currentUrl ?: return null
@@ -2795,7 +2797,9 @@ class BrowserTabViewModel @Inject constructor(
27952797
if (desktopSiteRequested && uri.isMobileSite) {
27962798
val desktopUrl = uri.toDesktopUri().toString()
27972799
logcat(INFO) { "Original URL $url - attempting $desktopUrl with desktop site UA string" }
2798-
command.value = NavigationCommand.Navigate(desktopUrl, getUrlHeaders(desktopUrl))
2800+
viewModelScope.launch {
2801+
command.value = NavigationCommand.Navigate(desktopUrl, getUrlHeaders(desktopUrl))
2802+
}
27992803
} else {
28002804
command.value = NavigationCommand.Refresh
28012805
}
@@ -3165,7 +3169,9 @@ class BrowserTabViewModel @Inject constructor(
31653169

31663170
fun nonHttpAppLinkClicked(appLink: NonHttpAppLink) {
31673171
if (nonHttpAppLinkChecker.isPermitted(appLink.intent)) {
3168-
command.value = HandleNonHttpAppLink(appLink, getUrlHeaders(appLink.fallbackUrl))
3172+
viewModelScope.launch {
3173+
command.value = HandleNonHttpAppLink(appLink, getUrlHeaders(appLink.fallbackUrl))
3174+
}
31693175
}
31703176
}
31713177

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,13 +363,13 @@ class WebViewRequestInterceptor(
363363
return WebResourceResponse(null, null, null)
364364
}
365365

366-
private fun getHeaders(request: WebResourceRequest): Map<String, String> {
366+
private suspend fun getHeaders(request: WebResourceRequest): Map<String, String> {
367367
return request.requestHeaders.apply {
368368
putAll(gpc.getHeaders(request.url.toString()))
369369
}
370370
}
371371

372-
private fun shouldAddGcpHeaders(request: WebResourceRequest): Boolean {
372+
private suspend fun shouldAddGcpHeaders(request: WebResourceRequest): Boolean {
373373
val existingHeaders = request.requestHeaders
374374
return (request.isForMainFrame && request.method == "GET" && gpc.canUrlAddHeaders(request.url.toString(), existingHeaders))
375375
}

app/src/main/java/com/duckduckgo/app/browser/trafficquality/AndroidFeaturesHeader.kt

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ import com.duckduckgo.app.browser.trafficquality.Result.Allowed
2121
import com.duckduckgo.app.browser.trafficquality.Result.NotAllowed
2222
import com.duckduckgo.app.browser.trafficquality.remote.AndroidFeaturesHeaderProvider
2323
import com.duckduckgo.app.pixels.remoteconfig.AndroidBrowserConfigFeature
24+
import com.duckduckgo.common.utils.DispatcherProvider
2425
import com.duckduckgo.common.utils.plugins.headers.CustomHeadersProvider.CustomHeadersPlugin
2526
import com.duckduckgo.di.scopes.AppScope
2627
import com.squareup.anvil.annotations.ContributesMultibinding
28+
import kotlinx.coroutines.withContext
2729
import javax.inject.Inject
2830

2931
@ContributesMultibinding(scope = AppScope::class)
@@ -33,9 +35,10 @@ class AndroidFeaturesHeaderPlugin @Inject constructor(
3335
private val androidBrowserConfigFeature: AndroidBrowserConfigFeature,
3436
private val androidFeaturesHeaderProvider: AndroidFeaturesHeaderProvider,
3537
private val appVersionProvider: AppVersionHeaderProvider,
38+
private val dispatchers: DispatcherProvider,
3639
) : CustomHeadersPlugin {
3740

38-
override fun getHeaders(url: String): Map<String, String> {
41+
override suspend fun getHeaders(url: String): Map<String, String> {
3942
if (isFeatureEnabled() && duckDuckGoUrlDetector.isDuckDuckGoQueryUrl(url)) {
4043
return when (val result = customHeaderAllowedChecker.isAllowed()) {
4144
is Allowed -> {
@@ -58,9 +61,11 @@ class AndroidFeaturesHeaderPlugin @Inject constructor(
5861
}
5962
}
6063

61-
private fun isFeatureEnabled(): Boolean {
62-
return androidBrowserConfigFeature.self().isEnabled() &&
63-
androidBrowserConfigFeature.featuresRequestHeader().isEnabled()
64+
private suspend fun isFeatureEnabled(): Boolean {
65+
return withContext(dispatchers.io()) {
66+
androidBrowserConfigFeature.self().isEnabled() &&
67+
androidBrowserConfigFeature.featuresRequestHeader().isEnabled()
68+
}
6469
}
6570

6671
companion object {

app/src/main/java/com/duckduckgo/app/browser/trafficquality/CustomHeaderAllowedChecker.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import java.time.temporal.ChronoUnit
2929
import javax.inject.Inject
3030

3131
interface CustomHeaderAllowedChecker {
32-
fun isAllowed(): Result<TrafficQualityAppVersion>
32+
suspend fun isAllowed(): Result<TrafficQualityAppVersion>
3333
}
3434

3535
sealed class Result<out R> {
@@ -42,7 +42,7 @@ class RealCustomHeaderGracePeriodChecker @Inject constructor(
4242
private val appBuildConfig: AppBuildConfig,
4343
private val featuresRequestHeaderStore: FeaturesRequestHeaderStore,
4444
) : CustomHeaderAllowedChecker {
45-
override fun isAllowed(): Result<TrafficQualityAppVersion> {
45+
override suspend fun isAllowed(): Result<TrafficQualityAppVersion> {
4646
val config = featuresRequestHeaderStore.getConfig()
4747
val versionConfig = config.find { it.appVersion == appBuildConfig.versionCode }
4848
return if (versionConfig != null) {

app/src/main/java/com/duckduckgo/app/browser/trafficquality/remote/FeaturesRequestHeaderSettingStore.kt

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,16 @@
1717
package com.duckduckgo.app.browser.trafficquality.remote
1818

1919
import com.duckduckgo.app.pixels.remoteconfig.AndroidBrowserConfigFeature
20+
import com.duckduckgo.common.utils.DispatcherProvider
2021
import com.duckduckgo.di.scopes.AppScope
2122
import com.squareup.anvil.annotations.ContributesBinding
2223
import com.squareup.moshi.JsonAdapter
2324
import com.squareup.moshi.Moshi
25+
import kotlinx.coroutines.withContext
2426
import javax.inject.Inject
2527

2628
interface FeaturesRequestHeaderStore {
27-
fun getConfig(): List<TrafficQualityAppVersion>
29+
suspend fun getConfig(): List<TrafficQualityAppVersion>
2830
}
2931

3032
data class TrafficQualitySettingsJson(
@@ -49,19 +51,22 @@ data class TrafficQualityAppVersionFeatures(
4951
class FeaturesRequestHeaderSettingStore @Inject constructor(
5052
private val androidBrowserConfigFeature: AndroidBrowserConfigFeature,
5153
private val moshi: Moshi,
54+
private val dispatcherProvider: DispatcherProvider,
5255
) : FeaturesRequestHeaderStore {
5356

5457
private val jsonAdapter: JsonAdapter<TrafficQualitySettingsJson> by lazy {
5558
moshi.adapter(TrafficQualitySettingsJson::class.java)
5659
}
5760

58-
override fun getConfig(): List<TrafficQualityAppVersion> {
59-
val config = androidBrowserConfigFeature.featuresRequestHeader().getSettings()?.let {
60-
runCatching {
61-
val configJson = jsonAdapter.fromJson(it)
62-
configJson?.versions
63-
}.getOrDefault(emptyList())
64-
} ?: emptyList()
65-
return config
61+
override suspend fun getConfig(): List<TrafficQualityAppVersion> {
62+
return withContext(dispatcherProvider.io()) {
63+
val config = androidBrowserConfigFeature.featuresRequestHeader().getSettings()?.let {
64+
runCatching {
65+
val configJson = jsonAdapter.fromJson(it)
66+
configJson?.versions
67+
}.getOrDefault(emptyList())
68+
} ?: emptyList()
69+
config
70+
}
6671
}
6772
}

app/src/main/java/com/duckduckgo/app/globalprivacycontrol/ui/GlobalPrivacyControlViewModel.kt

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import androidx.annotation.StringRes
2020
import androidx.lifecycle.LiveData
2121
import androidx.lifecycle.MutableLiveData
2222
import androidx.lifecycle.ViewModel
23+
import androidx.lifecycle.viewModelScope
2324
import com.duckduckgo.anvil.annotations.ContributesViewModel
2425
import com.duckduckgo.app.browser.R
2526
import com.duckduckgo.app.pixels.AppPixelName.*
@@ -29,6 +30,7 @@ import com.duckduckgo.di.scopes.ActivityScope
2930
import com.duckduckgo.feature.toggles.api.FeatureToggle
3031
import com.duckduckgo.privacy.config.api.Gpc
3132
import com.duckduckgo.privacy.config.api.PrivacyFeatureName
33+
import kotlinx.coroutines.launch
3234
import javax.inject.Inject
3335

3436
@ContributesViewModel(ActivityScope::class)
@@ -55,10 +57,13 @@ class GlobalPrivacyControlViewModel @Inject constructor(
5557
val command: SingleLiveEvent<Command> = SingleLiveEvent()
5658

5759
init {
58-
_viewState.value = ViewState(
59-
globalPrivacyControlEnabled = gpc.isEnabled(),
60-
globalPrivacyControlFeatureEnabled = featureToggle.isFeatureEnabled(PrivacyFeatureName.GpcFeatureName.value, true),
61-
)
60+
viewModelScope.launch {
61+
_viewState.value = ViewState(
62+
globalPrivacyControlEnabled = gpc.isEnabled(),
63+
globalPrivacyControlFeatureEnabled = featureToggle.isFeatureEnabled(PrivacyFeatureName.GpcFeatureName.value, true),
64+
)
65+
}
66+
6267
pixel.fire(SETTINGS_DO_NOT_SELL_SHOWN)
6368
}
6469

app/src/test/java/com/duckduckgo/app/brokensite/api/BrokenSiteSubmitterTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ class BrokenSiteSubmitterTest {
119119
private lateinit var testee: BrokenSiteSubmitter
120120

121121
@Before
122-
fun before() {
122+
fun before() = runTest {
123123
whenever(mockAppBuildConfig.deviceLocale).thenReturn(Locale.ENGLISH)
124124
whenever(mockAppBuildConfig.sdkInt).thenReturn(1)
125125
whenever(mockAppBuildConfig.manufacturer).thenReturn("manufacturer")

0 commit comments

Comments
 (0)