diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/CoronaWarnApplication.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/CoronaWarnApplication.kt index b0c270e62abf366fd24bf2dcf23f00e0d5fe95c9..3767a49eac79fa2be3673d031c3b62f97670501a 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/CoronaWarnApplication.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/CoronaWarnApplication.kt @@ -31,7 +31,6 @@ import de.rki.coronawarnapp.presencetracing.risk.execution.PresenceTracingRiskWo import de.rki.coronawarnapp.presencetracing.storage.retention.TraceLocationDbCleanUpScheduler import de.rki.coronawarnapp.risk.RiskLevelChangeDetector import de.rki.coronawarnapp.risk.execution.ExposureWindowRiskWorkScheduler -import de.rki.coronawarnapp.storage.OnboardingSettings import de.rki.coronawarnapp.submission.auto.AutoSubmission import de.rki.coronawarnapp.task.TaskController import de.rki.coronawarnapp.util.CWADebug @@ -68,7 +67,6 @@ class CoronaWarnApplication : Application(), HasAndroidInjector { @Inject lateinit var deviceTimeHandler: DeviceTimeHandler @Inject lateinit var autoSubmission: AutoSubmission @Inject lateinit var coronaTestRepository: CoronaTestRepository - @Inject lateinit var onboardingSettings: OnboardingSettings @Inject lateinit var autoCheckOut: AutoCheckOut @Inject lateinit var traceLocationDbCleanupScheduler: TraceLocationDbCleanUpScheduler @Inject lateinit var shareTestResultNotificationService: ShareTestResultNotificationService @@ -111,9 +109,8 @@ class CoronaWarnApplication : Application(), HasAndroidInjector { .onEach { isAppInForeground = it } .launchIn(GlobalScope) - if (onboardingSettings.isOnboarded) { - contactDiaryWorkScheduler.schedulePeriodic() - } + Timber.v("Setting up contact diary work scheduler") + contactDiaryWorkScheduler.setup() Timber.v("Setting up deadman notification scheduler") deadmanNotificationScheduler.setup() diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/retention/ContactDiaryWorkScheduler.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/retention/ContactDiaryWorkScheduler.kt index 15bbc81bdc3ca0ba7302bdecb7440d01772035d9..4e6c7aff32e8d9ef65c65dfe92adf309eb350493 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/retention/ContactDiaryWorkScheduler.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/retention/ContactDiaryWorkScheduler.kt @@ -1,22 +1,39 @@ package de.rki.coronawarnapp.contactdiary.retention +import androidx.annotation.VisibleForTesting import androidx.work.ExistingPeriodicWorkPolicy import androidx.work.WorkManager import dagger.Reusable +import de.rki.coronawarnapp.storage.OnboardingSettings +import de.rki.coronawarnapp.util.coroutine.AppScope +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import timber.log.Timber import javax.inject.Inject @Reusable class ContactDiaryWorkScheduler @Inject constructor( - val workManager: WorkManager, - private val workBuilder: ContactDiaryWorkBuilder + @AppScope val appScope: CoroutineScope, + private val workManager: WorkManager, + private val workBuilder: ContactDiaryWorkBuilder, + private val onboardingSettings: OnboardingSettings ) { + fun setup() { + onboardingSettings.isOnboardedFlow.onEach { isOnboarded -> + if (isOnboarded) { + schedulePeriodic() + } + }.launchIn(appScope) + } + /** * Enqueue background contact diary clean periodic worker * Replace with new if older work exists. */ - fun schedulePeriodic() { + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + internal fun schedulePeriodic() { Timber.d("ContactDiaryWorkScheduler schedulePeriodic()") // Create unique work and enqueue workManager.enqueueUniquePeriodicWork( diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivity.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivity.kt index 09f6ce0b1374dcdcbbfcbc16691ef79d723ee091..4c29cfed00bbd859dca32876331190bfd1ce6723 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivity.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivity.kt @@ -18,7 +18,6 @@ import dagger.android.DispatchingAndroidInjector import dagger.android.HasAndroidInjector import de.rki.coronawarnapp.NavGraphDirections import de.rki.coronawarnapp.R -import de.rki.coronawarnapp.contactdiary.retention.ContactDiaryWorkScheduler import de.rki.coronawarnapp.contactdiary.ui.overview.ContactDiaryOverviewFragmentDirections import de.rki.coronawarnapp.databinding.ActivityMainBinding import de.rki.coronawarnapp.datadonation.analytics.worker.DataDonationAnalyticsScheduler @@ -75,7 +74,6 @@ class MainActivity : AppCompatActivity(), HasAndroidInjector { private val navController by lazy { supportFragmentManager.findNavController(R.id.nav_host_fragment) } @Inject lateinit var powerManagement: PowerManagement - @Inject lateinit var contactDiaryWorkScheduler: ContactDiaryWorkScheduler @Inject lateinit var dataDonationAnalyticsScheduler: DataDonationAnalyticsScheduler override fun onCreate(savedInstanceState: Bundle?) { @@ -193,7 +191,6 @@ class MainActivity : AppCompatActivity(), HasAndroidInjector { override fun onResume() { super.onResume() vm.doBackgroundNoiseCheck() - contactDiaryWorkScheduler.schedulePeriodic() dataDonationAnalyticsScheduler.schedulePeriodic() } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/consent/CheckInsConsentFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/consent/CheckInsConsentFragment.kt index 8b014f565b08ae7e37cf3b95f3fd656701dde8c9..509c638328ff2aeeb7b3fec897bbf35d89d3dfc7 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/consent/CheckInsConsentFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/consent/CheckInsConsentFragment.kt @@ -81,6 +81,11 @@ class CheckInsConsentFragment : Fragment(R.layout.check_ins_consent_fragment), A } } + override fun onStop() { + super.onStop() + viewModel.setAutoSubmission() + } + private fun showSkipDialog() { MaterialAlertDialogBuilder(requireContext()) .setTitle(R.string.trace_location_attendee_consent_dialog_title) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/consent/CheckInsConsentViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/consent/CheckInsConsentViewModel.kt index ee398a8155056d60b6dc033cf8fb1b988707a2ba..6d131177005f045d4140cee2e8e60e0f135bbab5 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/consent/CheckInsConsentViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/consent/CheckInsConsentViewModel.kt @@ -51,8 +51,6 @@ class CheckInsConsentViewModel @AssistedInject constructor( resetPreviousSubmissionConsents() Timber.d("Navigate to shareSelectedCheckIns") - autoSubmission.updateMode(AutoSubmission.Mode.MONITOR) - // Update CheckIns for new submission val idsWithConsent = selectedSetFlow.value checkInRepository.updateSubmissionConsents( @@ -75,7 +73,6 @@ class CheckInsConsentViewModel @AssistedInject constructor( resetPreviousSubmissionConsents() Timber.d("Navigate to doNotShareCheckIns") - autoSubmission.updateMode(AutoSubmission.Mode.MONITOR) val event = if (coronaTest.first().isViewed) { Timber.d("Navigate to SubmissionResultReadyFragment") CheckInsConsentNavigation.ToSubmissionResultReadyFragment @@ -86,6 +83,11 @@ class CheckInsConsentViewModel @AssistedInject constructor( events.postValue(event) } + fun setAutoSubmission() { + Timber.d("setAutoSubmission") + autoSubmission.updateMode(AutoSubmission.Mode.MONITOR) + } + fun onCloseClick() = launch { val event = if (coronaTest.first().isViewed) { Timber.d("openSkipDialog") diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/contactdiary/retention/ContactDiaryWorkSchedulerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/contactdiary/retention/ContactDiaryWorkSchedulerTest.kt index 0bd5a76f4b1ce2e29ef686508a2f714af9e86984..573679b168fe7e5050c35e60a4d891e99f1b4a62 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/contactdiary/retention/ContactDiaryWorkSchedulerTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/contactdiary/retention/ContactDiaryWorkSchedulerTest.kt @@ -4,13 +4,18 @@ import androidx.work.ExistingPeriodicWorkPolicy import androidx.work.Operation import androidx.work.PeriodicWorkRequest import androidx.work.WorkManager +import de.rki.coronawarnapp.storage.OnboardingSettings import io.mockk.MockKAnnotations import io.mockk.every import io.mockk.impl.annotations.MockK -import io.mockk.verifySequence +import io.mockk.verify +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.test.runBlockingTest import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import testhelpers.BaseTest +import testhelpers.coroutines.runBlockingTest2 class ContactDiaryWorkSchedulerTest : BaseTest() { @@ -18,6 +23,7 @@ class ContactDiaryWorkSchedulerTest : BaseTest() { @MockK lateinit var operation: Operation @MockK lateinit var workBuilder: ContactDiaryWorkBuilder @MockK lateinit var periodicWorkRequest: PeriodicWorkRequest + @MockK lateinit var onBoardingSettings: OnboardingSettings @BeforeEach fun setup() { @@ -32,16 +38,32 @@ class ContactDiaryWorkSchedulerTest : BaseTest() { } returns operation } - private fun createScheduler() = ContactDiaryWorkScheduler( + private fun createScheduler(scope: CoroutineScope) = ContactDiaryWorkScheduler( + appScope = scope, workManager = workManager, - workBuilder = workBuilder + workBuilder = workBuilder, + onboardingSettings = onBoardingSettings ) @Test - fun `test periodic work was scheduled`() { - createScheduler().schedulePeriodic() + fun `test periodic work was scheduled`() = runBlockingTest { + createScheduler(this).schedulePeriodic() + verifyIfWorkWasScheduled() + } + + @Test + fun `periodic work should be scheduled after onboaring`() = runBlockingTest2(ignoreActive = true) { + val onboardingFlow = MutableStateFlow(false) + every { onBoardingSettings.isOnboardedFlow } returns onboardingFlow + createScheduler(this).setup() + verifyIfWorkWasScheduled(exactly = 0) + + onboardingFlow.value = true + verifyIfWorkWasScheduled(exactly = 1) + } - verifySequence { + private fun verifyIfWorkWasScheduled(exactly: Int = 1) { + verify(exactly = exactly) { workManager.enqueueUniquePeriodicWork( ContactDiaryWorkScheduler.PERIODIC_WORK_NAME, ExistingPeriodicWorkPolicy.REPLACE, diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/consent/CheckInsConsentViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/consent/CheckInsConsentViewModelTest.kt index bf5f2ee7a8c334051ded1733d6587b9b58b2f83f..d2e41bd456f9c6542916b339a4cf2d241e07f818 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/consent/CheckInsConsentViewModelTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/consent/CheckInsConsentViewModelTest.kt @@ -15,6 +15,7 @@ import io.mockk.every import io.mockk.impl.annotations.MockK import io.mockk.just import io.mockk.mockk +import io.mockk.verify import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.flowOf import okio.ByteString.Companion.decodeBase64 @@ -288,7 +289,6 @@ class CheckInsConsentViewModelTest : BaseTest() { coVerify { checkInRepository.updateSubmissionConsents(any(), false) - autoSubmission.updateMode(AutoSubmission.Mode.MONITOR) checkInRepository.updateSubmissionConsents(any(), true) } } @@ -303,7 +303,6 @@ class CheckInsConsentViewModelTest : BaseTest() { coVerify { checkInRepository.updateSubmissionConsents(any(), false) - autoSubmission.updateMode(AutoSubmission.Mode.MONITOR) checkInRepository.updateSubmissionConsents(any(), true) } } @@ -318,7 +317,6 @@ class CheckInsConsentViewModelTest : BaseTest() { coVerify { checkInRepository.updateSubmissionConsents(any(), false) - autoSubmission.updateMode(AutoSubmission.Mode.MONITOR) } } @@ -332,10 +330,15 @@ class CheckInsConsentViewModelTest : BaseTest() { coVerify { checkInRepository.updateSubmissionConsents(any(), false) - autoSubmission.updateMode(AutoSubmission.Mode.MONITOR) } } + @Test + fun setAutoSubmission() { + createViewModel().setAutoSubmission() + verify { autoSubmission.updateMode(AutoSubmission.Mode.MONITOR) } + } + private fun createViewModel() = CheckInsConsentViewModel( savedState = savedState, dispatcherProvider = TestDispatcherProvider(),