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

Commit

Permalink
Introduce dagger 2, first risk level unit tests (EXPOSUREAPP-2207) (#…
Browse files Browse the repository at this point in the history
…1069)

* - add hilt for dependency injection
- enable application & activities for hilt

* updated dependency versions

* test get risk level

* renamed binding

* -hilt +dagger 2

* satisfying klint

* satisfying klint

* satisfying klint

* satisfying klint

* satisfying klint for tests

* additional module stubs, explicit android injector

* additional module stubs, explicit android injector

* renamed implementations

* fixed compiler error for device for tester

Co-authored-by: Fabian Kajzar <[email protected]>
Co-authored-by: Jakob Möller <[email protected]>
  • Loading branch information
3 people authored Aug 26, 2020
1 parent 0d26afb commit 5240f1b
Show file tree
Hide file tree
Showing 23 changed files with 387 additions and 92 deletions.
7 changes: 7 additions & 0 deletions Corona-Warn-App/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,13 @@ dependencies {
implementation 'android.arch.lifecycle:extensions:1.1.1'
implementation 'androidx.annotation:annotation:1.1.0'

// DAGGER
implementation 'com.google.dagger:dagger:2.28.1'
implementation 'com.google.dagger:dagger-android:2.28.1'
implementation 'com.google.dagger:dagger-android-support:2.28.1'
kapt 'com.google.dagger:dagger-compiler:2.28.1'
kapt 'com.google.dagger:dagger-android-processor:2.28.1'

// QR
implementation('com.journeyapps:zxing-android-embedded:4.1.0') { transitive = false }
// noinspection GradleDependency - needed for SDK 23 compatibility, in combination with com.journeyapps:zxing-android-embedded:4.1.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import de.rki.coronawarnapp.exception.ExceptionCategory
import de.rki.coronawarnapp.exception.TransactionException
import de.rki.coronawarnapp.exception.reporting.report
import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
import de.rki.coronawarnapp.risk.DefaultRiskLevelCalculation
import de.rki.coronawarnapp.risk.RiskLevel
import de.rki.coronawarnapp.risk.RiskLevelCalculation
import de.rki.coronawarnapp.risk.TimeVariables
import de.rki.coronawarnapp.server.protocols.AppleLegacyKeyExchange
import de.rki.coronawarnapp.service.applicationconfiguration.ApplicationConfigurationService
Expand All @@ -37,7 +37,7 @@ import de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel
import de.rki.coronawarnapp.ui.viewmodel.TracingViewModel
import de.rki.coronawarnapp.util.KeyFileHelper
import de.rki.coronawarnapp.util.security.SecurityHelper
import kotlinx.android.synthetic.deviceForTesters.fragment_test_risk_level_calculation.transmission_number
import kotlinx.android.synthetic.deviceForTesters.fragment_test_risk_level_calculation.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
Expand Down Expand Up @@ -253,7 +253,7 @@ class TestRiskLevelCalculation : Fragment() {
val appConfig =
ApplicationConfigurationService.asyncRetrieveApplicationConfiguration()

val riskLevelScore = RiskLevelCalculation.calculateRiskScore(
val riskLevelScore = DefaultRiskLevelCalculation().calculateRiskScore(
appConfig.attenuationDuration,
exposureSummary
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,29 @@ import androidx.lifecycle.lifecycleScope
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.work.Configuration
import androidx.work.WorkManager
import dagger.android.AndroidInjector
import dagger.android.DispatchingAndroidInjector
import dagger.android.HasAndroidInjector
import de.rki.coronawarnapp.exception.reporting.ErrorReportReceiver
import de.rki.coronawarnapp.exception.reporting.ReportingConstants.ERROR_REPORT_LOCAL_BROADCAST_CHANNEL
import de.rki.coronawarnapp.notification.NotificationHelper
import de.rki.coronawarnapp.storage.LocalData
import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction
import de.rki.coronawarnapp.util.CWADebug
import de.rki.coronawarnapp.util.ConnectivityHelper
import de.rki.coronawarnapp.util.di.AppInjector
import de.rki.coronawarnapp.util.di.ApplicationComponent
import de.rki.coronawarnapp.worker.BackgroundWorkHelper
import de.rki.coronawarnapp.worker.BackgroundWorkScheduler
import kotlinx.coroutines.launch
import org.conscrypt.Conscrypt
import timber.log.Timber
import java.security.Security
import java.util.UUID
import javax.inject.Inject

class CoronaWarnApplication : Application(), LifecycleObserver,
Application.ActivityLifecycleCallbacks {
Application.ActivityLifecycleCallbacks, HasAndroidInjector {

companion object {
val TAG: String? = CoronaWarnApplication::class.simpleName
Expand All @@ -54,7 +60,15 @@ class CoronaWarnApplication : Application(), LifecycleObserver,

private lateinit var errorReceiver: ErrorReportReceiver

@Inject
lateinit var component: ApplicationComponent

@Inject
lateinit var androidInjector: DispatchingAndroidInjector<Any>

override fun onCreate() {
AppInjector.init(this)

super.onCreate()
instance = this

Expand Down Expand Up @@ -183,4 +197,6 @@ class CoronaWarnApplication : Application(), LifecycleObserver,
LocalBroadcastManager.getInstance(this)
.registerReceiver(errorReceiver, IntentFilter(ERROR_REPORT_LOCAL_BROADCAST_CHANNEL))
}

override fun androidInjector(): AndroidInjector<Any> = androidInjector
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package de.rki.coronawarnapp.receiver

import dagger.Module

@Module
internal abstract class ReceiverBinder
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package de.rki.coronawarnapp.risk

import com.google.android.gms.nearby.exposurenotification.ExposureSummary
import de.rki.coronawarnapp.server.protocols.ApplicationConfigurationOuterClass
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.math.round

@Singleton
class DefaultRiskLevelCalculation @Inject constructor() : RiskLevelCalculation {

companion object {

private var TAG = DefaultRiskLevelCalculation::class.simpleName

private const val DECIMAL_MULTIPLIER = 100
}

override fun calculateRiskScore(
attenuationParameters: ApplicationConfigurationOuterClass.AttenuationDuration,
exposureSummary: ExposureSummary
): Double {

/** all attenuation values are capped to [TimeVariables.MAX_ATTENUATION_DURATION] */
val weightedAttenuationLow =
attenuationParameters.weights.low
.times(exposureSummary.attenuationDurationsInMinutes[0].capped())
val weightedAttenuationMid =
attenuationParameters.weights.mid
.times(exposureSummary.attenuationDurationsInMinutes[1].capped())
val weightedAttenuationHigh =
attenuationParameters.weights.high
.times(exposureSummary.attenuationDurationsInMinutes[2].capped())

val maximumRiskScore = exposureSummary.maximumRiskScore.toDouble()

val defaultBucketOffset = attenuationParameters.defaultBucketOffset.toDouble()
val normalizationDivisor = attenuationParameters.riskScoreNormalizationDivisor.toDouble()

val attenuationStrings =
"Weighted Attenuation: ($weightedAttenuationLow + $weightedAttenuationMid + " +
"$weightedAttenuationHigh + $defaultBucketOffset)"
Timber.v(attenuationStrings)

val weightedAttenuationDuration =
weightedAttenuationLow
.plus(weightedAttenuationMid)
.plus(weightedAttenuationHigh)
.plus(defaultBucketOffset)

Timber.v("Formula used: ($maximumRiskScore / $normalizationDivisor) * $weightedAttenuationDuration")

val riskScore = (maximumRiskScore / normalizationDivisor) * weightedAttenuationDuration

return round(riskScore.times(DECIMAL_MULTIPLIER)).div(DECIMAL_MULTIPLIER)
}

private fun Int.capped(): Int {
return if (this > TimeVariables.getMaxAttenuationDuration()) {
TimeVariables.getMaxAttenuationDuration()
} else {
this
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package de.rki.coronawarnapp.risk

import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class DefaultRiskScoreAnalysis @Inject constructor() : RiskScoreAnalysis {

override fun withinDefinedLevelThreshold(riskScore: Double, min: Int, max: Int) =
riskScore >= min && riskScore <= max
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,58 +2,11 @@ package de.rki.coronawarnapp.risk

import com.google.android.gms.nearby.exposurenotification.ExposureSummary
import de.rki.coronawarnapp.server.protocols.ApplicationConfigurationOuterClass
import timber.log.Timber
import kotlin.math.round

object RiskLevelCalculation {
private var TAG = RiskLevelCalculation::class.simpleName

private const val DECIMAL_MULTIPLIER = 100
interface RiskLevelCalculation {

fun calculateRiskScore(
attenuationParameters: ApplicationConfigurationOuterClass.AttenuationDuration,
exposureSummary: ExposureSummary
): Double {

/** all attenuation values are capped to [TimeVariables.MAX_ATTENUATION_DURATION] */
val weightedAttenuationLow =
attenuationParameters.weights.low
.times(exposureSummary.attenuationDurationsInMinutes[0].capped())
val weightedAttenuationMid =
attenuationParameters.weights.mid
.times(exposureSummary.attenuationDurationsInMinutes[1].capped())
val weightedAttenuationHigh =
attenuationParameters.weights.high
.times(exposureSummary.attenuationDurationsInMinutes[2].capped())

val maximumRiskScore = exposureSummary.maximumRiskScore.toDouble()

val defaultBucketOffset = attenuationParameters.defaultBucketOffset.toDouble()
val normalizationDivisor = attenuationParameters.riskScoreNormalizationDivisor.toDouble()

val attenuationStrings =
"Weighted Attenuation: ($weightedAttenuationLow + $weightedAttenuationMid + " +
"$weightedAttenuationHigh + $defaultBucketOffset)"
Timber.v(attenuationStrings)

val weightedAttenuationDuration =
weightedAttenuationLow
.plus(weightedAttenuationMid)
.plus(weightedAttenuationHigh)
.plus(defaultBucketOffset)

Timber.v("Formula used: ($maximumRiskScore / $normalizationDivisor) * $weightedAttenuationDuration")

val riskScore = (maximumRiskScore / normalizationDivisor) * weightedAttenuationDuration

return round(riskScore.times(DECIMAL_MULTIPLIER)).div(DECIMAL_MULTIPLIER)
}

private fun Int.capped(): Int {
return if (this > TimeVariables.getMaxAttenuationDuration()) {
TimeVariables.getMaxAttenuationDuration()
} else {
this
}
}
): Double
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package de.rki.coronawarnapp.risk

import dagger.Binds
import dagger.Module
import javax.inject.Singleton

@Module
abstract class RiskModule {

@Binds
@Singleton
abstract fun bindRiskLevelCalculation(
riskLevelCalculation: DefaultRiskLevelCalculation
): RiskLevelCalculation

@Binds
@Singleton
abstract fun bindRiskScoreAnalysis(
riskScoreAnalysis: DefaultRiskScoreAnalysis
): RiskScoreAnalysis
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package de.rki.coronawarnapp.risk

interface RiskScoreAnalysis {

fun withinDefinedLevelThreshold(
riskScore: Double,
min: Int,
max: Int
): Boolean
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package de.rki.coronawarnapp.service

import dagger.Module

@Module
internal abstract class ServiceBinder
Loading

0 comments on commit 5240f1b

Please sign in to comment.