From 74cfe68251d48a7cd94ccd4d9f756bc081e87e21 Mon Sep 17 00:00:00 2001 From: Philipp Woessner <64482866+pwoessner@users.noreply.github.com> Date: Fri, 5 Jun 2020 15:30:44 +0200 Subject: [PATCH] Store last successful calculated risk level (#196) * added timestamp when onboarding was completed * added last successfully calculated risk level, refactored RiskLevelRepository Co-authored-by: marcmuschko <marc.muschko@sap.com> --- .../coronawarnapp/TestRiskLevelCalculation.kt | 6 +- .../de/rki/coronawarnapp/risk/RiskLevel.kt | 6 ++ .../de/rki/coronawarnapp/storage/LocalData.kt | 100 ++++++++++++++++++ .../storage/RiskLevelRepository.kt | 69 ++++++++---- .../ui/onboarding/OnboardingActivity.kt | 1 + .../fragment_test_risk_level_calculation.xml | 2 +- .../src/main/res/values/strings.xml | 8 ++ 7 files changed, 172 insertions(+), 20 deletions(-) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/TestRiskLevelCalculation.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/TestRiskLevelCalculation.kt index 7c76a021c..06ab72e5b 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/TestRiskLevelCalculation.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/TestRiskLevelCalculation.kt @@ -123,6 +123,7 @@ class TestRiskLevelCalculation : Fragment() { private suspend fun retrieveDiagnosisKeys() { try { RetrieveDiagnosisKeysTransaction.start() + calculateRiskLevel() } catch (e: TransactionException) { e.report(ExceptionCategory.INTERNAL) } @@ -210,7 +211,10 @@ class TestRiskLevelCalculation : Fragment() { Observer { tracingViewModel.viewModelScope.launch { val riskAsString = "Level: ${it.riskLevel}\n" + - "Calc. Score: ${it.riskScore}\n" + + "Last successful Level: " + + "${LocalData.lastSuccessfullyCalculatedRiskLevel()}\n" + + "Calculated Score: ${it.riskScore}\n" + + "Last Time Server Fetch: ${LocalData.lastTimeDiagnosisKeysFromServerFetch()}\n" + "Tracing Duration: " + "${TimeUnit.MILLISECONDS.toDays(TimeVariables.getTimeActiveTracingDuration())} days \n" + "Tracing Duration in last 14 days: " + diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevel.kt index 0f521a9d1..68db8003d 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskLevel.kt @@ -42,6 +42,12 @@ enum class RiskLevel(val raw: Int) { } // risk level categories + val UNSUCCESSFUL_RISK_LEVELS = + arrayOf( + UNDETERMINED, + NO_CALCULATION_POSSIBLE_TRACING_OFF, + UNKNOWN_RISK_OUTDATED_RESULTS + ) private val HIGH_RISK_LEVELS = arrayOf(INCREASED_RISK) private val LOW_RISK_LEVELS = arrayOf( UNKNOWN_RISK_INITIAL, diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/LocalData.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/LocalData.kt index 192bf74d9..7735bc4ce 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/LocalData.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/LocalData.kt @@ -4,6 +4,7 @@ import android.content.SharedPreferences import androidx.core.content.edit import de.rki.coronawarnapp.CoronaWarnApplication import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.risk.RiskLevel import de.rki.coronawarnapp.util.security.SecurityHelper.globalEncryptedSharedPreferencesInstance import java.util.Date @@ -45,6 +46,33 @@ object LocalData { ) } + /** + * Gets the time when the user has completed the onboarding + * from the EncryptedSharedPrefs + * + * @return + */ + fun onboardingCompletedTimestamp(): Long? { + val timestamp = getSharedPreferenceInstance().getLong( + CoronaWarnApplication.getAppContext() + .getString(R.string.preference_onboarding_completed_timestamp), 0L + ) + + if (timestamp == 0L) return null + return timestamp + } + + /** + * Sets the time when the user has completed the onboarding + * from the EncryptedSharedPrefs + * @param value + */ + fun onboardingCompletedTimestamp(value: Long) = getSharedPreferenceInstance().edit(true) { + putLong( + CoronaWarnApplication.getAppContext() + .getString(R.string.preference_onboarding_completed_timestamp), value + ) + } /**************************************************** * TRACING DATA ****************************************************/ @@ -146,6 +174,78 @@ object LocalData { } } + /**************************************************** + * RISK LEVEL + ****************************************************/ + + /** + * Gets the last calculated risk level + * from the EncryptedSharedPrefs + * + * @see RiskLevelRepository + * + * @return + */ + fun lastCalculatedRiskLevel(): RiskLevel { + val rawRiskLevel = getSharedPreferenceInstance().getInt( + CoronaWarnApplication.getAppContext() + .getString(R.string.preference_risk_level_score), + RiskLevel.UNDETERMINED.raw + ) + return RiskLevel.forValue(rawRiskLevel) + } + + /** + * Sets the last calculated risk level + * from the EncryptedSharedPrefs + * + * @see RiskLevelRepository + * + * @param rawRiskLevel + */ + fun lastCalculatedRiskLevel(rawRiskLevel: Int) = + getSharedPreferenceInstance().edit(true) { + putInt( + CoronaWarnApplication.getAppContext() + .getString(R.string.preference_risk_level_score), + rawRiskLevel + ) + } + + /** + * Gets the last successfully calculated risk level + * from the EncryptedSharedPrefs + * + * @see RiskLevelRepository + * + * @return + */ + fun lastSuccessfullyCalculatedRiskLevel(): RiskLevel { + val rawRiskLevel = getSharedPreferenceInstance().getInt( + CoronaWarnApplication.getAppContext() + .getString(R.string.preference_risk_level_score_successful), + RiskLevel.UNDETERMINED.raw + ) + return RiskLevel.forValue(rawRiskLevel) + } + + /** + * Sets the last calculated risk level + * from the EncryptedSharedPrefs + * + * @see RiskLevelRepository + * + * @param rawRiskLevel + */ + fun lastSuccessfullyCalculatedRiskLevel(rawRiskLevel: Int) = + getSharedPreferenceInstance().edit(true) { + putInt( + CoronaWarnApplication.getAppContext() + .getString(R.string.preference_risk_level_score_successful), + rawRiskLevel + ) + } + /**************************************************** * SERVER FETCH DATA ****************************************************/ diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/RiskLevelRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/RiskLevelRepository.kt index d2ecaaa45..61f9627f2 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/RiskLevelRepository.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/RiskLevelRepository.kt @@ -1,33 +1,66 @@ package de.rki.coronawarnapp.storage import androidx.lifecycle.MutableLiveData -import de.rki.coronawarnapp.CoronaWarnApplication -import de.rki.coronawarnapp.R import de.rki.coronawarnapp.risk.RiskLevel -import de.rki.coronawarnapp.risk.RiskLevel.UNDETERMINED import de.rki.coronawarnapp.risk.RiskLevelConstants object RiskLevelRepository { + /** + * LiveData variable that can be consumed in a ViewModel to observe RiskLevel changes + */ val riskLevelScore = MutableLiveData(RiskLevelConstants.UNKNOWN_RISK_INITIAL) - fun setRiskLevelScore(score: RiskLevel) { - val rawRiskLevel = score.raw + /** + * Set the new calculated [RiskLevel] + * Calculation happens in the [de.rki.coronawarnapp.transaction.RiskLevelTransaction] + * + * @see de.rki.coronawarnapp.transaction.RiskLevelTransaction + * @see de.rki.coronawarnapp.risk.RiskLevelCalculation + * + * @param riskLevel + */ + fun setRiskLevelScore(riskLevel: RiskLevel) { + val rawRiskLevel = riskLevel.raw riskLevelScore.postValue(rawRiskLevel) - LocalData.getSharedPreferenceInstance() - .edit() - .putInt( - CoronaWarnApplication.getAppContext() - .getString(R.string.preference_risk_level_score), - rawRiskLevel - ).apply() + + setLastCalculatedScore(rawRiskLevel) + setLastSuccessfullyCalculatedScore(riskLevel) } - fun getLastCalculatedScore(): RiskLevel { - val riskLevelScoreRaw = LocalData.getSharedPreferenceInstance().getInt( - CoronaWarnApplication.getAppContext() - .getString(R.string.preference_risk_level_score), UNDETERMINED.raw - ) - return RiskLevel.forValue(riskLevelScoreRaw) + /** + * Get the last calculated RiskLevel + * + * @return + */ + fun getLastCalculatedScore(): RiskLevel = LocalData.lastCalculatedRiskLevel() + + /** + * Set the last calculated RiskLevel + * + * @param rawRiskLevel + */ + private fun setLastCalculatedScore(rawRiskLevel: Int) = + LocalData.lastCalculatedRiskLevel(rawRiskLevel) + + /** + * Get the last successfully calculated [RiskLevel] + * + * @see RiskLevel + * + * @return + */ + fun getLastSuccessfullyCalculatedScore(): RiskLevel = + LocalData.lastSuccessfullyCalculatedRiskLevel() + + /** + * Set the last successfully calculated [RiskLevel] + * + * @param riskLevel + */ + private fun setLastSuccessfullyCalculatedScore(riskLevel: RiskLevel) { + if (!RiskLevel.UNSUCCESSFUL_RISK_LEVELS.contains(riskLevel)) { + LocalData.lastSuccessfullyCalculatedRiskLevel(riskLevel.raw) + } } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingActivity.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingActivity.kt index 871029e48..bee511d98 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingActivity.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingActivity.kt @@ -48,6 +48,7 @@ class OnboardingActivity : AppCompatActivity(), LifecycleObserver { fun completeOnboarding() { LocalData.isOnboarded(true) + LocalData.onboardingCompletedTimestamp(System.currentTimeMillis()) startActivity(Intent(this, MainActivity::class.java)) finish() } diff --git a/Corona-Warn-App/src/main/res/layout/fragment_test_risk_level_calculation.xml b/Corona-Warn-App/src/main/res/layout/fragment_test_risk_level_calculation.xml index de86e326e..64cadd014 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_test_risk_level_calculation.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_test_risk_level_calculation.xml @@ -63,7 +63,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="@dimen/spacing_normal" - android:text="Retrieve Local QR Code" /> + android:text="Scan Local QR Code" /> <Button android:id="@+id/button_calculate_risk_level" diff --git a/Corona-Warn-App/src/main/res/values/strings.xml b/Corona-Warn-App/src/main/res/values/strings.xml index 6474fed1f..0969b7372 100644 --- a/Corona-Warn-App/src/main/res/values/strings.xml +++ b/Corona-Warn-App/src/main/res/values/strings.xml @@ -14,6 +14,10 @@ <xliff:g id="preference">preference_onboarding_completed</xliff:g> </string> <!-- NOTR --> + <string name="preference_onboarding_completed_timestamp"> + <xliff:g id="preference">preference_onboarding_completed_timestamp</xliff:g> + </string> + <!-- NOTR --> <string name="preference_reset_app"> <xliff:g id="preference">preference_reset_app</xliff:g> </string> @@ -77,6 +81,10 @@ <xliff:g id="preference">preference_risk_level_score</xliff:g> </string> <!-- NOTR --> + <string name="preference_risk_level_score_successful"> + <xliff:g id="preference">preference_risk_level_score_successful</xliff:g> + </string> + <!-- NOTR --> <string name="preference_test_guid"> <xliff:g id="preference">preference_test_guid</xliff:g> </string> -- GitLab