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 7c76a021c136143cfc24ea622e70770d00d10ff8..06ab72e5bd5d4db5c22262ebd42b247d9bdcf527 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 0f521a9d18849bfbca2d8ee19306508047d05b64..68db8003d018a4d36a8613c42cafd614447b08f0 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 192bf74d988e7093cae7bc93e369b877304fd940..7735bc4ced327496573f3297d5d3bf0e4941ba73 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 d2ecaaa45a67e2f9755c7a82f08670657348306a..61f9627f2b6bf8e2a067026723db217e7e7d3ebe 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 871029e488c1e173473012e37a8f8c69d1d64796..bee511d98e39ba1566300da84fcf7fcdcc12f44a 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 de86e326eb36ded52f49cba93a3719ae9d60d120..64cadd0143537488cfcb6068dadea8435ac1c672 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 6474fed1f768505b1c588fafb9540005d4825b9e..0969b737219e643e15ab83253e1a259c0e82a28a 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>