Skip to content
This repository has been archived by the owner on Jun 20, 2023. It is now read-only.

EOL (EXPOSUREAPP-14785) #5845

Merged
merged 35 commits into from Feb 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
9618adb
Setup `Eol`
mtwalli Feb 15, 2023
ee13dea
Add Settings
mtwalli Feb 15, 2023
af8d7ff
Dev Settings
mtwalli Feb 15, 2023
eca23ff
Home Screen proofing
mtwalli Feb 15, 2023
4955f2c
Stats
mtwalli Feb 16, 2023
e439633
Analytics
mtwalli Feb 16, 2023
e6dbeba
Lint
mtwalli Feb 16, 2023
f040547
Cwa App stop inits
mtwalli Feb 16, 2023
fc2d457
Restart
mtwalli Feb 16, 2023
17fd736
Notifications
mtwalli Feb 16, 2023
e20f6b6
FAQ card
mtwalli Feb 16, 2023
8591889
Merge branch 'release/3.2.x' into feature/14785-eol
mtwalli Feb 16, 2023
2321ffd
Cancel worker
mtwalli Feb 16, 2023
27ce914
Card in Home
mtwalli Feb 16, 2023
bcd9ee3
Tests
mtwalli Feb 16, 2023
606d271
Lint
mtwalli Feb 16, 2023
b75d782
Fix stats
mtwalli Feb 16, 2023
7c36396
fix tests
mtwalli Feb 16, 2023
d2394bd
Notification
mtwalli Feb 16, 2023
c4ee095
Merge branch 'release/3.2.x' into feature/14785-eol
mtwalli Feb 17, 2023
0cc31d5
EOL - Recycle Bin (EXPOSUREAPP-14793) (#5846)
mtwalli Feb 17, 2023
45910a7
Merge branch 'release/3.2.x' into feature/14785-eol
mtwalli Feb 20, 2023
1d97c8b
EOL - certificates (EXPOSUREAPP-14790) (#5849)
schauersbergern Feb 20, 2023
bb19623
EOL - Background Work (EXPOSUREAPP-14794) (#5852)
mtwalli Feb 20, 2023
ccc1e37
EOL - onboarding (EXPOSUREAPP-14788) (#5851)
SamuraiKek Feb 20, 2023
09a072b
Eol bottom bar (EXPOSUREAPP-14791) (#5853)
schauersbergern Feb 20, 2023
48fa898
Merge branch 'release/3.2.x' into feature/14785-eol
mtwalli Feb 21, 2023
e42f344
EOL - Battery optimization / tracing dialogs
mtwalli Feb 21, 2023
7a4195c
EOL - Disable deep-links (#5855)
mtwalli Feb 21, 2023
cf3a8e9
EOL - error logs (EXPOSUREAPP-14837) (#5857)
mtwalli Feb 21, 2023
bb1539d
EOL - notifications (EXPOSUREAPP-14795) (#5854)
mtwalli Feb 21, 2023
2c23cfb
Merge branch 'feature/14838-dialogs' into feature/14785-eol
mtwalli Feb 21, 2023
dd16666
Hide options in menu and app information. (#5858)
SamuraiKek Feb 21, 2023
cb27f7e
EOL - Shortcuts (EXPOSUREAPP-14804) (#5859)
mtwalli Feb 22, 2023
bee9d42
Merge branch 'release/3.2.x' into feature/14785-eol
mtwalli Feb 22, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -64,7 +64,7 @@ class HomeFragmentTest : BaseUITest() {
MockKAnnotations.init(this, relaxed = true)
with(homeFragmentViewModel) {
every { refreshTests() } just Runs
every { tracingHeaderState } returns MutableLiveData(TracingHeaderState.TracingActive)
every { tracingHeaderState } returns MutableLiveData(false to TracingHeaderState.TracingActive)
every { homeItems } returns homeFragmentItemsLiveData()
every { events } returns SingleLiveEvent()
every { showPopUps() } just Runs
Expand Down Expand Up @@ -134,7 +134,7 @@ class HomeFragmentTest : BaseUITest() {
@Screenshot
@Test
fun captureHomeFragmentTracingDisabled() {
every { homeFragmentViewModel.tracingHeaderState } returns MutableLiveData(TracingHeaderState.TracingInActive)
every { homeFragmentViewModel.tracingHeaderState } returns MutableLiveData(false to TracingHeaderState.TracingInActive)
every { homeFragmentViewModel.homeItems } returns homeFragmentItemsLiveData(
HomeData.Tracing.TRACING_DISABLED_ITEM
)
Expand Down
Expand Up @@ -6,6 +6,9 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import dagger.Module
import dagger.android.ContributesAndroidInjector
import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.eol.AppEol
import io.mockk.MockKAnnotations
import io.mockk.impl.annotations.MockK
import org.junit.After
import org.junit.Before
import org.junit.Test
Expand All @@ -20,11 +23,15 @@ import testhelpers.takeScreenshot
@RunWith(AndroidJUnit4::class)
class OnboardingPrivacyFragmentTest : BaseUITest() {

@MockK lateinit var appEol: AppEol

@Before
fun setup() {
MockKAnnotations.init(this, relaxed = true)

setupMockViewModel(
object : OnboardingPrivacyViewModel.Factory {
override fun create(): OnboardingPrivacyViewModel = OnboardingPrivacyViewModel()
override fun create(): OnboardingPrivacyViewModel = OnboardingPrivacyViewModel(appEol)
}
)
}
Expand Down
@@ -0,0 +1,101 @@
package de.rki.coronawarnapp.test.eol

import android.os.Bundle
import android.text.format.DateFormat
import android.view.View
import androidx.fragment.app.Fragment
import com.google.android.material.datepicker.MaterialDatePicker
import com.google.android.material.timepicker.MaterialTimePicker
import com.google.android.material.timepicker.TimeFormat
import com.jakewharton.processphoenix.ProcessPhoenix
import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.databinding.FragmentTestEolBinding
import de.rki.coronawarnapp.test.menu.ui.TestMenuItem
import de.rki.coronawarnapp.ui.dialog.displayDialog
import de.rki.coronawarnapp.util.di.AutoInject
import de.rki.coronawarnapp.util.ui.viewBinding
import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
import de.rki.coronawarnapp.util.viewmodel.cwaViewModels
import java.time.Instant
import java.time.LocalTime
import java.time.ZoneId
import javax.inject.Inject

class EolTestFragment : Fragment(R.layout.fragment_test_eol), AutoInject {

@Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory

private val viewModel: EolTestViewModel by cwaViewModels { viewModelFactory }
private val binding: FragmentTestEolBinding by viewBinding()

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

viewModel.dateTime.observe(viewLifecycleOwner) {
binding.dateTime.text = it.toString()
}

viewModel.restart.observe(viewLifecycleOwner) {
displayDialog {
title("Restarting ↻")
message("EOL will be fully effective after restart")
setCancelable(false)
}
ProcessPhoenix.triggerRebirth(context)
}

binding.openPicket.setOnClickListener { showDatePicker() }
}

private fun showDatePicker() {
MaterialDatePicker
.Builder
.datePicker()
.setSelection(Instant.now().toEpochMilli())
.build()
.apply {
addOnPositiveButtonClickListener { date ->
showTimePicker { time ->
viewModel.updateEolDateTime(
Instant.ofEpochMilli(date)
.atZone(ZoneId.systemDefault())
.toLocalDate()
.atTime(time.hour, time.minute)
.atZone(ZoneId.of("CET"))
)
}
}
}
.show(childFragmentManager, "eol.test.date.picker")
}

private fun showTimePicker(
defaultValue: LocalTime = LocalTime.now(),
callback: (LocalTime) -> Unit
) {
MaterialTimePicker
.Builder()
.setTimeFormat(
if (DateFormat.is24HourFormat(requireContext())) TimeFormat.CLOCK_24H else TimeFormat.CLOCK_12H
)
.apply {
setHour(defaultValue.hour)
setMinute(defaultValue.minute)
}
.build()
.apply {
addOnPositiveButtonClickListener {
callback(LocalTime.of(hour, minute))
}
}
.show(childFragmentManager, "eol.test.time.picker")
}

companion object {
val MENU_ITEM = TestMenuItem(
title = "EOl Date Time",
description = "End of Life Dev Settings",
targetId = R.id.eolTestFragment
)
}
}
@@ -0,0 +1,16 @@
package de.rki.coronawarnapp.test.eol

import dagger.Binds
import dagger.Module
import dagger.multibindings.IntoMap
import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
import de.rki.coronawarnapp.util.viewmodel.CWAViewModelKey

@Module
abstract class EolTestModule {
@Binds
@IntoMap
@CWAViewModelKey(EolTestViewModel::class)
abstract fun eolTest(factory: EolTestViewModel.Factory): CWAViewModelFactory<out CWAViewModel>
}
@@ -0,0 +1,25 @@
package de.rki.coronawarnapp.test.eol

import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import de.rki.coronawarnapp.eol.EolSetting
import de.rki.coronawarnapp.util.ui.SingleLiveEvent
import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory
import java.time.ZonedDateTime

class EolTestViewModel @AssistedInject constructor(
private val eolSetting: EolSetting
) : CWAViewModel() {

val dateTime = eolSetting.eolDateTime.asLiveData2()
val restart = SingleLiveEvent<Unit>()

fun updateEolDateTime(dateTime: ZonedDateTime) = launch {
eolSetting.setEolDateTime(dateTime.toString())
restart.postValue(Unit)
}

@AssistedFactory
interface Factory : SimpleCWAViewModelFactory<EolTestViewModel>
}
Expand Up @@ -14,6 +14,7 @@ import de.rki.coronawarnapp.test.dccticketing.DccTicketingTestFragment
import de.rki.coronawarnapp.test.debugoptions.ui.DebugOptionsFragment
import de.rki.coronawarnapp.test.deltaonboarding.ui.DeltaOnboardingFragment
import de.rki.coronawarnapp.test.dsc.ui.DccStateValidationTestFragment
import de.rki.coronawarnapp.test.eol.EolTestFragment
import de.rki.coronawarnapp.test.hometestcards.ui.HomeTestCardsFragment
import de.rki.coronawarnapp.test.keydownload.ui.KeyDownloadTestFragment
import de.rki.coronawarnapp.test.playground.ui.PlaygroundFragment
Expand All @@ -38,6 +39,7 @@ class TestMenuFragmentViewModel @AssistedInject constructor(

val testMenuData by lazy {
listOf(
EolTestFragment.MENU_ITEM,
CclTestFragment.MENU_ITEM,
DebugOptionsFragment.MENU_ITEM,
SettingsCrashReportFragment.MENU_ITEM,
Expand Down
Expand Up @@ -20,6 +20,8 @@ import de.rki.coronawarnapp.test.deltaonboarding.ui.DeltaOnboardingFragment
import de.rki.coronawarnapp.test.deltaonboarding.ui.DeltaOnboardingFragmentModule
import de.rki.coronawarnapp.test.dsc.ui.DccStateValidationTestFragment
import de.rki.coronawarnapp.test.dsc.ui.DccStateValidationTestModule
import de.rki.coronawarnapp.test.eol.EolTestFragment
import de.rki.coronawarnapp.test.eol.EolTestModule
import de.rki.coronawarnapp.test.hometestcards.ui.HomeTestCardsFragment
import de.rki.coronawarnapp.test.hometestcards.ui.HomeTestCardsFragmentModule
import de.rki.coronawarnapp.test.keydownload.ui.KeyDownloadTestFragment
Expand Down Expand Up @@ -95,4 +97,7 @@ abstract class MainActivityTestModule {

@ContributesAndroidInjector(modules = [CclTestModule::class])
abstract fun cclTestFragment(): CclTestFragment

@ContributesAndroidInjector(modules = [EolTestModule::class])
abstract fun eolTestFragment(): EolTestFragment
}
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>

<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:ignore="HardcodedText">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/margin_8"
android:orientation="vertical">

<LinearLayout
style="@style/Card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/margin_8"
android:orientation="vertical">

<TextView
style="@style/headline6"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="EOL Date Time"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />


<TextView
android:id="@+id/date_time"
style="@style/body1Medium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="10dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<Button
android:id="@+id/open_picket"
style="@style/buttonPrimary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_16"
android:text="Open Picker" />

</LinearLayout>

</LinearLayout>
</androidx.core.widget.NestedScrollView>
Expand Up @@ -179,4 +179,9 @@
android:name="de.rki.coronawarnapp.test.ccl.CclTestFragment"
android:label="CclTestFragment" />

<fragment
android:id="@+id/eolTestFragment"
android:name="de.rki.coronawarnapp.test.eol.EolTestFragment"
android:label="EolTestFragment" />

</navigation>
Expand Up @@ -16,7 +16,7 @@ import dagger.android.HasAndroidInjector
import de.rki.coronawarnapp.bugreporting.loghistory.LogHistoryTree
import de.rki.coronawarnapp.exception.reporting.ErrorReportReceiver
import de.rki.coronawarnapp.exception.reporting.ReportingConstants.ERROR_REPORT_LOCAL_BROADCAST_CHANNEL
import de.rki.coronawarnapp.initializer.Initializer
import de.rki.coronawarnapp.initializer.AppStarter
import de.rki.coronawarnapp.util.BuildVersionWrap
import de.rki.coronawarnapp.util.CWADebug
import de.rki.coronawarnapp.util.coroutine.AppScope
Expand All @@ -29,17 +29,15 @@ import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Provider

class CoronaWarnApplication : Application(), HasAndroidInjector {

@Inject lateinit var appStarter: AppStarter
@Inject lateinit var component: ApplicationComponent
@Inject lateinit var androidInjector: DispatchingAndroidInjector<Any>

@Inject lateinit var workManager: WorkManager
@Inject lateinit var imageLoaderFactory: ImageLoaderFactory
@Inject lateinit var foregroundState: ForegroundState
@Inject lateinit var initializers: Provider<Set<@JvmSuppressWildcards Initializer>>
@AppScope @Inject lateinit var appScope: CoroutineScope
@LogHistoryTree @Inject lateinit var rollingLogHistory: Timber.Tree

Expand All @@ -61,10 +59,7 @@ class CoronaWarnApplication : Application(), HasAndroidInjector {
compPreview.inject(this)
}

initializers.get().forEach { initializer ->
Timber.d("initialize => %s", initializer::class.simpleName)
initializer.initialize()
}
appStarter.start()

Timber.plant(rollingLogHistory)

Expand Down
Expand Up @@ -8,6 +8,7 @@ import de.rki.coronawarnapp.ccl.dccwalletinfo.calculation.DccWalletInfoCalculati
import de.rki.coronawarnapp.covidcertificate.person.core.PersonCertificates
import de.rki.coronawarnapp.covidcertificate.person.core.PersonCertificatesProvider
import de.rki.coronawarnapp.covidcertificate.person.core.PersonCertificatesSettings
import de.rki.coronawarnapp.eol.AppEol
import de.rki.coronawarnapp.tag
import de.rki.coronawarnapp.util.coroutine.AppScope
import kotlinx.coroutines.CoroutineScope
Expand All @@ -29,6 +30,7 @@ class DccWalletInfoUpdateTrigger @Inject constructor(
private val personCertificateProvider: PersonCertificatesProvider,
private val personCertificatesSettings: PersonCertificatesSettings,
private val dccWalletInfoCalculationManager: DccWalletInfoCalculationManager,
private val appEol: AppEol,
) {

init {
Expand All @@ -45,16 +47,24 @@ class DccWalletInfoUpdateTrigger @Inject constructor(
// delay to collect rapid changes and do only one recalculation
.debounce(1000L)
.collectLatest {
runCatching {
triggerNow(admissionScenarioId())
}.onFailure {
Timber.tag(TAG).d(it, "Failed to calculate dccWallet")
if (!appEol.isEol.first()) {
runCatching {
triggerNow(admissionScenarioId())
}.onFailure {
Timber.tag(TAG).d(it, "Failed to calculate dccWallet")
}
} else {
Timber.tag(TAG).d("EOL -> quit")
}
}
}
}

suspend fun triggerAfterConfigChange(configurationChanged: Boolean = false) {
if (appEol.isEol.first()) {
Timber.tag(TAG).d("EOL -> quit")
return
}
Timber.tag(TAG).d("triggerAfterConfigChange()")
dccWalletInfoCalculationManager.triggerAfterConfigChange(
admissionScenarioId = admissionScenarioId(),
Expand Down
Expand Up @@ -38,6 +38,23 @@ class ContactDiaryRetentionCalculation @Inject constructor(
return list.filter { entity -> isOutOfRetention(entity.date) }
}

suspend fun clearOutdatedEntries() {
clearObsoleteContactDiaryLocationVisits()
Timber.d("Obsolete contact diary location visits cleaned up")

clearObsoleteContactDiaryPersonEncounters()
Timber.d("Obsolete contact diary person encounters cleaned up")

clearObsoleteRiskPerDate()
Timber.d("Obsolete Aggregated Risk Per Date Results cleaned up")

clearObsoleteCoronaTests()
Timber.d("Obsolete Contact Diary Corona Tests cleaned up")

clearObsoleteSubmissions()
Timber.d("Obsolete Contact Diary Submissions cleaned up")
}

suspend fun clearObsoleteContactDiaryLocationVisits() {
val list = repository.locationVisits.first()
Timber.d("Contact Diary Location Visits total count: ${list.size}")
Expand Down