From 290298ce0155777c5e4a2bd13580a3e2b1d178cd Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 22 Sep 2025 10:30:04 +0200 Subject: [PATCH] Change in clear cache behavior: - Do not reset the analytics store, so that we do not ask the user consent again => Parity with iOS. - Do not reset the permission store, because it contains information that's related to the system permission, which cannot be retrieved otherwise => Should help with #3195. --- .../features/ftue/api/state/FtueService.kt | 3 -- .../ftue/impl/state/DefaultFtueService.kt | 7 --- .../ftue/impl/DefaultFtueServiceTest.kt | 43 ------------------- .../features/ftue/test/FakeFtueService.kt | 9 +--- features/preferences/impl/build.gradle.kts | 2 - .../impl/tasks/ClearCacheUseCase.kt | 3 -- .../tasks/DefaultClearCacheUseCaseTest.kt | 7 --- .../api/PermissionStateProvider.kt | 2 - .../impl/DefaultPermissionStateProvider.kt | 2 - .../test/FakePermissionStateProvider.kt | 7 --- .../analytics/api/AnalyticsService.kt | 5 --- .../analytics/impl/DefaultAnalyticsService.kt | 4 -- .../impl/DefaultAnalyticsServiceTest.kt | 14 ------ .../analytics/noop/NoopAnalyticsService.kt | 1 - .../analytics/test/FakeAnalyticsService.kt | 6 --- 15 files changed, 1 insertion(+), 114 deletions(-) diff --git a/features/ftue/api/src/main/kotlin/io/element/android/features/ftue/api/state/FtueService.kt b/features/ftue/api/src/main/kotlin/io/element/android/features/ftue/api/state/FtueService.kt index 7ea26c548f1..b596f328d5e 100644 --- a/features/ftue/api/src/main/kotlin/io/element/android/features/ftue/api/state/FtueService.kt +++ b/features/ftue/api/src/main/kotlin/io/element/android/features/ftue/api/state/FtueService.kt @@ -15,9 +15,6 @@ import kotlinx.coroutines.flow.StateFlow interface FtueService { /** The current state of the FTUE. */ val state: StateFlow - - /** Reset the FTUE state. */ - suspend fun reset() } /** The state of the FTUE. */ diff --git a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/state/DefaultFtueService.kt b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/state/DefaultFtueService.kt index ae26ee28bc8..40f19b1e7a6 100644 --- a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/state/DefaultFtueService.kt +++ b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/state/DefaultFtueService.kt @@ -58,13 +58,6 @@ class DefaultFtueService( } } - override suspend fun reset() { - analyticsService.reset() - if (sdkVersionProvider.isAtLeast(Build.VERSION_CODES.TIRAMISU)) { - permissionStateProvider.resetPermission(Manifest.permission.POST_NOTIFICATIONS) - } - } - init { combine( sessionVerificationService.sessionVerifiedStatus.onEach { sessionVerifiedStatus -> diff --git a/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/DefaultFtueServiceTest.kt b/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/DefaultFtueServiceTest.kt index 4ec2558c74c..e46f43f3c36 100644 --- a/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/DefaultFtueServiceTest.kt +++ b/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/DefaultFtueServiceTest.kt @@ -27,8 +27,6 @@ import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.analytics.noop.NoopAnalyticsService import io.element.android.services.analytics.test.FakeAnalyticsService import io.element.android.services.toolbox.test.sdk.FakeBuildVersionSdkIntProvider -import io.element.android.tests.testutils.lambda.lambdaRecorder -import io.element.android.tests.testutils.lambda.value import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Test @@ -191,47 +189,6 @@ class DefaultFtueServiceTest { assertThat(awaitItem()).isEqualTo(InternalFtueState.Complete) } } - - @Test - fun `reset do the expected actions S`() = runTest { - val resetAnalyticsLambda = lambdaRecorder { } - val analyticsService = FakeAnalyticsService( - resetLambda = resetAnalyticsLambda - ) - val resetPermissionLambda = lambdaRecorder { } - val permissionStateProvider = FakePermissionStateProvider( - resetPermissionLambda = resetPermissionLambda - ) - val service = createDefaultFtueService( - sdkIntVersion = Build.VERSION_CODES.S, - permissionStateProvider = permissionStateProvider, - analyticsService = analyticsService, - ) - service.reset() - resetAnalyticsLambda.assertions().isCalledOnce() - resetPermissionLambda.assertions().isNeverCalled() - } - - @Test - fun `reset do the expected actions TIRAMISU`() = runTest { - val resetLambda = lambdaRecorder { } - val analyticsService = FakeAnalyticsService( - resetLambda = resetLambda - ) - val resetPermissionLambda = lambdaRecorder { } - val permissionStateProvider = FakePermissionStateProvider( - resetPermissionLambda = resetPermissionLambda - ) - val service = createDefaultFtueService( - sdkIntVersion = Build.VERSION_CODES.TIRAMISU, - permissionStateProvider = permissionStateProvider, - analyticsService = analyticsService, - ) - service.reset() - resetLambda.assertions().isCalledOnce() - resetPermissionLambda.assertions().isCalledOnce() - .with(value("android.permission.POST_NOTIFICATIONS")) - } } internal fun TestScope.createDefaultFtueService( diff --git a/features/ftue/test/src/main/kotlin/io/element/android/features/ftue/test/FakeFtueService.kt b/features/ftue/test/src/main/kotlin/io/element/android/features/ftue/test/FakeFtueService.kt index 9217dbd22c7..1dbc2c281be 100644 --- a/features/ftue/test/src/main/kotlin/io/element/android/features/ftue/test/FakeFtueService.kt +++ b/features/ftue/test/src/main/kotlin/io/element/android/features/ftue/test/FakeFtueService.kt @@ -9,18 +9,11 @@ package io.element.android.features.ftue.test import io.element.android.features.ftue.api.state.FtueService import io.element.android.features.ftue.api.state.FtueState -import io.element.android.tests.testutils.lambda.lambdaError import kotlinx.coroutines.flow.MutableStateFlow -class FakeFtueService( - private val resetLambda: () -> Unit = { lambdaError() }, -) : FtueService { +class FakeFtueService : FtueService { override val state: MutableStateFlow = MutableStateFlow(FtueState.Unknown) - override suspend fun reset() { - resetLambda() - } - suspend fun emitState(newState: FtueState) { state.emit(newState) } diff --git a/features/preferences/impl/build.gradle.kts b/features/preferences/impl/build.gradle.kts index d1041c1ba74..d3edba5833e 100644 --- a/features/preferences/impl/build.gradle.kts +++ b/features/preferences/impl/build.gradle.kts @@ -72,7 +72,6 @@ dependencies { implementation(projects.features.rageshake.api) implementation(projects.features.lockscreen.api) implementation(projects.features.analytics.api) - implementation(projects.features.ftue.api) implementation(projects.features.licenses.api) implementation(projects.features.logout.api) implementation(projects.features.deactivation.api) @@ -101,7 +100,6 @@ dependencies { testImplementation(projects.libraries.preferences.test) testImplementation(projects.libraries.push.test) testImplementation(projects.libraries.pushstore.test) - testImplementation(projects.features.ftue.test) testImplementation(projects.features.invite.test) testImplementation(projects.features.rageshake.test) testImplementation(projects.features.logout.test) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/tasks/ClearCacheUseCase.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/tasks/ClearCacheUseCase.kt index 11c4a3c94fd..50d9cf8798c 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/tasks/ClearCacheUseCase.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/tasks/ClearCacheUseCase.kt @@ -12,7 +12,6 @@ import coil3.SingletonImageLoader import dev.zacsweers.metro.ContributesBinding import dev.zacsweers.metro.Inject import dev.zacsweers.metro.Provider -import io.element.android.features.ftue.api.state.FtueService import io.element.android.features.invite.api.SeenInvitesStore import io.element.android.features.preferences.impl.DefaultCacheService import io.element.android.libraries.core.coroutine.CoroutineDispatchers @@ -36,7 +35,6 @@ class DefaultClearCacheUseCase( private val coroutineDispatchers: CoroutineDispatchers, private val defaultCacheService: DefaultCacheService, private val okHttpClient: Provider, - private val ftueService: FtueService, private val pushService: PushService, private val seenInvitesStore: SeenInvitesStore, private val activeRoomsHolder: ActiveRoomsHolder, @@ -56,7 +54,6 @@ class DefaultClearCacheUseCase( // Clear app cache context.cacheDir.deleteRecursively() // Clear some settings - ftueService.reset() seenInvitesStore.clear() // Ensure any error will be displayed again pushService.setIgnoreRegistrationError(matrixClient.sessionId, false) diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/tasks/DefaultClearCacheUseCaseTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/tasks/DefaultClearCacheUseCaseTest.kt index cfdc63984ca..1e16509ad29 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/tasks/DefaultClearCacheUseCaseTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/tasks/DefaultClearCacheUseCaseTest.kt @@ -10,7 +10,6 @@ package io.element.android.features.preferences.impl.tasks import androidx.test.platform.app.InstrumentationRegistry import app.cash.turbine.test import com.google.common.truth.Truth.assertThat -import io.element.android.features.ftue.test.FakeFtueService import io.element.android.features.invite.test.InMemorySeenInvitesStore import io.element.android.features.preferences.impl.DefaultCacheService import io.element.android.libraries.matrix.api.core.SessionId @@ -41,10 +40,6 @@ class DefaultClearCacheUseCaseTest { clearCacheLambda = clearCacheLambda, ) val defaultCacheService = DefaultCacheService() - val resetFtueLambda = lambdaRecorder { } - val ftueService = FakeFtueService( - resetLambda = resetFtueLambda, - ) val setIgnoreRegistrationErrorLambda = lambdaRecorder { _, _ -> } val resetBatteryOptimizationStateResult = lambdaRecorder { } val pushService = FakePushService( @@ -59,7 +54,6 @@ class DefaultClearCacheUseCaseTest { coroutineDispatchers = testCoroutineDispatchers(), defaultCacheService = defaultCacheService, okHttpClient = { OkHttpClient.Builder().build() }, - ftueService = ftueService, pushService = pushService, seenInvitesStore = seenInvitesStore, activeRoomsHolder = activeRoomsHolder, @@ -67,7 +61,6 @@ class DefaultClearCacheUseCaseTest { defaultCacheService.clearedCacheEventFlow.test { sut.invoke() clearCacheLambda.assertions().isCalledOnce() - resetFtueLambda.assertions().isCalledOnce() setIgnoreRegistrationErrorLambda.assertions().isCalledOnce() .with(value(matrixClient.sessionId), value(false)) resetBatteryOptimizationStateResult.assertions().isCalledOnce() diff --git a/libraries/permissions/api/src/main/kotlin/io/element/android/libraries/permissions/api/PermissionStateProvider.kt b/libraries/permissions/api/src/main/kotlin/io/element/android/libraries/permissions/api/PermissionStateProvider.kt index 0c811b72659..be9e38c4fb8 100644 --- a/libraries/permissions/api/src/main/kotlin/io/element/android/libraries/permissions/api/PermissionStateProvider.kt +++ b/libraries/permissions/api/src/main/kotlin/io/element/android/libraries/permissions/api/PermissionStateProvider.kt @@ -16,6 +16,4 @@ interface PermissionStateProvider { suspend fun setPermissionAsked(permission: String, value: Boolean) fun isPermissionAsked(permission: String): Flow - - suspend fun resetPermission(permission: String) } diff --git a/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/DefaultPermissionStateProvider.kt b/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/DefaultPermissionStateProvider.kt index f61147fffac..69022479701 100644 --- a/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/DefaultPermissionStateProvider.kt +++ b/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/DefaultPermissionStateProvider.kt @@ -40,6 +40,4 @@ class DefaultPermissionStateProvider( override suspend fun setPermissionAsked(permission: String, value: Boolean) = permissionsStore.setPermissionAsked(permission, value) override fun isPermissionAsked(permission: String): Flow = permissionsStore.isPermissionAsked(permission) - - override suspend fun resetPermission(permission: String) = permissionsStore.resetPermission(permission) } diff --git a/libraries/permissions/test/src/main/kotlin/io/element/android/libraries/permissions/test/FakePermissionStateProvider.kt b/libraries/permissions/test/src/main/kotlin/io/element/android/libraries/permissions/test/FakePermissionStateProvider.kt index c97057bc7d9..0365ebfbbeb 100644 --- a/libraries/permissions/test/src/main/kotlin/io/element/android/libraries/permissions/test/FakePermissionStateProvider.kt +++ b/libraries/permissions/test/src/main/kotlin/io/element/android/libraries/permissions/test/FakePermissionStateProvider.kt @@ -15,7 +15,6 @@ class FakePermissionStateProvider( private var permissionGranted: Boolean = true, permissionDenied: Boolean = false, permissionAsked: Boolean = false, - private val resetPermissionLambda: (String) -> Unit = {}, ) : PermissionStateProvider { private val permissionDeniedFlow = MutableStateFlow(permissionDenied) private val permissionAskedFlow = MutableStateFlow(permissionAsked) @@ -37,10 +36,4 @@ class FakePermissionStateProvider( } override fun isPermissionAsked(permission: String): Flow = permissionAskedFlow - - override suspend fun resetPermission(permission: String) { - setPermissionAsked(permission, false) - setPermissionDenied(permission, false) - resetPermissionLambda(permission) - } } diff --git a/services/analytics/api/src/main/kotlin/io/element/android/services/analytics/api/AnalyticsService.kt b/services/analytics/api/src/main/kotlin/io/element/android/services/analytics/api/AnalyticsService.kt index 750a6d1d17d..589abf28fe4 100644 --- a/services/analytics/api/src/main/kotlin/io/element/android/services/analytics/api/AnalyticsService.kt +++ b/services/analytics/api/src/main/kotlin/io/element/android/services/analytics/api/AnalyticsService.kt @@ -47,9 +47,4 @@ interface AnalyticsService : AnalyticsTracker, ErrorTracker { * Update analyticsId from the AccountData. */ suspend fun setAnalyticsId(analyticsId: String) - - /** - * Reset the analytics service (will ask for user consent again). - */ - suspend fun reset() } diff --git a/services/analytics/impl/src/main/kotlin/io/element/android/services/analytics/impl/DefaultAnalyticsService.kt b/services/analytics/impl/src/main/kotlin/io/element/android/services/analytics/impl/DefaultAnalyticsService.kt index 1df6c3ca6ae..d80a8288adf 100644 --- a/services/analytics/impl/src/main/kotlin/io/element/android/services/analytics/impl/DefaultAnalyticsService.kt +++ b/services/analytics/impl/src/main/kotlin/io/element/android/services/analytics/impl/DefaultAnalyticsService.kt @@ -70,10 +70,6 @@ class DefaultAnalyticsService( analyticsStore.setDidAskUserConsent() } - override suspend fun reset() { - analyticsStore.setDidAskUserConsent(false) - } - override suspend fun setAnalyticsId(analyticsId: String) { Timber.tag(analyticsTag.value).d("setAnalyticsId($analyticsId)") analyticsStore.setAnalyticsId(analyticsId) diff --git a/services/analytics/impl/src/test/kotlin/io/element/android/services/analytics/impl/DefaultAnalyticsServiceTest.kt b/services/analytics/impl/src/test/kotlin/io/element/android/services/analytics/impl/DefaultAnalyticsServiceTest.kt index e05a6e4208f..6e653037614 100644 --- a/services/analytics/impl/src/test/kotlin/io/element/android/services/analytics/impl/DefaultAnalyticsServiceTest.kt +++ b/services/analytics/impl/src/test/kotlin/io/element/android/services/analytics/impl/DefaultAnalyticsServiceTest.kt @@ -180,20 +180,6 @@ class DefaultAnalyticsServiceTest { resetLambda.assertions().isCalledOnce() } - @Test - fun `when reset is invoked, the user consent is reset`() = runTest { - val store = FakeAnalyticsStore( - defaultDidAskUserConsent = true, - ) - val sut = createDefaultAnalyticsService( - coroutineScope = backgroundScope, - analyticsStore = store, - ) - assertThat(store.didAskUserConsentFlow.first()).isTrue() - sut.reset() - assertThat(store.didAskUserConsentFlow.first()).isFalse() - } - @Test fun `when a session is added, nothing happen`() = runTest { val sut = createDefaultAnalyticsService( diff --git a/services/analytics/noop/src/main/kotlin/io/element/android/services/analytics/noop/NoopAnalyticsService.kt b/services/analytics/noop/src/main/kotlin/io/element/android/services/analytics/noop/NoopAnalyticsService.kt index f43367c66a3..db03ca5553d 100644 --- a/services/analytics/noop/src/main/kotlin/io/element/android/services/analytics/noop/NoopAnalyticsService.kt +++ b/services/analytics/noop/src/main/kotlin/io/element/android/services/analytics/noop/NoopAnalyticsService.kt @@ -31,7 +31,6 @@ class NoopAnalyticsService : AnalyticsService { override suspend fun setDidAskUserConsent() = Unit override val analyticsIdFlow: Flow = flowOf("") override suspend fun setAnalyticsId(analyticsId: String) = Unit - override suspend fun reset() = Unit override fun capture(event: VectorAnalyticsEvent) = Unit override fun screen(screen: VectorAnalyticsScreen) = Unit override fun updateUserProperties(userProperties: UserProperties) = Unit diff --git a/services/analytics/test/src/main/kotlin/io/element/android/services/analytics/test/FakeAnalyticsService.kt b/services/analytics/test/src/main/kotlin/io/element/android/services/analytics/test/FakeAnalyticsService.kt index 081f66d4e63..f8b250e37be 100644 --- a/services/analytics/test/src/main/kotlin/io/element/android/services/analytics/test/FakeAnalyticsService.kt +++ b/services/analytics/test/src/main/kotlin/io/element/android/services/analytics/test/FakeAnalyticsService.kt @@ -20,7 +20,6 @@ import kotlinx.coroutines.flow.asStateFlow class FakeAnalyticsService( isEnabled: Boolean = false, didAskUserConsent: Boolean = false, - private val resetLambda: () -> Unit = {}, ) : AnalyticsService { private val isEnabledFlow = MutableStateFlow(isEnabled) override val didAskUserConsentFlow = MutableStateFlow(didAskUserConsent) @@ -65,9 +64,4 @@ class FakeAnalyticsService( override fun updateSuperProperties(updatedProperties: SuperProperties) { // No op } - - override suspend fun reset() { - didAskUserConsentFlow.value = false - resetLambda() - } }