Skip to content
Snippets Groups Projects
Unverified Commit 07e4b397 authored by Matthias Urhahn's avatar Matthias Urhahn Committed by GitHub
Browse files

Remove legacy code and static access for disabling tracing (DEV) (#3122)


* Remove legacy code and static access for disabling tracing.

* Add unit test.

* Fix instrumentation test.

Co-authored-by: default avatarMohamed <mohamed.metwalli@sap.com>
parent 6f7c8edc
No related branches found
No related tags found
No related merge requests found
Showing
with 73 additions and 69 deletions
......@@ -3,6 +3,7 @@ package de.rki.coronawarnapp.ui.onboarding
import androidx.test.ext.junit.runners.AndroidJUnit4
import dagger.Module
import dagger.android.ContributesAndroidInjector
import de.rki.coronawarnapp.nearby.ENFClient
import de.rki.coronawarnapp.nearby.TracingPermissionHelper
import de.rki.coronawarnapp.storage.TracingSettings
import de.rki.coronawarnapp.storage.interoperability.InteroperabilityRepository
......@@ -33,6 +34,7 @@ class OnboardingTracingFragmentTest : BaseUITest() {
@MockK lateinit var interopRepo: InteroperabilityRepository
@MockK lateinit var factory: TracingPermissionHelper.Factory
@MockK lateinit var tracingSettings: TracingSettings
@MockK lateinit var enfClient: ENFClient
@Rule
@JvmField
......@@ -50,7 +52,8 @@ class OnboardingTracingFragmentTest : BaseUITest() {
interoperabilityRepository = interopRepo,
tracingPermissionHelperFactory = factory,
dispatcherProvider = TestDispatcherProvider(),
tracingSettings = tracingSettings
tracingSettings = tracingSettings,
enfClient = enfClient,
)
)
......
package de.rki.coronawarnapp.nearby
import de.rki.coronawarnapp.util.di.AppInjector
import kotlinx.coroutines.flow.first
import timber.log.Timber
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
/**
* Wrapper class for the Exposure Notification Client in the com.google.android.gms.nearby.Nearby
* implementing all Exposure Notification related APIs
*/
object InternalExposureNotificationClient {
// reference to the client from the Google framework with the given application context
private val enfClient by lazy {
AppInjector.component.enfClient
}
/**
* Disables broadcasting and scanning. You can call this directly, and it is also called when
* users uninstall the app. When it’s called as part of the uninstallation process, the
* database and keys are deleted from the device.
*
* @return
*/
suspend fun asyncStop() = suspendCoroutine<Unit> { cont ->
enfClient.setTracing(
false,
onSuccess = { cont.resume(Unit) },
onError = { cont.resumeWithException(it) },
onPermissionRequired = { Timber.e("Permission was required to disable tracing?") }
)
}
/**
* Indicates if exposure notifications are running
*
* @return
*/
suspend fun asyncIsEnabled(): Boolean = enfClient.isTracingEnabled.first()
}
......@@ -2,6 +2,11 @@ package de.rki.coronawarnapp.nearby.modules.tracing
import com.google.android.gms.common.api.Status
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import timber.log.Timber
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
interface TracingStatus {
val isTracingEnabled: Flow<Boolean>
......@@ -13,3 +18,22 @@ interface TracingStatus {
onPermissionRequired: (Status) -> Unit
)
}
/**
* Returns true if tracing was disabled.
*/
suspend fun TracingStatus.disableTracingIfEnabled(): Boolean {
if (!isTracingEnabled.first()) {
Timber.d("Tracing was already disabled.")
return false
}
return suspendCoroutine { cont ->
setTracing(
enable = false,
onSuccess = { cont.resume(true) },
onError = { cont.resumeWithException(it) },
onPermissionRequired = { Timber.e("Permission was required to disable tracing?") }
)
}
}
......@@ -3,7 +3,6 @@ package de.rki.coronawarnapp.storage
import android.annotation.SuppressLint
import de.rki.coronawarnapp.diagnosiskeys.download.DownloadDiagnosisKeysTask
import de.rki.coronawarnapp.nearby.ENFClient
import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
import de.rki.coronawarnapp.nearby.modules.detectiontracker.ExposureDetectionTracker
import de.rki.coronawarnapp.nearby.modules.detectiontracker.lastSubmission
import de.rki.coronawarnapp.presencetracing.risk.execution.PresenceTracingRiskWorkScheduler
......@@ -34,8 +33,6 @@ import javax.inject.Singleton
/**
* The Tracing Repository refreshes and triggers all tracing relevant data. Some functions get their
* data directly from the Exposure Notification, others consume the shared preferences.
*
* @see InternalExposureNotificationClient
*/
@Singleton
class TracingRepository @Inject constructor(
......
......@@ -8,7 +8,6 @@ import androidx.fragment.app.Fragment
import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.bugreporting.ui.toErrorDialogBuilder
import de.rki.coronawarnapp.databinding.FragmentSettingsTracingBinding
import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
import de.rki.coronawarnapp.tracing.ui.TracingConsentDialog
import de.rki.coronawarnapp.tracing.ui.settings.SettingsTracingFragmentViewModel.Event
import de.rki.coronawarnapp.util.DialogHelper
......@@ -24,8 +23,6 @@ import javax.inject.Inject
/**
* The user can start/stop tracing and is informed about tracing.
*
* @see InternalExposureNotificationClient
*/
class SettingsTracingFragment : Fragment(R.layout.fragment_settings_tracing), AutoInject {
......
......@@ -11,8 +11,9 @@ import dagger.assisted.AssistedInject
import de.rki.coronawarnapp.exception.ExceptionCategory
import de.rki.coronawarnapp.exception.reporting.report
import de.rki.coronawarnapp.installTime.InstallTimeProvider
import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
import de.rki.coronawarnapp.nearby.ENFClient
import de.rki.coronawarnapp.nearby.TracingPermissionHelper
import de.rki.coronawarnapp.nearby.modules.tracing.disableTracingIfEnabled
import de.rki.coronawarnapp.risk.execution.ExposureWindowRiskWorkScheduler
import de.rki.coronawarnapp.tracing.GeneralTracingStatus
import de.rki.coronawarnapp.tracing.ui.details.items.periodlogged.PeriodLoggedBox
......@@ -35,7 +36,8 @@ class SettingsTracingFragmentViewModel @AssistedInject constructor(
installTimeProvider: InstallTimeProvider,
private val backgroundStatus: BackgroundModeStatus,
tracingPermissionHelperFactory: TracingPermissionHelper.Factory,
private val exposureWindowRiskWorkScheduler: ExposureWindowRiskWorkScheduler
private val exposureWindowRiskWorkScheduler: ExposureWindowRiskWorkScheduler,
private val enfClient: ENFClient,
) : CWAViewModel(dispatcherProvider = dispatcherProvider) {
val loggingPeriod: LiveData<PeriodLoggedBox.Item> =
......@@ -120,8 +122,7 @@ class SettingsTracingFragmentViewModel @AssistedInject constructor(
isTracingSwitchChecked.postValue(false)
launch {
try {
if (InternalExposureNotificationClient.asyncIsEnabled()) {
InternalExposureNotificationClient.asyncStop()
if (enfClient.disableTracingIfEnabled()) {
exposureWindowRiskWorkScheduler.setPeriodicRiskCalculation(enabled = false)
}
} catch (exception: Exception) {
......
......@@ -7,8 +7,9 @@ import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import de.rki.coronawarnapp.exception.ExceptionCategory
import de.rki.coronawarnapp.exception.reporting.report
import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
import de.rki.coronawarnapp.nearby.ENFClient
import de.rki.coronawarnapp.nearby.TracingPermissionHelper
import de.rki.coronawarnapp.nearby.modules.tracing.disableTracingIfEnabled
import de.rki.coronawarnapp.storage.TracingSettings
import de.rki.coronawarnapp.storage.interoperability.InteroperabilityRepository
import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
......@@ -22,6 +23,7 @@ class OnboardingTracingFragmentViewModel @AssistedInject constructor(
tracingPermissionHelperFactory: TracingPermissionHelper.Factory,
dispatcherProvider: DispatcherProvider,
private val tracingSettings: TracingSettings,
private val enfClient: ENFClient,
) : CWAViewModel(dispatcherProvider = dispatcherProvider) {
val countryList = interoperabilityRepository.countryList
......@@ -63,8 +65,7 @@ class OnboardingTracingFragmentViewModel @AssistedInject constructor(
fun resetTracing() {
launch {
try {
if (InternalExposureNotificationClient.asyncIsEnabled()) {
InternalExposureNotificationClient.asyncStop()
if (enfClient.disableTracingIfEnabled()) {
tracingSettings.isConsentGiven = false
}
} catch (exception: Exception) {
......
......@@ -5,7 +5,8 @@ import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import de.rki.coronawarnapp.exception.ExceptionCategory
import de.rki.coronawarnapp.exception.reporting.report
import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
import de.rki.coronawarnapp.nearby.ENFClient
import de.rki.coronawarnapp.nearby.modules.tracing.disableTracingIfEnabled
import de.rki.coronawarnapp.util.DataReset
import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
import de.rki.coronawarnapp.util.shortcuts.AppShortcutsHelper
......@@ -17,6 +18,7 @@ class SettingsResetViewModel @AssistedInject constructor(
dispatcherProvider: DispatcherProvider,
private val dataReset: DataReset,
private val shortcutsHelper: AppShortcutsHelper,
private val enfClient: ENFClient,
) : CWAViewModel(dispatcherProvider = dispatcherProvider) {
val clickEvent: SingleLiveEvent<SettingsEvents> = SingleLiveEvent()
......@@ -32,18 +34,9 @@ class SettingsResetViewModel @AssistedInject constructor(
fun deleteAllAppContent() {
launch {
try {
// TODO Remove static access
val isTracingEnabled = InternalExposureNotificationClient.asyncIsEnabled()
// only stop tracing if it is currently enabled
if (isTracingEnabled) {
InternalExposureNotificationClient.asyncStop()
}
enfClient.disableTracingIfEnabled()
} catch (apiException: ApiException) {
apiException.report(
ExceptionCategory.EXPOSURENOTIFICATION,
TAG,
null
)
apiException.report(ExceptionCategory.EXPOSURENOTIFICATION, TAG, null)
}
dataReset.clearAllLocalData()
......
......@@ -9,12 +9,15 @@ import io.mockk.Called
import io.mockk.MockKAnnotations
import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.mockk.mockk
import io.mockk.verify
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.take
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import testhelpers.BaseTest
......@@ -129,4 +132,32 @@ class DefaultTracingStatusTest : BaseTest() {
thrownError shouldBe ourError
}
@Test
fun `extension for disabling tracing if enabled`() {
val enabledFlow = MutableStateFlow(false)
val tracingStatus = mockk<TracingStatus>().apply {
every { isTracingEnabled } returns enabledFlow
every { setTracing(any(), any(), any(), any()) } answers {
val enabled = arg<Boolean>(0)
val onSuccess = arg<(Boolean) -> Unit>(1)
val onError = arg<(Throwable) -> Unit>(2)
val onPermissionRequired = arg<(Status) -> Unit>(3)
onSuccess(false)
}
}
runBlocking {
tracingStatus.disableTracingIfEnabled()
verify(exactly = 0) { tracingStatus.setTracing(any(), any(), any(), any()) }
}
enabledFlow.value = true
runBlocking {
tracingStatus.disableTracingIfEnabled() shouldBe true
verify(exactly = 1) { tracingStatus.setTracing(any(), any(), any(), any()) }
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment