diff --git a/app/build.gradle b/app/build.gradle index 765ae2be7d82..36003ecd0e26 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -110,14 +110,13 @@ ext { legacySupport = "1.0.0" coreTesting = "2.1.0" testRunner = "1.3.0" - coroutines = "1.3.5" - retrofitCoroutinesAdapter = "0.9.2" + coroutines = "1.4.2" webkit = "1.3.0" referrerLibrary = "1.1.2" junit = "4.12" dagger = "2.27" - retrofit = "2.8.1" + retrofit = "2.9.0" ankoVersion = "0.10.4" glide = "4.11.0" lottieVersion = "3.4.0" @@ -141,7 +140,12 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines" - androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines" + androidTestImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines") { + // https://github.com/Kotlin/kotlinx.coroutines/issues/2023 + // conflicts with mockito due to direct inclusion of byte buddy + exclude group: "org.jetbrains.kotlinx", module: "kotlinx-coroutines-debug" + } implementation "androidx.appcompat:appcompat:$androidX" implementation "com.google.android.material:material:$materialDesign" @@ -154,7 +158,6 @@ dependencies { implementation "com.squareup.retrofit2:converter-moshi:$retrofit" implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofit" implementation "com.squareup.retrofit2:converter-scalars:$retrofit" - implementation "com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:$retrofitCoroutinesAdapter" implementation "io.reactivex.rxjava2:rxjava:$rxJava" implementation "io.reactivex.rxjava2:rxandroid:$rxAndroid" implementation "com.jakewharton.timber:timber:$timber" diff --git a/app/src/androidTest/java/com/duckduckgo/app/cta/ui/CtaViewModelTest.kt b/app/src/androidTest/java/com/duckduckgo/app/cta/ui/CtaViewModelTest.kt index d876380bf387..ed1b2fae75ea 100644 --- a/app/src/androidTest/java/com/duckduckgo/app/cta/ui/CtaViewModelTest.kt +++ b/app/src/androidTest/java/com/duckduckgo/app/cta/ui/CtaViewModelTest.kt @@ -616,14 +616,13 @@ class CtaViewModelTest { givenOnboardingActive() db.tabsDao().insertTab(TabEntity(tabId = "0", position = 0)) db.dismissedCtaDao().insert(DismissedCta(CtaId.DAX_DIALOG_TRACKERS_FOUND)) + db.tabsDao().insertTab(TabEntity(tabId = "1", position = 1)) + val collector = launch { testee.showFireButtonPulseAnimation.collect { - values.add(it) + assertFalse(it) } } - db.tabsDao().insertTab(TabEntity(tabId = "1", position = 1)) - - assertEquals(listOf(true, false), values) collector.cancel() } diff --git a/app/src/androidTest/java/com/duckduckgo/app/launch/LaunchViewModelTest.kt b/app/src/androidTest/java/com/duckduckgo/app/launch/LaunchViewModelTest.kt index c2b711234848..b779c07e89cb 100644 --- a/app/src/androidTest/java/com/duckduckgo/app/launch/LaunchViewModelTest.kt +++ b/app/src/androidTest/java/com/duckduckgo/app/launch/LaunchViewModelTest.kt @@ -23,13 +23,11 @@ import com.duckduckgo.app.launch.LaunchViewModel.Command.Home import com.duckduckgo.app.launch.LaunchViewModel.Command.Onboarding import com.duckduckgo.app.onboarding.store.AppStage import com.duckduckgo.app.onboarding.store.UserStageStore -import com.duckduckgo.app.referral.AppInstallationReferrerStateListener -import com.duckduckgo.app.referral.ParsedReferrerResult +import com.duckduckgo.app.referral.StubAppReferrerFoundStateListener import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.whenever import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.delay import kotlinx.coroutines.test.runBlockingTest import org.junit.After import org.junit.Rule @@ -115,15 +113,4 @@ class LaunchViewModelTest { testee.determineViewToShow() verify(mockCommandObserver).onChanged(any(Home::class.java)) } - - class StubAppReferrerFoundStateListener(private val referrer: String, private val mockDelayMs: Long = 0) : AppInstallationReferrerStateListener { - override suspend fun waitForReferrerCode(): ParsedReferrerResult { - if (mockDelayMs > 0) delay(mockDelayMs) - - return ParsedReferrerResult.CampaignReferrerFound(referrer) - } - - override fun initialiseReferralRetrieval() { - } - } } diff --git a/app/src/androidTest/java/com/duckduckgo/app/referral/StubAppReferrerFoundStateListener.kt b/app/src/androidTest/java/com/duckduckgo/app/referral/StubAppReferrerFoundStateListener.kt new file mode 100644 index 000000000000..dc7dc804e4ae --- /dev/null +++ b/app/src/androidTest/java/com/duckduckgo/app/referral/StubAppReferrerFoundStateListener.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2021 DuckDuckGo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.duckduckgo.app.referral + +import kotlinx.coroutines.delay + +class StubAppReferrerFoundStateListener(private val referrer: String, private val mockDelayMs: Long = 0) : AppInstallationReferrerStateListener { + override suspend fun waitForReferrerCode(): ParsedReferrerResult { + if (mockDelayMs > 0) delay(mockDelayMs) + + return ParsedReferrerResult.CampaignReferrerFound(referrer) + } + + override fun initialiseReferralRetrieval() { + } +} diff --git a/app/src/androidTest/java/com/duckduckgo/app/statistics/AtbInitializerTest.kt b/app/src/androidTest/java/com/duckduckgo/app/statistics/AtbInitializerTest.kt index 9f4155bb565c..188a7cd3f3dc 100644 --- a/app/src/androidTest/java/com/duckduckgo/app/statistics/AtbInitializerTest.kt +++ b/app/src/androidTest/java/com/duckduckgo/app/statistics/AtbInitializerTest.kt @@ -17,18 +17,15 @@ package com.duckduckgo.app.statistics import com.duckduckgo.app.referral.AppInstallationReferrerStateListener -import com.duckduckgo.app.referral.ParsedReferrerResult +import com.duckduckgo.app.referral.StubAppReferrerFoundStateListener import com.duckduckgo.app.statistics.api.StatisticsUpdater import com.duckduckgo.app.statistics.store.StatisticsDataStore import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.whenever import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.delay import kotlinx.coroutines.test.runBlockingTest -import org.junit.Before import org.junit.Test -import org.mockito.stubbing.Answer @ExperimentalCoroutinesApi class AtbInitializerTest { @@ -37,17 +34,13 @@ class AtbInitializerTest { private val statisticsDataStore: StatisticsDataStore = mock() private val statisticsUpdater: StatisticsUpdater = mock() - private val appReferrerStateListener: AppInstallationReferrerStateListener = mock() - - @Before - fun setup() { - testee = AtbInitializer(statisticsDataStore, statisticsUpdater, appReferrerStateListener) - } + private lateinit var appReferrerStateListener: AppInstallationReferrerStateListener @Test fun whenReferrerInformationInstantlyAvailableThenAtbInitialized() = runBlockingTest { whenever(statisticsDataStore.hasInstallationStatistics).thenReturn(false) - whenever(appReferrerStateListener.waitForReferrerCode()).thenAnswer(referrerAnswer(0)) + appReferrerStateListener = StubAppReferrerFoundStateListener(referrer = "xx") + testee = AtbInitializer(statisticsDataStore, statisticsUpdater, appReferrerStateListener) testee.initializeAfterReferrerAvailable() @@ -57,7 +50,8 @@ class AtbInitializerTest { @Test fun whenReferrerInformationQuicklyAvailableThenAtbInitialized() = runBlockingTest { whenever(statisticsDataStore.hasInstallationStatistics).thenReturn(false) - whenever(appReferrerStateListener.waitForReferrerCode()).thenAnswer(referrerAnswer(1000)) + appReferrerStateListener = StubAppReferrerFoundStateListener(referrer = "xx", mockDelayMs = 1000L) + testee = AtbInitializer(statisticsDataStore, statisticsUpdater, appReferrerStateListener) testee.initializeAfterReferrerAvailable() @@ -67,7 +61,8 @@ class AtbInitializerTest { @Test fun whenReferrerInformationTimesOutThenAtbInitialized() = runBlockingTest { whenever(statisticsDataStore.hasInstallationStatistics).thenReturn(false) - whenever(appReferrerStateListener.waitForReferrerCode()).thenAnswer(referrerAnswer(Long.MAX_VALUE)) + appReferrerStateListener = StubAppReferrerFoundStateListener(referrer = "xx", mockDelayMs = Long.MAX_VALUE) + testee = AtbInitializer(statisticsDataStore, statisticsUpdater, appReferrerStateListener) testee.initializeAfterReferrerAvailable() @@ -77,17 +72,14 @@ class AtbInitializerTest { @Test fun whenAlreadyInitializedThenRefreshCalled() = runBlockingTest { configureAlreadyInitialized() + testee = AtbInitializer(statisticsDataStore, statisticsUpdater, appReferrerStateListener) + testee.initializeAfterReferrerAvailable() verify(statisticsUpdater).refreshAppRetentionAtb() } - private suspend fun configureAlreadyInitialized() { + private fun configureAlreadyInitialized() { whenever(statisticsDataStore.hasInstallationStatistics).thenReturn(true) - whenever(appReferrerStateListener.waitForReferrerCode()).thenAnswer(referrerAnswer(0)) - } - - private suspend fun referrerAnswer(delayMs: Long): Answer { - delay(delayMs) - return Answer { ParsedReferrerResult.CampaignReferrerFound("") } + appReferrerStateListener = StubAppReferrerFoundStateListener(referrer = "xx") } } diff --git a/app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt b/app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt index 3ac19b844eab..866691da37de 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt @@ -331,7 +331,6 @@ class BrowserTabViewModel( browserViewState.value = currentBrowserViewState().copy(isFireproofWebsite = isFireproofWebsite()) } - @ExperimentalCoroutinesApi private val fireButtonAnimation = Observer { shouldShowAnimation -> Timber.i("shouldShowAnimation $shouldShowAnimation") if (currentBrowserViewState().fireButton is FireButton.Visible) { @@ -343,7 +342,6 @@ class BrowserTabViewModel( } } - @ExperimentalCoroutinesApi private fun registerAndScheduleDismissAction() { viewModelScope.launch(dispatchers.io()) { val fireButtonHighlightedEvent = userEventsStore.getUserEvent(UserEventKey.FIRE_BUTTON_HIGHLIGHTED) diff --git a/app/src/main/java/com/duckduckgo/app/cta/ui/CtaViewModel.kt b/app/src/main/java/com/duckduckgo/app/cta/ui/CtaViewModel.kt index 4e73a7425846..4a0d15909db0 100644 --- a/app/src/main/java/com/duckduckgo/app/cta/ui/CtaViewModel.kt +++ b/app/src/main/java/com/duckduckgo/app/cta/ui/CtaViewModel.kt @@ -100,7 +100,6 @@ class CtaViewModel @Inject constructor( ) } - @ExperimentalCoroutinesApi suspend fun dismissPulseAnimation() { withContext(dispatchers.io()) { dismissedCtaDao.insert(DismissedCta(CtaId.DAX_FIRE_BUTTON)) @@ -357,7 +356,6 @@ class CtaViewModel @Inject constructor( } } - @ExperimentalCoroutinesApi private fun forceStopFireButtonPulseAnimationFlow() = tabRepository.flowTabs.distinctUntilChanged() .map { tabs -> if (tabs.size >= MAX_TABS_OPEN_FIRE_EDUCATION) return@map true @@ -378,7 +376,6 @@ class CtaViewModel @Inject constructor( } }.shouldShowPulseAnimation() - @ExperimentalCoroutinesApi private fun Flow, Boolean>>.shouldShowPulseAnimation(): Flow { return this.map { (dismissedCtaDao, forceStopAnimation) -> withContext(dispatchers.io()) { diff --git a/app/src/main/java/com/duckduckgo/app/di/NetworkModule.kt b/app/src/main/java/com/duckduckgo/app/di/NetworkModule.kt index f5fdf35d523b..667cb1c074e8 100644 --- a/app/src/main/java/com/duckduckgo/app/di/NetworkModule.kt +++ b/app/src/main/java/com/duckduckgo/app/di/NetworkModule.kt @@ -40,7 +40,6 @@ import com.duckduckgo.app.surrogates.api.ResourceSurrogateListService import com.duckduckgo.app.survey.api.SurveyService import com.duckduckgo.app.trackerdetection.api.TrackerListService import com.duckduckgo.app.trackerdetection.db.TdsMetadataDao -import com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory import com.squareup.moshi.Moshi import dagger.Module import dagger.Provides @@ -91,7 +90,6 @@ class NetworkModule { .client(okHttpClient) .addConverterFactory(ScalarsConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) - .addCallAdapterFactory(CoroutineCallAdapterFactory()) .addConverterFactory(MoshiConverterFactory.create(moshi)) .build() } diff --git a/app/src/main/java/com/duckduckgo/app/feedback/api/FeedbackService.kt b/app/src/main/java/com/duckduckgo/app/feedback/api/FeedbackService.kt index e54ffd5a894a..792896cbe89f 100644 --- a/app/src/main/java/com/duckduckgo/app/feedback/api/FeedbackService.kt +++ b/app/src/main/java/com/duckduckgo/app/feedback/api/FeedbackService.kt @@ -16,7 +16,6 @@ package com.duckduckgo.app.feedback.api -import retrofit2.Call import retrofit2.http.Field import retrofit2.http.FormUrlEncoded import retrofit2.http.POST @@ -25,7 +24,7 @@ interface FeedbackService { @FormUrlEncoded @POST("/feedback.js?type=app-feedback") - fun submitFeedback( + suspend fun submitFeedback( @Field("reason") reason: String = REASON_GENERAL, @Field("rating") rating: String, @Field("category") category: String?, @@ -38,7 +37,7 @@ interface FeedbackService { @Field("manufacturer") manufacturer: String, @Field("model") model: String, @Field("atb") atb: String - ): Call + ) companion object { const val REASON_GENERAL = "general" diff --git a/app/src/main/java/com/duckduckgo/app/feedback/api/FeedbackSubmitter.kt b/app/src/main/java/com/duckduckgo/app/feedback/api/FeedbackSubmitter.kt index e3a04abcb480..22562f6dfd83 100644 --- a/app/src/main/java/com/duckduckgo/app/feedback/api/FeedbackSubmitter.kt +++ b/app/src/main/java/com/duckduckgo/app/feedback/api/FeedbackSubmitter.kt @@ -112,7 +112,7 @@ class FireAndForgetFeedbackSubmitter( pixel.fire(pixelName) } - private fun submitFeedback( + private suspend fun submitFeedback( openEnded: String, rating: String, category: String? = null, @@ -132,7 +132,7 @@ class FireAndForgetFeedbackSubmitter( model = Build.MODEL, api = Build.VERSION.SDK_INT, atb = atbWithVariant() - ).execute() + ) } private fun categoryFromMainReason(mainReason: MainReason): String {