diff --git a/anvil/anvil-annotations/src/main/java/com/duckduckgo/anvil/annotations/ContributesRemoteFeature.kt b/anvil/anvil-annotations/src/main/java/com/duckduckgo/anvil/annotations/ContributesRemoteFeature.kt index bd5205973c98..18a5df3c9db7 100644 --- a/anvil/anvil-annotations/src/main/java/com/duckduckgo/anvil/annotations/ContributesRemoteFeature.kt +++ b/anvil/anvil-annotations/src/main/java/com/duckduckgo/anvil/annotations/ContributesRemoteFeature.kt @@ -58,9 +58,6 @@ annotation class ContributesRemoteFeature( @Deprecated("Not needed anymore. Settings is now supported in top-level and sub-features and Toggle#getSettings returns it") val settingsStore: KClass<*> = Unit::class, - /** The class that implements the [FeatureExceptions.Store] interface */ - val exceptionsStore: KClass<*> = Unit::class, - /** The class that implements the [Toggle.Store] interface */ val toggleStore: KClass<*> = Unit::class, ) diff --git a/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributesRemoteFeatureCodeGenerator.kt b/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributesRemoteFeatureCodeGenerator.kt index c5e884c98f60..4dbd919c7a5c 100644 --- a/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributesRemoteFeatureCodeGenerator.kt +++ b/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributesRemoteFeatureCodeGenerator.kt @@ -152,27 +152,6 @@ class ContributesRemoteFeatureCodeGenerator : CodeGenerator { .build(), ) } - if (!customStorePresence.exceptionStorePresent) { - addFunction( - FunSpec.builder("providesNoopExceptionsStore") - .addAnnotation(Provides::class.asClassName()) - .addAnnotation( - AnnotationSpec.builder(RemoteFeatureStoreNamed::class.asClassName()) - .addMember("value = %T::class", boundType.asClassName()) - .build(), - ) - .addCode( - CodeBlock.of( - """ - return %T.EMPTY_STORE - """.trimIndent(), - FeatureExceptions::class.asClassName(), - ), - ) - .returns(FeatureExceptions.Store::class.asClassName()) - .build(), - ) - } addFunction( FunSpec.builder("provides${boundType.shortName}Inventory") .addAnnotation(Provides::class.asClassName()) @@ -264,20 +243,6 @@ class ContributesRemoteFeatureCodeGenerator : CodeGenerator { .primaryConstructor( FunSpec.constructorBuilder() .addAnnotation(AnnotationSpec.builder(Inject::class).build()) - .addParameter( - ParameterSpec - .builder( - "exceptionStore", - FeatureExceptions.Store::class, - ) - .addAnnotation( - AnnotationSpec - .builder(RemoteFeatureStoreNamed::class).addMember("value = %T::class", boundType.asClassName()) - .build(), - - ) - .build(), - ) .addParameter( ParameterSpec .builder( @@ -298,16 +263,6 @@ class ContributesRemoteFeatureCodeGenerator : CodeGenerator { .addParameter("context", context.asClassName(module)) .build(), ) - .addProperty( - PropertySpec - .builder( - "exceptionStore", - FeatureExceptions.Store::class, - KModifier.PRIVATE, - ) - .initializer("exceptionStore") - .build(), - ) .addProperty( PropertySpec .builder( @@ -400,18 +355,6 @@ class ContributesRemoteFeatureCodeGenerator : CodeGenerator { .returns(FeatureSettings.Store::class.java.asClassName()) .build(), ) - .addFunction( - FunSpec.builder("bindOptionalExceptionsStore") - .addModifiers(KModifier.ABSTRACT) - .addAnnotation(BindsOptionalOf::class.asClassName()) - .addAnnotation( - AnnotationSpec.builder(RemoteFeatureStoreNamed::class.asClassName()) - .addMember("value = %T::class", boundType.asClassName()) - .build(), - ) - .returns(FeatureExceptions.Store::class.java.asClassName()) - .build(), - ) .build(), ) } @@ -487,8 +430,6 @@ class ContributesRemoteFeatureCodeGenerator : CodeGenerator { } val exceptions = parseExceptions(feature.exceptions) - // TODO: Remove once migrating everything to getExceptions() - exceptionStore.insertAll(exceptions) val isEnabled = (feature.state == "enabled") || (appBuildConfig.flavor == %T && feature.state == "internal") this.feature.get().invokeMethod("self").setRawStoredState( @@ -656,11 +597,11 @@ class ContributesRemoteFeatureCodeGenerator : CodeGenerator { } return featureExceptions.toList() """.trimIndent(), - FeatureExceptions.FeatureException::class.fqName.asClassName(module), - FeatureExceptions.FeatureException::class.fqName.asClassName(module), + FeatureException::class.fqName.asClassName(module), + FeatureException::class.fqName.asClassName(module), ).build(), ) - .returns(List::class.asClassName().parameterizedBy(FeatureExceptions.FeatureException::class.asClassName())) + .returns(List::class.asClassName().parameterizedBy(FeatureException::class.asClassName())) .build() } @@ -1025,7 +966,6 @@ class ContributesRemoteFeatureCodeGenerator : CodeGenerator { } } - var exceptionStore = false var settingsStore = false var toggleStore = false @@ -1080,20 +1020,6 @@ class ContributesRemoteFeatureCodeGenerator : CodeGenerator { requireFeatureAndStoreCrossReference(vmClass, this) } } - with(annotation.exceptionsStoreOrNull()) { - exceptionStore = this != null - if (this != null) { - if (this.directSuperTypeReferences() - .none { it.asClassReferenceOrNull()?.fqName == FeatureExceptions.Store::class.fqName } - ) { - throw AnvilCompilationException( - "${vmClass.fqName} [exceptionsStore] must extend [FeatureExceptions.Store]", - element = vmClass.clazz.identifyingElement, - ) - } - requireFeatureAndStoreCrossReference(vmClass, this) - } - } with(annotation.toggleStoreOrNull()) { toggleStore = this != null if (this != null) { @@ -1152,30 +1078,33 @@ class ContributesRemoteFeatureCodeGenerator : CodeGenerator { } return CustomStorePresence( - exceptionStorePresent = exceptionStore, toggleStorePresent = toggleStore, settingsStorePresent = settingsStore, ) } + private enum class ContributesRemoteFeatureValues { + SCOPE, + BOUND_TYPE, + FEATURE_NAME, + SETTINGS_STORE, + TOGGLE_STORE, + } + private fun AnnotationReference.remoteFeatureStoreValueOrNull(): ClassReference? { - return argumentAt("value", 0)?.value() + return argumentAt("value", ContributesRemoteFeatureValues.SCOPE.ordinal)?.value() } private fun AnnotationReference.featureNameOrNull(): String? { - return argumentAt("featureName", 2)?.value() + return argumentAt("featureName", ContributesRemoteFeatureValues.FEATURE_NAME.ordinal)?.value() } private fun AnnotationReference.settingsStoreOrNull(): ClassReference? { - return argumentAt("settingsStore", 3)?.value() - } - - private fun AnnotationReference.exceptionsStoreOrNull(): ClassReference? { - return argumentAt("exceptionsStore", 4)?.value() + return argumentAt("settingsStore", ContributesRemoteFeatureValues.SETTINGS_STORE.ordinal)?.value() } private fun AnnotationReference.toggleStoreOrNull(): ClassReference? { - return argumentAt("toggleStore", 5)?.value() + return argumentAt("toggleStore", ContributesRemoteFeatureValues.TOGGLE_STORE.ordinal)?.value() } private fun ClassReference.declaredFunctions(): List { @@ -1208,6 +1137,5 @@ class ContributesRemoteFeatureCodeGenerator : CodeGenerator { private data class CustomStorePresence( val settingsStorePresent: Boolean = false, - val exceptionStorePresent: Boolean = false, val toggleStorePresent: Boolean = false, ) diff --git a/app/src/androidTest/java/com/duckduckgo/app/referencetests/FirstPartyCookiesReferenceTest.kt b/app/src/androidTest/java/com/duckduckgo/app/referencetests/FirstPartyCookiesReferenceTest.kt index 3f15fd9fb9aa..34e2fca6d9d0 100644 --- a/app/src/androidTest/java/com/duckduckgo/app/referencetests/FirstPartyCookiesReferenceTest.kt +++ b/app/src/androidTest/java/com/duckduckgo/app/referencetests/FirstPartyCookiesReferenceTest.kt @@ -37,7 +37,7 @@ import com.duckduckgo.cookies.store.CookieExceptionEntity import com.duckduckgo.cookies.store.CookiesRepository import com.duckduckgo.cookies.store.FirstPartyCookiePolicyEntity import com.duckduckgo.cookies.store.toFeatureException -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import com.duckduckgo.privacy.config.api.UnprotectedTemporary import com.duckduckgo.privacy.config.impl.models.JsonPrivacyConfig import com.duckduckgo.privacy.config.impl.network.JSONObjectAdapter diff --git a/app/src/androidTest/java/com/duckduckgo/app/referencetests/HttpsReferenceTest.kt b/app/src/androidTest/java/com/duckduckgo/app/referencetests/HttpsReferenceTest.kt index 8db7aa871a87..58b3f7942aed 100644 --- a/app/src/androidTest/java/com/duckduckgo/app/referencetests/HttpsReferenceTest.kt +++ b/app/src/androidTest/java/com/duckduckgo/app/referencetests/HttpsReferenceTest.kt @@ -27,7 +27,7 @@ import com.duckduckgo.common.test.CoroutineTestRule import com.duckduckgo.common.test.FileUtilities import com.duckduckgo.common.utils.isHttps import com.duckduckgo.common.utils.store.BinaryDataStore -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import com.duckduckgo.feature.toggles.api.FeatureToggle import com.duckduckgo.httpsupgrade.api.HttpsEmbeddedDataPersister import com.duckduckgo.httpsupgrade.api.HttpsUpgrader diff --git a/app/src/androidTest/java/com/duckduckgo/cookies/impl/features/firstparty/RealFirstPartyCookiesModifierTest.kt b/app/src/androidTest/java/com/duckduckgo/cookies/impl/features/firstparty/RealFirstPartyCookiesModifierTest.kt index a1170cee8253..aa51e993c588 100644 --- a/app/src/androidTest/java/com/duckduckgo/cookies/impl/features/firstparty/RealFirstPartyCookiesModifierTest.kt +++ b/app/src/androidTest/java/com/duckduckgo/cookies/impl/features/firstparty/RealFirstPartyCookiesModifierTest.kt @@ -29,7 +29,7 @@ import com.duckduckgo.common.utils.DefaultDispatcherProvider import com.duckduckgo.cookies.impl.SQLCookieRemover import com.duckduckgo.cookies.store.CookiesRepository import com.duckduckgo.cookies.store.FirstPartyCookiePolicyEntity -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import com.duckduckgo.privacy.config.api.UnprotectedTemporary import java.time.Instant import java.time.ZoneOffset diff --git a/app/src/main/java/com/duckduckgo/app/browser/di/BrowserModule.kt b/app/src/main/java/com/duckduckgo/app/browser/di/BrowserModule.kt index fb24bfea97bf..ea842b8c2068 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/di/BrowserModule.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/di/BrowserModule.kt @@ -22,7 +22,6 @@ import android.content.pm.PackageManager import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.preferencesDataStore -import androidx.room.Room import androidx.work.WorkManager import com.duckduckgo.adclick.api.AdClickManager import com.duckduckgo.app.browser.* @@ -45,9 +44,6 @@ import com.duckduckgo.app.browser.httperrors.HttpCodeSiteErrorHandlerImpl import com.duckduckgo.app.browser.httperrors.StringSiteErrorHandler import com.duckduckgo.app.browser.httperrors.StringSiteErrorHandlerImpl import com.duckduckgo.app.browser.logindetection.* -import com.duckduckgo.app.browser.mediaplayback.store.ALL_MIGRATIONS -import com.duckduckgo.app.browser.mediaplayback.store.MediaPlaybackDao -import com.duckduckgo.app.browser.mediaplayback.store.MediaPlaybackDatabase import com.duckduckgo.app.browser.pageloadpixel.PageLoadedPixelDao import com.duckduckgo.app.browser.pageloadpixel.firstpaint.PagePaintedPixelDao import com.duckduckgo.app.browser.session.WebViewSessionInMemoryStorage @@ -340,22 +336,6 @@ class BrowserModule { return appDatabase.pagePaintedPixelDao() } - @Provides - @SingleInstanceIn(AppScope::class) - fun provideMediaPlaybackDatabase(context: Context): MediaPlaybackDatabase { - return Room.databaseBuilder(context, MediaPlaybackDatabase::class.java, "media_playback.db") - .enableMultiInstanceInvalidation() - .fallbackToDestructiveMigration() - .addMigrations(*ALL_MIGRATIONS) - .build() - } - - @Provides - @SingleInstanceIn(AppScope::class) - fun providesMediaPlaybackDao(mediaPlaybackDatabase: MediaPlaybackDatabase): MediaPlaybackDao { - return mediaPlaybackDatabase.mediaPlaybackDao() - } - private val Context.indonesiaNewTabSectionDataStore: DataStore by preferencesDataStore( name = "indonesia_new_tab_section_store", ) diff --git a/app/src/main/java/com/duckduckgo/app/browser/mediaplayback/UnusedMediaPlaybackFeatureFeatureCodegenTrigger.kt b/app/src/main/java/com/duckduckgo/app/browser/mediaplayback/UnusedMediaPlaybackFeatureFeatureCodegenTrigger.kt index e6d576c5cb1b..785a67efcf07 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/mediaplayback/UnusedMediaPlaybackFeatureFeatureCodegenTrigger.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/mediaplayback/UnusedMediaPlaybackFeatureFeatureCodegenTrigger.kt @@ -17,13 +17,11 @@ package com.duckduckgo.app.browser.mediaplayback import com.duckduckgo.anvil.annotations.ContributesRemoteFeature -import com.duckduckgo.app.browser.mediaplayback.store.MediaPlaybackStore import com.duckduckgo.di.scopes.AppScope @ContributesRemoteFeature( scope = AppScope::class, featureName = "mediaPlaybackRequiresUserGesture", - exceptionsStore = MediaPlaybackStore::class, boundType = MediaPlaybackFeature::class, ) @Suppress("unused") diff --git a/app/src/main/java/com/duckduckgo/app/browser/mediaplayback/store/MediaPlaybackDao.kt b/app/src/main/java/com/duckduckgo/app/browser/mediaplayback/store/MediaPlaybackDao.kt deleted file mode 100644 index d509ab94b65f..000000000000 --- a/app/src/main/java/com/duckduckgo/app/browser/mediaplayback/store/MediaPlaybackDao.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2024 DuckDuckGo - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.duckduckgo.app.browser.mediaplayback.store - -import androidx.room.Dao -import androidx.room.Insert -import androidx.room.OnConflictStrategy -import androidx.room.Query -import androidx.room.Transaction - -@Dao -abstract class MediaPlaybackDao { - @Insert(onConflict = OnConflictStrategy.REPLACE) - abstract fun insertAll(domains: List) - - @Transaction - open fun updateAll(domains: List) { - deleteAll() - insertAll(domains) - } - - @Query("select * from media_playback_user_gesture_exceptions") - abstract fun getAll(): List - - @Query("delete from media_playback_user_gesture_exceptions") - abstract fun deleteAll() -} diff --git a/app/src/main/java/com/duckduckgo/app/browser/mediaplayback/store/MediaPlaybackDatabase.kt b/app/src/main/java/com/duckduckgo/app/browser/mediaplayback/store/MediaPlaybackDatabase.kt deleted file mode 100644 index 275cfdfa5e59..000000000000 --- a/app/src/main/java/com/duckduckgo/app/browser/mediaplayback/store/MediaPlaybackDatabase.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2024 DuckDuckGo - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.duckduckgo.app.browser.mediaplayback.store - -import androidx.room.Database -import androidx.room.RoomDatabase -import androidx.room.migration.Migration - -@Database( - exportSchema = true, - version = 1, - entities = [ - MediaPlaybackExceptionEntity::class, - ], -) -abstract class MediaPlaybackDatabase : RoomDatabase() { - abstract fun mediaPlaybackDao(): MediaPlaybackDao -} - -val ALL_MIGRATIONS = emptyArray() diff --git a/app/src/main/java/com/duckduckgo/app/browser/mediaplayback/store/MediaPlaybackExceptionEntity.kt b/app/src/main/java/com/duckduckgo/app/browser/mediaplayback/store/MediaPlaybackExceptionEntity.kt deleted file mode 100644 index 66a6e9aff3f9..000000000000 --- a/app/src/main/java/com/duckduckgo/app/browser/mediaplayback/store/MediaPlaybackExceptionEntity.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2024 DuckDuckGo - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.duckduckgo.app.browser.mediaplayback.store - -import androidx.room.Entity -import androidx.room.PrimaryKey -import com.duckduckgo.feature.toggles.api.FeatureExceptions - -@Entity(tableName = "media_playback_user_gesture_exceptions") -data class MediaPlaybackExceptionEntity(@PrimaryKey val domain: String) - -fun MediaPlaybackExceptionEntity.toFeatureException(): FeatureExceptions.FeatureException { - return FeatureExceptions.FeatureException(domain = this.domain, reason = null) -} diff --git a/app/src/main/java/com/duckduckgo/app/browser/mediaplayback/store/MediaPlaybackRepository.kt b/app/src/main/java/com/duckduckgo/app/browser/mediaplayback/store/MediaPlaybackRepository.kt index 829a799b1e17..c97f09906f17 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/mediaplayback/store/MediaPlaybackRepository.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/mediaplayback/store/MediaPlaybackRepository.kt @@ -16,12 +16,15 @@ package com.duckduckgo.app.browser.mediaplayback.store +import com.duckduckgo.app.browser.mediaplayback.MediaPlaybackFeature import com.duckduckgo.app.di.AppCoroutineScope import com.duckduckgo.app.di.IsMainProcess import com.duckduckgo.common.utils.DispatcherProvider import com.duckduckgo.di.scopes.AppScope -import com.duckduckgo.feature.toggles.api.FeatureExceptions +import com.duckduckgo.feature.toggles.api.FeatureException +import com.duckduckgo.privacy.config.api.PrivacyConfigCallbackPlugin import com.squareup.anvil.annotations.ContributesBinding +import com.squareup.anvil.annotations.ContributesMultibinding import dagger.SingleInstanceIn import java.util.concurrent.CopyOnWriteArrayList import javax.inject.Inject @@ -29,38 +32,41 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch interface MediaPlaybackRepository { - fun updateAll(exceptions: List) - val exceptions: CopyOnWriteArrayList + val exceptions: CopyOnWriteArrayList } -@ContributesBinding(AppScope::class) +@ContributesBinding( + scope = AppScope::class, + boundType = MediaPlaybackRepository::class, +) +@ContributesMultibinding( + scope = AppScope::class, + boundType = PrivacyConfigCallbackPlugin::class, +) @SingleInstanceIn(AppScope::class) class RealMediaPlaybackRepository @Inject constructor( - private val mediaPlaybackDao: MediaPlaybackDao, - @AppCoroutineScope appCoroutineScope: CoroutineScope, - dispatcherProvider: DispatcherProvider, - @IsMainProcess isMainProcess: Boolean, -) : MediaPlaybackRepository { + private val mediaPlaybackFeature: MediaPlaybackFeature, + @AppCoroutineScope private val appCoroutineScope: CoroutineScope, + private val dispatcherProvider: DispatcherProvider, + @IsMainProcess private val isMainProcess: Boolean, +) : MediaPlaybackRepository, PrivacyConfigCallbackPlugin { - override val exceptions = CopyOnWriteArrayList() + override val exceptions = CopyOnWriteArrayList() init { - appCoroutineScope.launch(dispatcherProvider.io()) { - if (isMainProcess) { - loadToMemory() - } - } + loadToMemory() } - override fun updateAll(exceptions: List) { - mediaPlaybackDao.updateAll(exceptions) + override fun onPrivacyConfigDownloaded() { loadToMemory() } private fun loadToMemory() { - exceptions.clear() - mediaPlaybackDao.getAll().map { - exceptions.add(it.toFeatureException()) + appCoroutineScope.launch(dispatcherProvider.io()) { + if (isMainProcess) { + exceptions.clear() + exceptions.addAll(mediaPlaybackFeature.self().getExceptions()) + } } } } diff --git a/app/src/main/java/com/duckduckgo/app/browser/mediaplayback/store/MediaPlaybackStore.kt b/app/src/main/java/com/duckduckgo/app/browser/mediaplayback/store/MediaPlaybackStore.kt deleted file mode 100644 index bef97d1fd1d8..000000000000 --- a/app/src/main/java/com/duckduckgo/app/browser/mediaplayback/store/MediaPlaybackStore.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2024 DuckDuckGo - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.duckduckgo.app.browser.mediaplayback.store - -import com.duckduckgo.app.browser.mediaplayback.MediaPlaybackFeature -import com.duckduckgo.di.scopes.AppScope -import com.duckduckgo.feature.toggles.api.FeatureExceptions -import com.duckduckgo.feature.toggles.api.RemoteFeatureStoreNamed -import com.squareup.anvil.annotations.ContributesBinding -import javax.inject.Inject - -@ContributesBinding(AppScope::class) -@RemoteFeatureStoreNamed(MediaPlaybackFeature::class) -class MediaPlaybackStore @Inject constructor( - private val mediaPlaybackRepository: MediaPlaybackRepository, -) : FeatureExceptions.Store { - override fun insertAll(exception: List) { - mediaPlaybackRepository.updateAll( - exception.map { MediaPlaybackExceptionEntity(domain = it.domain) }, - ) - } -} diff --git a/app/src/test/java/com/duckduckgo/app/browser/mediaplayback/store/RealMediaPlaybackRepositoryTest.kt b/app/src/test/java/com/duckduckgo/app/browser/mediaplayback/store/RealMediaPlaybackRepositoryTest.kt index ef75ef8172bc..7fff9c7934f9 100644 --- a/app/src/test/java/com/duckduckgo/app/browser/mediaplayback/store/RealMediaPlaybackRepositoryTest.kt +++ b/app/src/test/java/com/duckduckgo/app/browser/mediaplayback/store/RealMediaPlaybackRepositoryTest.kt @@ -1,81 +1,56 @@ package com.duckduckgo.app.browser.mediaplayback.store +import com.duckduckgo.app.browser.mediaplayback.MediaPlaybackFeature import com.duckduckgo.common.test.CoroutineTestRule +import com.duckduckgo.feature.toggles.api.FakeFeatureToggleFactory +import com.duckduckgo.feature.toggles.api.FeatureException +import com.duckduckgo.feature.toggles.api.Toggle import junit.framework.TestCase.assertEquals import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Rule import org.junit.Test -import org.mockito.ArgumentMatchers.anyList -import org.mockito.kotlin.mock -import org.mockito.kotlin.reset -import org.mockito.kotlin.verify -import org.mockito.kotlin.whenever class RealMediaPlaybackRepositoryTest { @get:Rule var coroutineRule = CoroutineTestRule() - lateinit var testee: RealMediaPlaybackRepository - - private val mockMediaPlaybackDatabase: MediaPlaybackDatabase = mock() - private val mockMediaPlaybackDao: MediaPlaybackDao = mock() + private val mediaPlaybackFeature = FakeFeatureToggleFactory.create(MediaPlaybackFeature::class.java) @Before fun before() { - whenever(mockMediaPlaybackDatabase.mediaPlaybackDao()).thenReturn(mockMediaPlaybackDao) - initRepository() + mediaPlaybackFeature.self().setRawStoredState(Toggle.State(exceptions = exceptions)) } @Test fun whenRepositoryIsCreatedThenValuesLoadedIntoMemory() { - givenMediaPlaybackDaoContainsEntities() - - initRepository() - - assertEquals(mediaPlaybackExceptionEntity.toFeatureException(), testee.exceptions.first()) - } - - @Test - fun whenUpdateAllThenUpdateAllCalled() = runTest { - initRepository() - - testee.updateAll(listOf()) + val repository = RealMediaPlaybackRepository( + mediaPlaybackFeature, + TestScope(), + coroutineRule.testDispatcherProvider, + isMainProcess = true, + ) - verify(mockMediaPlaybackDao).updateAll(anyList()) + assertEquals(exceptions, repository.exceptions) } @Test - fun whenUpdateAllThenPreviousValuesAreClearedAndNewValuesUpdated() = runTest { - givenMediaPlaybackDaoContainsEntities() - - initRepository() - assertEquals(1, testee.exceptions.size) - - reset(mockMediaPlaybackDao) - - testee.updateAll(listOf()) - - assertEquals(0, testee.exceptions.size) - } - - private fun initRepository() { - testee = RealMediaPlaybackRepository( - mockMediaPlaybackDao, + fun whenRemoteConfigUpdateThenExceptionsUpdated() = runTest { + val repository = RealMediaPlaybackRepository( + mediaPlaybackFeature, TestScope(), coroutineRule.testDispatcherProvider, isMainProcess = true, ) - } - private fun givenMediaPlaybackDaoContainsEntities() { - whenever(mockMediaPlaybackDao.getAll()).thenReturn(listOf(mediaPlaybackExceptionEntity)) + assertEquals(exceptions, repository.exceptions) + mediaPlaybackFeature.self().setRawStoredState(Toggle.State(exceptions = emptyList())) + repository.onPrivacyConfigDownloaded() + assertEquals(emptyList(), repository.exceptions) } companion object { - val mediaPlaybackExceptionEntity = MediaPlaybackExceptionEntity( - domain = "example.com", - ) + val exceptions = listOf(FeatureException("example.com", "reason")) } } diff --git a/autoconsent/autoconsent-impl/src/main/java/com/duckduckgo/autoconsent/impl/di/AutoconsentModule.kt b/autoconsent/autoconsent-impl/src/main/java/com/duckduckgo/autoconsent/impl/di/AutoconsentModule.kt index d51c56ad376a..7b7dbde21ed2 100644 --- a/autoconsent/autoconsent-impl/src/main/java/com/duckduckgo/autoconsent/impl/di/AutoconsentModule.kt +++ b/autoconsent/autoconsent-impl/src/main/java/com/duckduckgo/autoconsent/impl/di/AutoconsentModule.kt @@ -20,10 +20,8 @@ import android.content.Context import androidx.room.Room import com.duckduckgo.app.di.AppCoroutineScope import com.duckduckgo.app.di.IsMainProcess -import com.duckduckgo.autoconsent.impl.remoteconfig.AutoconsentExceptionsRepository import com.duckduckgo.autoconsent.impl.remoteconfig.AutoconsentFeature import com.duckduckgo.autoconsent.impl.remoteconfig.AutoconsentFeatureSettingsRepository -import com.duckduckgo.autoconsent.impl.remoteconfig.RealAutoconsentExceptionsRepository import com.duckduckgo.autoconsent.impl.remoteconfig.RealAutoconsentFeatureSettingsRepository import com.duckduckgo.autoconsent.impl.store.AutoconsentDatabase import com.duckduckgo.autoconsent.impl.store.AutoconsentSettingsRepository @@ -58,17 +56,6 @@ object AutoconsentModule { .build() } - @SingleInstanceIn(AppScope::class) - @Provides - fun provideAutoconsentExceptionsRepository( - database: AutoconsentDatabase, - @AppCoroutineScope appCoroutineScope: CoroutineScope, - dispatcherProvider: DispatcherProvider, - @IsMainProcess isMainProcess: Boolean, - ): AutoconsentExceptionsRepository { - return RealAutoconsentExceptionsRepository(appCoroutineScope, dispatcherProvider, database, isMainProcess) - } - @SingleInstanceIn(AppScope::class) @Provides fun provideAutoconsentFeatureSettingsRepository( diff --git a/autoconsent/autoconsent-impl/src/main/java/com/duckduckgo/autoconsent/impl/remoteconfig/AutoconsentExceptionsRepository.kt b/autoconsent/autoconsent-impl/src/main/java/com/duckduckgo/autoconsent/impl/remoteconfig/AutoconsentExceptionsRepository.kt index 414db2c3bed6..08291dd28911 100644 --- a/autoconsent/autoconsent-impl/src/main/java/com/duckduckgo/autoconsent/impl/remoteconfig/AutoconsentExceptionsRepository.kt +++ b/autoconsent/autoconsent-impl/src/main/java/com/duckduckgo/autoconsent/impl/remoteconfig/AutoconsentExceptionsRepository.kt @@ -16,45 +16,56 @@ package com.duckduckgo.autoconsent.impl.remoteconfig -import com.duckduckgo.autoconsent.impl.store.AutoconsentDatabase -import com.duckduckgo.autoconsent.impl.store.AutoconsentExceptionEntity +import com.duckduckgo.app.di.AppCoroutineScope +import com.duckduckgo.app.di.IsMainProcess import com.duckduckgo.common.utils.DispatcherProvider -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.di.scopes.AppScope +import com.duckduckgo.feature.toggles.api.FeatureException +import com.duckduckgo.privacy.config.api.PrivacyConfigCallbackPlugin +import com.squareup.anvil.annotations.ContributesBinding +import com.squareup.anvil.annotations.ContributesMultibinding +import dagger.SingleInstanceIn import java.util.concurrent.CopyOnWriteArrayList +import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch interface AutoconsentExceptionsRepository { - fun insertAllExceptions(exceptions: List) val exceptions: CopyOnWriteArrayList } -class RealAutoconsentExceptionsRepository( - coroutineScope: CoroutineScope, - dispatcherProvider: DispatcherProvider, - val database: AutoconsentDatabase, - isMainProcess: Boolean, -) : AutoconsentExceptionsRepository { +@SingleInstanceIn(AppScope::class) +@ContributesBinding( + scope = AppScope::class, + boundType = AutoconsentExceptionsRepository::class, +) +@ContributesMultibinding( + scope = AppScope::class, + boundType = PrivacyConfigCallbackPlugin::class, +) +class RealAutoconsentExceptionsRepository @Inject constructor( + @AppCoroutineScope private val coroutineScope: CoroutineScope, + private val dispatcherProvider: DispatcherProvider, + private val autoconsentFeature: AutoconsentFeature, + @IsMainProcess private val isMainProcess: Boolean, +) : AutoconsentExceptionsRepository, PrivacyConfigCallbackPlugin { - private val dao = database.autoconsentDao() override val exceptions = CopyOnWriteArrayList() init { + loadToMemory() + } + + private fun loadToMemory() { coroutineScope.launch(dispatcherProvider.io()) { if (isMainProcess) { - loadToMemory() + exceptions.clear() + exceptions.addAll(autoconsentFeature.self().getExceptions()) } } } - override fun insertAllExceptions(exceptions: List) { - dao.updateAllExceptions(exceptions.map { AutoconsentExceptionEntity(domain = it.domain, reason = it.reason ?: "") }) + override fun onPrivacyConfigDownloaded() { loadToMemory() } - - private fun loadToMemory() { - exceptions.clear() - val exceptionsEntityList = dao.getExceptions() - exceptions.addAll(exceptionsEntityList.map { FeatureException(domain = it.domain, reason = it.reason) }) - } } diff --git a/autoconsent/autoconsent-impl/src/main/java/com/duckduckgo/autoconsent/impl/remoteconfig/AutoconsentExceptionsStore.kt b/autoconsent/autoconsent-impl/src/main/java/com/duckduckgo/autoconsent/impl/remoteconfig/AutoconsentExceptionsStore.kt deleted file mode 100644 index 818c25d44048..000000000000 --- a/autoconsent/autoconsent-impl/src/main/java/com/duckduckgo/autoconsent/impl/remoteconfig/AutoconsentExceptionsStore.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2024 DuckDuckGo - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.duckduckgo.autoconsent.impl.remoteconfig - -import com.duckduckgo.di.scopes.AppScope -import com.duckduckgo.feature.toggles.api.FeatureExceptions -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException -import com.duckduckgo.feature.toggles.api.RemoteFeatureStoreNamed -import com.squareup.anvil.annotations.ContributesBinding -import javax.inject.Inject - -@ContributesBinding(AppScope::class) -@RemoteFeatureStoreNamed(AutoconsentFeature::class) -class AutoconsentExceptionsStore @Inject constructor( - val autoconsentExceptionsRepository: AutoconsentExceptionsRepository, -) : FeatureExceptions.Store { - override fun insertAll(exception: List) { - autoconsentExceptionsRepository.insertAllExceptions(exception) - } -} diff --git a/autoconsent/autoconsent-impl/src/main/java/com/duckduckgo/autoconsent/impl/remoteconfig/AutoconsentFeature.kt b/autoconsent/autoconsent-impl/src/main/java/com/duckduckgo/autoconsent/impl/remoteconfig/AutoconsentFeature.kt index e673a66bc2b2..329acc87a723 100644 --- a/autoconsent/autoconsent-impl/src/main/java/com/duckduckgo/autoconsent/impl/remoteconfig/AutoconsentFeature.kt +++ b/autoconsent/autoconsent-impl/src/main/java/com/duckduckgo/autoconsent/impl/remoteconfig/AutoconsentFeature.kt @@ -25,7 +25,6 @@ import com.duckduckgo.feature.toggles.api.Toggle.DefaultFeatureValue scope = AppScope::class, featureName = "autoconsent", settingsStore = AutoconsentFeatureSettingsStore::class, - exceptionsStore = AutoconsentExceptionsStore::class, ) /** * This is the class that represents the autoconsent feature flags diff --git a/autoconsent/autoconsent-impl/src/main/java/com/duckduckgo/autoconsent/impl/store/AutoconsentDao.kt b/autoconsent/autoconsent-impl/src/main/java/com/duckduckgo/autoconsent/impl/store/AutoconsentDao.kt index a02f49ae9187..6359bc80f41d 100644 --- a/autoconsent/autoconsent-impl/src/main/java/com/duckduckgo/autoconsent/impl/store/AutoconsentDao.kt +++ b/autoconsent/autoconsent-impl/src/main/java/com/duckduckgo/autoconsent/impl/store/AutoconsentDao.kt @@ -28,38 +28,15 @@ abstract class AutoconsentDao { @Insert(onConflict = OnConflictStrategy.REPLACE) abstract fun insertDisabledCmps(disabledCmps: List) - @Insert(onConflict = OnConflictStrategy.REPLACE) - abstract fun insertExceptions(exceptions: List) - - @Transaction - open fun updateAll(exceptions: List, disabledCmps: List) { - deleteDisabledCmps() - deleteExceptions() - insertDisabledCmps(disabledCmps) - insertExceptions(exceptions) - } - @Transaction open fun updateAllDisabledCMPs(disabledCMPs: List) { deleteDisabledCmps() insertDisabledCmps(disabledCMPs) } - @Transaction - open fun updateAllExceptions(exceptions: List) { - deleteExceptions() - insertExceptions(exceptions) - } - - @Query("select * from autoconsent_exceptions") - abstract fun getExceptions(): List - @Query("select * from autoconsent_disabled_cmps") abstract fun getDisabledCmps(): List @Query("delete from autoconsent_disabled_cmps") abstract fun deleteDisabledCmps() - - @Query("delete from autoconsent_exceptions") - abstract fun deleteExceptions() } diff --git a/autoconsent/autoconsent-impl/src/main/java/com/duckduckgo/autoconsent/impl/store/AutoconsentDatabase.kt b/autoconsent/autoconsent-impl/src/main/java/com/duckduckgo/autoconsent/impl/store/AutoconsentDatabase.kt index 8777fc2310e2..8970405f9a8d 100644 --- a/autoconsent/autoconsent-impl/src/main/java/com/duckduckgo/autoconsent/impl/store/AutoconsentDatabase.kt +++ b/autoconsent/autoconsent-impl/src/main/java/com/duckduckgo/autoconsent/impl/store/AutoconsentDatabase.kt @@ -21,9 +21,8 @@ import androidx.room.RoomDatabase @Database( exportSchema = true, - version = 1, + version = 2, entities = [ - AutoconsentExceptionEntity::class, DisabledCmpsEntity::class, ], ) diff --git a/autoconsent/autoconsent-impl/src/main/java/com/duckduckgo/autoconsent/impl/store/AutoconsentDatabaseModels.kt b/autoconsent/autoconsent-impl/src/main/java/com/duckduckgo/autoconsent/impl/store/AutoconsentDatabaseModels.kt index 7818fdc8d47f..a4724d9ad914 100644 --- a/autoconsent/autoconsent-impl/src/main/java/com/duckduckgo/autoconsent/impl/store/AutoconsentDatabaseModels.kt +++ b/autoconsent/autoconsent-impl/src/main/java/com/duckduckgo/autoconsent/impl/store/AutoconsentDatabaseModels.kt @@ -18,17 +18,6 @@ package com.duckduckgo.autoconsent.impl.store import androidx.room.Entity import androidx.room.PrimaryKey -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException - -@Entity(tableName = "autoconsent_exceptions") -data class AutoconsentExceptionEntity( - @PrimaryKey val domain: String, - val reason: String, -) - -fun AutoconsentExceptionEntity.toFeatureException(): FeatureException { - return FeatureException(domain = this.domain, reason = this.reason) -} @Entity(tableName = "autoconsent_disabled_cmps") data class DisabledCmpsEntity( diff --git a/autoconsent/autoconsent-impl/src/test/java/com/duckduckgo/autoconsent/impl/Fakes.kt b/autoconsent/autoconsent-impl/src/test/java/com/duckduckgo/autoconsent/impl/Fakes.kt index b5d556b7628d..69f61d45d708 100644 --- a/autoconsent/autoconsent-impl/src/test/java/com/duckduckgo/autoconsent/impl/Fakes.kt +++ b/autoconsent/autoconsent-impl/src/test/java/com/duckduckgo/autoconsent/impl/Fakes.kt @@ -24,7 +24,7 @@ import com.duckduckgo.autoconsent.api.AutoconsentCallback import com.duckduckgo.autoconsent.impl.store.AutoconsentSettingsRepository import com.duckduckgo.common.utils.domain import com.duckduckgo.common.utils.plugins.PluginPoint -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import com.duckduckgo.privacy.config.api.UnprotectedTemporary import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf diff --git a/autoconsent/autoconsent-impl/src/test/java/com/duckduckgo/autoconsent/impl/RealAutoconsentTest.kt b/autoconsent/autoconsent-impl/src/test/java/com/duckduckgo/autoconsent/impl/RealAutoconsentTest.kt index 07b3cf4f1009..f40f4e841f84 100644 --- a/autoconsent/autoconsent-impl/src/test/java/com/duckduckgo/autoconsent/impl/RealAutoconsentTest.kt +++ b/autoconsent/autoconsent-impl/src/test/java/com/duckduckgo/autoconsent/impl/RealAutoconsentTest.kt @@ -21,7 +21,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry import com.duckduckgo.autoconsent.impl.remoteconfig.AutoconsentExceptionsRepository import com.duckduckgo.autoconsent.impl.remoteconfig.AutoconsentFeature -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import com.duckduckgo.feature.toggles.api.Toggle import java.util.concurrent.CopyOnWriteArrayList import org.junit.Assert.* diff --git a/autoconsent/autoconsent-impl/src/test/java/com/duckduckgo/autoconsent/impl/remoteconfig/RealAutoconsentExceptionsRepositoryTest.kt b/autoconsent/autoconsent-impl/src/test/java/com/duckduckgo/autoconsent/impl/remoteconfig/RealAutoconsentExceptionsRepositoryTest.kt index b158c37963b1..dfb2abddd886 100644 --- a/autoconsent/autoconsent-impl/src/test/java/com/duckduckgo/autoconsent/impl/remoteconfig/RealAutoconsentExceptionsRepositoryTest.kt +++ b/autoconsent/autoconsent-impl/src/test/java/com/duckduckgo/autoconsent/impl/remoteconfig/RealAutoconsentExceptionsRepositoryTest.kt @@ -16,74 +16,55 @@ package com.duckduckgo.autoconsent.impl.remoteconfig -import com.duckduckgo.autoconsent.impl.store.AutoconsentDao -import com.duckduckgo.autoconsent.impl.store.AutoconsentDatabase -import com.duckduckgo.autoconsent.impl.store.AutoconsentExceptionEntity -import com.duckduckgo.autoconsent.impl.store.toFeatureException +import android.annotation.SuppressLint import com.duckduckgo.common.test.CoroutineTestRule +import com.duckduckgo.feature.toggles.api.FakeFeatureToggleFactory +import com.duckduckgo.feature.toggles.api.FeatureException +import com.duckduckgo.feature.toggles.api.Toggle import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest -import org.junit.Assert.* -import org.junit.Before +import org.junit.Assert.assertEquals import org.junit.Rule import org.junit.Test -import org.mockito.ArgumentMatchers.anyList -import org.mockito.kotlin.mock -import org.mockito.kotlin.reset -import org.mockito.kotlin.verify -import org.mockito.kotlin.whenever +@SuppressLint("DenyListedApi") // setRawStoredState class RealAutoconsentExceptionsRepositoryTest { @get:Rule var coroutineRule = CoroutineTestRule() - private val mockDatabase: AutoconsentDatabase = mock() - private val mockDao: AutoconsentDao = mock() - - lateinit var repository: AutoconsentExceptionsRepository - - @Before - fun before() { - whenever(mockDatabase.autoconsentDao()).thenReturn(mockDao) - } - - @Test - fun whenRepositoryIsCreatedThenExceptionsLoadedIntoMemory() { - givenDaoContainsExceptions() - - repository = RealAutoconsentExceptionsRepository(TestScope(), coroutineRule.testDispatcherProvider, mockDatabase, isMainProcess = true) - - assertEquals(exception.toFeatureException(), repository.exceptions.first()) + private val autoconsentFeature: AutoconsentFeature = FakeFeatureToggleFactory.create(AutoconsentFeature::class.java).apply { + self().setRawStoredState(Toggle.State(exceptions = exceptions)) } @Test - fun whenUpdateAllThenUpdateAllCalled() = runTest { - repository = RealAutoconsentExceptionsRepository(TestScope(), coroutineRule.testDispatcherProvider, mockDatabase, isMainProcess = true) - - repository.insertAllExceptions(listOf()) - - verify(mockDao).updateAllExceptions(anyList()) + fun whenRepositoryIsCreatedThenExceptionsLoadedIntoMemory() = runTest { + val repository = RealAutoconsentExceptionsRepository( + TestScope(), + coroutineRule.testDispatcherProvider, + autoconsentFeature, + isMainProcess = true, + ) + + assertEquals(exceptions, repository.exceptions) } @Test - fun whenUpdateAllThenPreviousExceptionsAreCleared() = runTest { - givenDaoContainsExceptions() - repository = RealAutoconsentExceptionsRepository(TestScope(), coroutineRule.testDispatcherProvider, mockDatabase, isMainProcess = true) - - assertEquals(1, repository.exceptions.size) - reset(mockDao) - - repository.insertAllExceptions(listOf()) - - assertEquals(0, repository.exceptions.size) - } - - private fun givenDaoContainsExceptions() { - whenever(mockDao.getExceptions()).thenReturn(listOf(exception)) + fun whenRemoteConfigUpdateThenExceptionsUpdated() = runTest { + val repository = RealAutoconsentExceptionsRepository( + TestScope(), + coroutineRule.testDispatcherProvider, + autoconsentFeature, + isMainProcess = true, + ) + + assertEquals(exceptions, repository.exceptions) + autoconsentFeature.self().setRawStoredState(Toggle.State(exceptions = emptyList())) + repository.onPrivacyConfigDownloaded() + assertEquals(emptyList(), repository.exceptions) } companion object { - val exception = AutoconsentExceptionEntity("example.com", "reason") + val exceptions = listOf(FeatureException("example.com", "reason")) } } diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/RealAutofill.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/RealAutofill.kt index 6e814725a4a4..dffa44dbcac9 100644 --- a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/RealAutofill.kt +++ b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/RealAutofill.kt @@ -18,7 +18,7 @@ package com.duckduckgo.autofill.impl import com.duckduckgo.app.browser.UriString.Companion.sameOrSubdomain import com.duckduckgo.autofill.api.Autofill -import com.duckduckgo.autofill.store.feature.AutofillFeatureRepository +import com.duckduckgo.autofill.impl.feature.plugin.AutofillFeatureRepository import com.duckduckgo.di.scopes.AppScope import com.duckduckgo.privacy.config.api.UnprotectedTemporary import com.squareup.anvil.annotations.ContributesBinding diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/di/AutofillModule.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/di/AutofillModule.kt index 7259323e5520..42fb473b2437 100644 --- a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/di/AutofillModule.kt +++ b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/di/AutofillModule.kt @@ -19,8 +19,6 @@ package com.duckduckgo.autofill.impl.di import android.content.Context import androidx.room.Room import com.duckduckgo.anvil.annotations.ContributesPluginPoint -import com.duckduckgo.app.di.AppCoroutineScope -import com.duckduckgo.app.di.IsMainProcess import com.duckduckgo.autofill.api.AutofillFeature import com.duckduckgo.autofill.api.AutofillFragmentResultsPlugin import com.duckduckgo.autofill.api.InternalTestUserChecker @@ -39,24 +37,16 @@ import com.duckduckgo.autofill.store.RealInternalTestUserStore import com.duckduckgo.autofill.store.RealLastUpdatedTimeProvider import com.duckduckgo.autofill.store.engagement.AutofillEngagementDatabase import com.duckduckgo.autofill.store.feature.AutofillDefaultStateDecider -import com.duckduckgo.autofill.store.feature.AutofillFeatureRepository import com.duckduckgo.autofill.store.feature.RealAutofillDefaultStateDecider -import com.duckduckgo.autofill.store.feature.RealAutofillFeatureRepository -import com.duckduckgo.autofill.store.feature.email.incontext.ALL_MIGRATIONS as EmailInContextMigrations -import com.duckduckgo.autofill.store.feature.email.incontext.EmailProtectionInContextDatabase -import com.duckduckgo.autofill.store.feature.email.incontext.EmailProtectionInContextFeatureRepository -import com.duckduckgo.autofill.store.feature.email.incontext.RealEmailProtectionInContextFeatureRepository import com.duckduckgo.autofill.store.targets.DomainTargetAppDao import com.duckduckgo.autofill.store.targets.DomainTargetAppsDatabase import com.duckduckgo.browser.api.UserBrowserProperties -import com.duckduckgo.common.utils.DispatcherProvider import com.duckduckgo.di.scopes.ActivityScope import com.duckduckgo.di.scopes.AppScope import com.squareup.anvil.annotations.ContributesTo import dagger.Module import dagger.Provides import dagger.SingleInstanceIn -import kotlinx.coroutines.CoroutineScope @Module @ContributesTo(AppScope::class) @@ -103,37 +93,6 @@ class AutofillModule { .build() } - @SingleInstanceIn(AppScope::class) - @Provides - fun provideEmailInContextDatabase(context: Context): EmailProtectionInContextDatabase { - return Room.databaseBuilder(context, EmailProtectionInContextDatabase::class.java, "emailInContext.db") - .fallbackToDestructiveMigration() - .addMigrations(*EmailInContextMigrations) - .build() - } - - @SingleInstanceIn(AppScope::class) - @Provides - fun provideAutofillRepository( - database: AutofillDatabase, - @AppCoroutineScope appCoroutineScope: CoroutineScope, - dispatcherProvider: DispatcherProvider, - @IsMainProcess isMainProcess: Boolean, - ): AutofillFeatureRepository { - return RealAutofillFeatureRepository(database, appCoroutineScope, dispatcherProvider, isMainProcess) - } - - @SingleInstanceIn(AppScope::class) - @Provides - fun provideEmailInContextRepository( - database: EmailProtectionInContextDatabase, - @AppCoroutineScope appCoroutineScope: CoroutineScope, - dispatcherProvider: DispatcherProvider, - @IsMainProcess isMainProcess: Boolean, - ): EmailProtectionInContextFeatureRepository { - return RealEmailProtectionInContextFeatureRepository(database, appCoroutineScope, dispatcherProvider, isMainProcess) - } - @Provides @SingleInstanceIn(AppScope::class) fun providesCredentialsSyncDao( diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/email/remoteconfig/EmailProtectionInContextExceptionsImpl.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/email/remoteconfig/EmailProtectionInContextExceptionsImpl.kt index 8b3048c6194d..90306c8d122b 100644 --- a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/email/remoteconfig/EmailProtectionInContextExceptionsImpl.kt +++ b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/email/remoteconfig/EmailProtectionInContextExceptionsImpl.kt @@ -17,7 +17,6 @@ package com.duckduckgo.autofill.impl.email.remoteconfig import com.duckduckgo.app.browser.UriString.Companion.sameOrSubdomain -import com.duckduckgo.autofill.store.feature.email.incontext.EmailProtectionInContextFeatureRepository import com.duckduckgo.di.scopes.AppScope import com.squareup.anvil.annotations.ContributesBinding import dagger.SingleInstanceIn diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/email/remoteconfig/EmailProtectionInContextFeatureRepository.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/email/remoteconfig/EmailProtectionInContextFeatureRepository.kt new file mode 100644 index 000000000000..f8afda0071b8 --- /dev/null +++ b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/email/remoteconfig/EmailProtectionInContextFeatureRepository.kt @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2025 DuckDuckGo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.duckduckgo.autofill.impl.email.remoteconfig + +import com.duckduckgo.app.di.AppCoroutineScope +import com.duckduckgo.app.di.IsMainProcess +import com.duckduckgo.autofill.impl.email.incontext.EmailProtectionInContextSignupFeature +import com.duckduckgo.common.utils.DispatcherProvider +import com.duckduckgo.di.scopes.AppScope +import com.duckduckgo.privacy.config.api.PrivacyConfigCallbackPlugin +import com.squareup.anvil.annotations.ContributesBinding +import com.squareup.anvil.annotations.ContributesMultibinding +import dagger.SingleInstanceIn +import java.util.concurrent.CopyOnWriteArrayList +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch + +interface EmailProtectionInContextFeatureRepository { + val exceptions: CopyOnWriteArrayList +} + +@ContributesBinding( + scope = AppScope::class, + boundType = EmailProtectionInContextFeatureRepository::class, +) +@ContributesMultibinding( + scope = AppScope::class, + boundType = PrivacyConfigCallbackPlugin::class, +) +@SingleInstanceIn(AppScope::class) +class RealEmailProtectionInContextFeatureRepository @Inject constructor( + private val feature: EmailProtectionInContextSignupFeature, + @AppCoroutineScope private val coroutineScope: CoroutineScope, + private val dispatcherProvider: DispatcherProvider, + @IsMainProcess private val isMainProcess: Boolean, +) : EmailProtectionInContextFeatureRepository, PrivacyConfigCallbackPlugin { + + override val exceptions = CopyOnWriteArrayList() + + init { + loadToMemory() + } + + override fun onPrivacyConfigDownloaded() { + loadToMemory() + } + + private fun loadToMemory() { + coroutineScope.launch(dispatcherProvider.io()) { + if (isMainProcess) { + exceptions.clear() + exceptions.addAll(feature.self().getExceptions().map { it.domain }) + } + } + } +} diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/email/remoteconfig/EmailProtectionInContextRemoteExceptionsPersister.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/email/remoteconfig/EmailProtectionInContextRemoteExceptionsPersister.kt deleted file mode 100644 index f9eec8266f97..000000000000 --- a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/email/remoteconfig/EmailProtectionInContextRemoteExceptionsPersister.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2023 DuckDuckGo - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.duckduckgo.autofill.impl.email.remoteconfig - -import com.duckduckgo.autofill.impl.email.incontext.EmailProtectionInContextSignupFeature -import com.duckduckgo.autofill.store.feature.email.incontext.EmailInContextExceptionEntity -import com.duckduckgo.autofill.store.feature.email.incontext.EmailProtectionInContextFeatureRepository -import com.duckduckgo.di.scopes.AppScope -import com.duckduckgo.feature.toggles.api.FeatureExceptions -import com.duckduckgo.feature.toggles.api.RemoteFeatureStoreNamed -import com.squareup.anvil.annotations.ContributesBinding -import javax.inject.Inject - -@ContributesBinding(AppScope::class) -@RemoteFeatureStoreNamed(EmailProtectionInContextSignupFeature::class) -class EmailProtectionInContextRemoteExceptionsPersister @Inject constructor( - private val emailProtectionFeatureRepository: EmailProtectionInContextFeatureRepository, -) : FeatureExceptions.Store { - override fun insertAll(exception: List) { - emailProtectionFeatureRepository.updateAllExceptions( - exception.map { EmailInContextExceptionEntity(domain = it.domain, reason = it.reason.orEmpty()) }, - ) - } -} diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/email/remoteconfig/UnusedEmailProtectionInContextSignupRemoteFeatureCodegenTrigger.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/email/remoteconfig/UnusedEmailProtectionInContextSignupRemoteFeatureCodegenTrigger.kt index 4b2a72111079..890f8d91b87b 100644 --- a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/email/remoteconfig/UnusedEmailProtectionInContextSignupRemoteFeatureCodegenTrigger.kt +++ b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/email/remoteconfig/UnusedEmailProtectionInContextSignupRemoteFeatureCodegenTrigger.kt @@ -25,7 +25,6 @@ import com.duckduckgo.di.scopes.AppScope boundType = EmailProtectionInContextSignupFeature::class, featureName = "incontextSignup", settingsStore = EmailProtectionInContextRemoteSettingsPersister::class, - exceptionsStore = EmailProtectionInContextRemoteExceptionsPersister::class, ) @Suppress("unused") private interface UnusedEmailProtectionInContextSignupRemoteFeatureCodegenTrigger diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/feature/plugin/AutofillFeatureExceptionStore.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/feature/plugin/AutofillFeatureExceptionStore.kt deleted file mode 100644 index 057877f93fbb..000000000000 --- a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/feature/plugin/AutofillFeatureExceptionStore.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2023 DuckDuckGo - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.duckduckgo.autofill.impl.feature.plugin - -import com.duckduckgo.autofill.api.AutofillFeature -import com.duckduckgo.autofill.store.AutofillExceptionEntity -import com.duckduckgo.autofill.store.feature.AutofillFeatureRepository -import com.duckduckgo.di.scopes.AppScope -import com.duckduckgo.feature.toggles.api.FeatureExceptions -import com.duckduckgo.feature.toggles.api.RemoteFeatureStoreNamed -import com.squareup.anvil.annotations.ContributesBinding -import javax.inject.Inject - -@ContributesBinding(AppScope::class) -@RemoteFeatureStoreNamed(AutofillFeature::class) -class AutofillFeatureExceptionStore @Inject constructor( - private val autofillFeatureRepository: AutofillFeatureRepository, -) : FeatureExceptions.Store { - override fun insertAll(exception: List) { - autofillFeatureRepository.updateAllExceptions( - exception.map { AutofillExceptionEntity(domain = it.domain, reason = it.reason.orEmpty()) }, - ) - } -} diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/feature/plugin/AutofillFeatureRepository.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/feature/plugin/AutofillFeatureRepository.kt new file mode 100644 index 000000000000..52df0273e999 --- /dev/null +++ b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/feature/plugin/AutofillFeatureRepository.kt @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2025 DuckDuckGo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.duckduckgo.autofill.impl.feature.plugin + +import com.duckduckgo.app.di.AppCoroutineScope +import com.duckduckgo.app.di.IsMainProcess +import com.duckduckgo.autofill.api.AutofillFeature +import com.duckduckgo.common.utils.DispatcherProvider +import com.duckduckgo.di.scopes.AppScope +import com.duckduckgo.feature.toggles.api.FeatureException +import com.duckduckgo.privacy.config.api.PrivacyConfigCallbackPlugin +import com.squareup.anvil.annotations.ContributesBinding +import com.squareup.anvil.annotations.ContributesMultibinding +import dagger.SingleInstanceIn +import java.util.concurrent.CopyOnWriteArrayList +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch + +interface AutofillFeatureRepository { + val exceptions: CopyOnWriteArrayList +} + +@ContributesMultibinding( + scope = AppScope::class, + boundType = PrivacyConfigCallbackPlugin::class, +) +@ContributesBinding( + scope = AppScope::class, + boundType = AutofillFeatureRepository::class, +) +@SingleInstanceIn(AppScope::class) +class RealAutofillFeatureRepository @Inject constructor( + private val feature: AutofillFeature, + @AppCoroutineScope private val coroutineScope: CoroutineScope, + private val dispatcherProvider: DispatcherProvider, + @IsMainProcess private val isMainProcess: Boolean, +) : AutofillFeatureRepository, PrivacyConfigCallbackPlugin { + + override val exceptions = CopyOnWriteArrayList() + + init { + loadToMemory() + } + + override fun onPrivacyConfigDownloaded() { + loadToMemory() + } + + private fun loadToMemory() { + coroutineScope.launch(dispatcherProvider.io()) { + if (isMainProcess) { + exceptions.clear() + exceptions.addAll(feature.self().getExceptions()) + } + } + } +} diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/feature/plugin/UnusedAutofillRemoteFeatureCodegenTrigger.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/feature/plugin/UnusedAutofillRemoteFeatureCodegenTrigger.kt index c09dca48523e..e1b5d71d14b5 100644 --- a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/feature/plugin/UnusedAutofillRemoteFeatureCodegenTrigger.kt +++ b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/feature/plugin/UnusedAutofillRemoteFeatureCodegenTrigger.kt @@ -24,7 +24,6 @@ import com.duckduckgo.di.scopes.AppScope scope = AppScope::class, boundType = AutofillFeature::class, featureName = "autofill", - exceptionsStore = AutofillFeatureExceptionStore::class, ) @Suppress("unused") private interface UnusedAutofillRemoteFeatureCodegenTrigger diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/reporting/AutofillBreakageReportCanShowRules.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/reporting/AutofillBreakageReportCanShowRules.kt index 6224ef28b229..8f93acfbfb88 100644 --- a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/reporting/AutofillBreakageReportCanShowRules.kt +++ b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/reporting/AutofillBreakageReportCanShowRules.kt @@ -17,9 +17,9 @@ package com.duckduckgo.autofill.impl.reporting import com.duckduckgo.autofill.impl.reporting.remoteconfig.AutofillSiteBreakageReportingFeature +import com.duckduckgo.autofill.impl.reporting.remoteconfig.AutofillSiteBreakageReportingFeatureRepository import com.duckduckgo.autofill.impl.time.TimeProvider import com.duckduckgo.autofill.impl.urlmatcher.AutofillUrlMatcher -import com.duckduckgo.autofill.store.reporting.AutofillSiteBreakageReportingFeatureRepository import com.duckduckgo.common.utils.DispatcherProvider import com.duckduckgo.di.scopes.AppScope import com.squareup.anvil.annotations.ContributesBinding diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/reporting/remoteconfig/AutofillSiteBreakageReportingExceptionsPersister.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/reporting/remoteconfig/AutofillSiteBreakageReportingExceptionsPersister.kt deleted file mode 100644 index 86b4ca318729..000000000000 --- a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/reporting/remoteconfig/AutofillSiteBreakageReportingExceptionsPersister.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2024 DuckDuckGo - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.duckduckgo.autofill.impl.reporting.remoteconfig - -import com.duckduckgo.autofill.store.reporting.AutofillSiteBreakageReportingEntity -import com.duckduckgo.autofill.store.reporting.AutofillSiteBreakageReportingFeatureRepository -import com.duckduckgo.di.scopes.AppScope -import com.duckduckgo.feature.toggles.api.FeatureExceptions -import com.duckduckgo.feature.toggles.api.RemoteFeatureStoreNamed -import com.squareup.anvil.annotations.ContributesBinding -import javax.inject.Inject - -@ContributesBinding(AppScope::class) -@RemoteFeatureStoreNamed(AutofillSiteBreakageReportingFeature::class) -class AutofillSiteBreakageReportingExceptionsPersister @Inject constructor( - private val repository: AutofillSiteBreakageReportingFeatureRepository, -) : FeatureExceptions.Store { - override fun insertAll(exception: List) { - repository.updateAllExceptions( - exception.map { AutofillSiteBreakageReportingEntity(domain = it.domain, reason = it.reason.orEmpty()) }, - ) - } -} diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/reporting/remoteconfig/AutofillSiteBreakageReportingFeature.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/reporting/remoteconfig/AutofillSiteBreakageReportingFeature.kt index 9c21bf022539..64d51aa792a3 100644 --- a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/reporting/remoteconfig/AutofillSiteBreakageReportingFeature.kt +++ b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/reporting/remoteconfig/AutofillSiteBreakageReportingFeature.kt @@ -26,7 +26,6 @@ import com.duckduckgo.feature.toggles.api.Toggle.DefaultFeatureValue boundType = AutofillSiteBreakageReportingFeature::class, featureName = "autofillBreakageReporter", settingsStore = AutofillSiteBreakageReportingRemoteSettingsPersister::class, - exceptionsStore = AutofillSiteBreakageReportingExceptionsPersister::class, ) /** * This is the class that represents the feature flag for offering to report Autofill breakages diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/reporting/remoteconfig/AutofillSiteBreakageReportingFeatureRepository.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/reporting/remoteconfig/AutofillSiteBreakageReportingFeatureRepository.kt new file mode 100644 index 000000000000..08a6d4f6a89a --- /dev/null +++ b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/reporting/remoteconfig/AutofillSiteBreakageReportingFeatureRepository.kt @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2025 DuckDuckGo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.duckduckgo.autofill.impl.reporting.remoteconfig + +import com.duckduckgo.app.di.AppCoroutineScope +import com.duckduckgo.app.di.IsMainProcess +import com.duckduckgo.common.utils.DispatcherProvider +import com.duckduckgo.di.scopes.AppScope +import com.duckduckgo.privacy.config.api.PrivacyConfigCallbackPlugin +import com.squareup.anvil.annotations.ContributesBinding +import com.squareup.anvil.annotations.ContributesMultibinding +import dagger.SingleInstanceIn +import java.util.concurrent.CopyOnWriteArrayList +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch + +interface AutofillSiteBreakageReportingFeatureRepository { + val exceptions: List +} + +@ContributesBinding( + scope = AppScope::class, + boundType = AutofillSiteBreakageReportingFeatureRepository::class, +) +@ContributesMultibinding( + scope = AppScope::class, + boundType = PrivacyConfigCallbackPlugin::class, +) +@SingleInstanceIn(AppScope::class) +class AutofillSiteBreakageReportingFeatureRepositoryImpl @Inject constructor( + private val feature: AutofillSiteBreakageReportingFeature, + @AppCoroutineScope private val coroutineScope: CoroutineScope, + private val dispatcherProvider: DispatcherProvider, + @IsMainProcess private val isMainProcess: Boolean, +) : AutofillSiteBreakageReportingFeatureRepository, PrivacyConfigCallbackPlugin { + + override val exceptions = CopyOnWriteArrayList() + + init { + loadToMemory() + } + + override fun onPrivacyConfigDownloaded() { + loadToMemory() + } + + private fun loadToMemory() { + coroutineScope.launch(dispatcherProvider.io()) { + if (isMainProcess) { + exceptions.clear() + exceptions.addAll(feature.self().getExceptions().map { it.domain }) + } + } + } +} diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/reporting/remoteconfig/AutofillSiteBreakageReportingModule.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/reporting/remoteconfig/AutofillSiteBreakageReportingModule.kt index 350bf7c667ef..f5171c9bd06a 100644 --- a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/reporting/remoteconfig/AutofillSiteBreakageReportingModule.kt +++ b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/reporting/remoteconfig/AutofillSiteBreakageReportingModule.kt @@ -20,46 +20,17 @@ import android.content.Context import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.preferencesDataStore -import androidx.room.Room -import com.duckduckgo.app.di.AppCoroutineScope -import com.duckduckgo.app.di.IsMainProcess -import com.duckduckgo.autofill.store.reporting.ALL_MIGRATIONS -import com.duckduckgo.autofill.store.reporting.AutofillSiteBreakageReportingDatabase -import com.duckduckgo.autofill.store.reporting.AutofillSiteBreakageReportingFeatureRepository -import com.duckduckgo.autofill.store.reporting.AutofillSiteBreakageReportingFeatureRepositoryImpl -import com.duckduckgo.common.utils.DispatcherProvider import com.duckduckgo.di.scopes.AppScope import com.squareup.anvil.annotations.ContributesTo import dagger.Module import dagger.Provides import dagger.SingleInstanceIn import javax.inject.Qualifier -import kotlinx.coroutines.CoroutineScope @Module @ContributesTo(AppScope::class) class AutofillSiteBreakageReportingModule { - @SingleInstanceIn(AppScope::class) - @Provides - fun repository( - database: AutofillSiteBreakageReportingDatabase, - @AppCoroutineScope appCoroutineScope: CoroutineScope, - dispatcherProvider: DispatcherProvider, - @IsMainProcess isMainProcess: Boolean, - ): AutofillSiteBreakageReportingFeatureRepository { - return AutofillSiteBreakageReportingFeatureRepositoryImpl(database, appCoroutineScope, dispatcherProvider, isMainProcess) - } - - @Provides - @SingleInstanceIn(AppScope::class) - fun database(context: Context): AutofillSiteBreakageReportingDatabase { - return Room.databaseBuilder(context, AutofillSiteBreakageReportingDatabase::class.java, "autofillSiteBreakageReporting.db") - .fallbackToDestructiveMigration() - .addMigrations(*ALL_MIGRATIONS) - .build() - } - private val Context.autofillSiteBreakageReportingDataStore: DataStore by preferencesDataStore( name = "autofill_site_breakage_reporting", ) diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/service/AutofillServiceExceptions.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/service/AutofillServiceExceptions.kt index d1a1fdec2819..1d13a3842875 100644 --- a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/service/AutofillServiceExceptions.kt +++ b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/service/AutofillServiceExceptions.kt @@ -17,7 +17,7 @@ package com.duckduckgo.autofill.impl.service import com.duckduckgo.app.browser.UriString.Companion.sameOrSubdomain -import com.duckduckgo.autofill.impl.service.store.AutofillFeatureRepository +import com.duckduckgo.autofill.impl.service.store.AutofillServiceFeatureRepository import com.duckduckgo.di.scopes.AppScope import com.squareup.anvil.annotations.ContributesBinding import dagger.SingleInstanceIn @@ -30,7 +30,7 @@ interface AutofillServiceExceptions { @ContributesBinding(AppScope::class) @SingleInstanceIn(AppScope::class) class RealAutofillServiceExceptions @Inject constructor( - private val repository: AutofillFeatureRepository, + private val repository: AutofillServiceFeatureRepository, ) : AutofillServiceExceptions { override fun isAnException(domain: String): Boolean { diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/service/AutofillServiceFeature.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/service/AutofillServiceFeature.kt index 46023e3110e0..c839245bce01 100644 --- a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/service/AutofillServiceFeature.kt +++ b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/service/AutofillServiceFeature.kt @@ -17,7 +17,6 @@ package com.duckduckgo.autofill.impl.service import com.duckduckgo.anvil.annotations.ContributesRemoteFeature -import com.duckduckgo.autofill.impl.service.store.AutofillServiceExceptionsStore import com.duckduckgo.di.scopes.AppScope import com.duckduckgo.feature.toggles.api.Toggle import com.duckduckgo.feature.toggles.api.Toggle.DefaultFeatureValue @@ -26,7 +25,6 @@ import com.duckduckgo.feature.toggles.api.Toggle.InternalAlwaysEnabled @ContributesRemoteFeature( scope = AppScope::class, featureName = "autofillService", - exceptionsStore = AutofillServiceExceptionsStore::class, ) interface AutofillServiceFeature { diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/service/store/AutofillServiceDatabase.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/service/store/AutofillServiceDatabase.kt deleted file mode 100644 index 3302e67942f9..000000000000 --- a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/service/store/AutofillServiceDatabase.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2025 DuckDuckGo - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.duckduckgo.autofill.impl.service.store - -import androidx.room.Database -import androidx.room.Entity -import androidx.room.PrimaryKey -import androidx.room.RoomDatabase -import androidx.room.migration.Migration - -@Database( - exportSchema = true, - version = 1, - entities = [ - AutofillServiceException::class, - ], -) -abstract class AutofillServiceDatabase : RoomDatabase() { - abstract fun exceptionsDao(): ExceptionsDao -} - -@Entity(tableName = "autofill_service_exceptions") -data class AutofillServiceException( - @PrimaryKey val domain: String, - val reason: String, -) - -val ALL_MIGRATIONS = emptyArray() diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/service/store/AutofillServiceExceptionsStore.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/service/store/AutofillServiceExceptionsStore.kt deleted file mode 100644 index 3884d05358b6..000000000000 --- a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/service/store/AutofillServiceExceptionsStore.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2025 DuckDuckGo - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.duckduckgo.autofill.impl.service.store - -import com.duckduckgo.autofill.impl.service.AutofillServiceFeature -import com.duckduckgo.di.scopes.AppScope -import com.duckduckgo.feature.toggles.api.FeatureExceptions -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException -import com.duckduckgo.feature.toggles.api.RemoteFeatureStoreNamed -import com.squareup.anvil.annotations.ContributesBinding -import javax.inject.Inject - -@ContributesBinding(AppScope::class) -@RemoteFeatureStoreNamed(AutofillServiceFeature::class) -class AutofillServiceExceptionsStore @Inject constructor( - private val autofillFeatureRepository: AutofillFeatureRepository, -) : FeatureExceptions.Store { - override fun insertAll(exception: List) { - autofillFeatureRepository.insertAll( - exception.map { AutofillServiceException(domain = it.domain, reason = it.reason.orEmpty()) }, - ) - } -} diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/service/store/AutofillFeatureRepository.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/service/store/AutofillServiceFeatureRepository.kt similarity index 61% rename from autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/service/store/AutofillFeatureRepository.kt rename to autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/service/store/AutofillServiceFeatureRepository.kt index e1e0562d3d56..ff4757622c03 100644 --- a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/service/store/AutofillFeatureRepository.kt +++ b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/service/store/AutofillServiceFeatureRepository.kt @@ -19,9 +19,12 @@ package com.duckduckgo.autofill.impl.service.store import com.duckduckgo.app.di.AppCoroutineScope import com.duckduckgo.app.di.IsMainProcess import com.duckduckgo.app.di.ProcessName +import com.duckduckgo.autofill.impl.service.AutofillServiceFeature import com.duckduckgo.common.utils.DispatcherProvider import com.duckduckgo.di.scopes.AppScope +import com.duckduckgo.privacy.config.api.PrivacyConfigCallbackPlugin import com.squareup.anvil.annotations.ContributesBinding +import com.squareup.anvil.annotations.ContributesMultibinding import dagger.SingleInstanceIn import java.util.concurrent.CopyOnWriteArrayList import javax.inject.Inject @@ -29,41 +32,46 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import timber.log.Timber -interface AutofillFeatureRepository { - fun insertAll(newList: List) +interface AutofillServiceFeatureRepository { val exceptions: CopyOnWriteArrayList } @SingleInstanceIn(AppScope::class) -@ContributesBinding(AppScope::class) -class RealAutofillFeatureRepository @Inject constructor( - private val autofillServiceDatabase: AutofillServiceDatabase, +@ContributesBinding( + scope = AppScope::class, + boundType = AutofillServiceFeatureRepository::class, +) +@ContributesMultibinding( + scope = AppScope::class, + boundType = AutofillServiceFeatureRepository::class, +) +class RealAutofillServiceFeatureRepository @Inject constructor( @IsMainProcess private val isMainProcess: Boolean, @ProcessName private val processName: String, - @AppCoroutineScope appCoroutineScope: CoroutineScope, - dispatcherProvider: DispatcherProvider, -) : AutofillFeatureRepository { - - private val dao = autofillServiceDatabase.exceptionsDao() + @AppCoroutineScope private val appCoroutineScope: CoroutineScope, + private val dispatcherProvider: DispatcherProvider, + private val autofillServiceFeature: AutofillServiceFeature, +) : AutofillServiceFeatureRepository, PrivacyConfigCallbackPlugin { override val exceptions = CopyOnWriteArrayList() init { appCoroutineScope.launch(dispatcherProvider.io()) { Timber.i("DDGAutofillService: Init AutofillFeatureRepository from $processName") - if (isMainProcess || processName == ":autofill") { - loadToMemory() - } + loadToMemory() } } - override fun insertAll(newList: List) { - dao.updateAll(newList) + override fun onPrivacyConfigDownloaded() { loadToMemory() } private fun loadToMemory() { - exceptions.clear() - dao.getAll().map { exceptions.add(it.domain) } + appCoroutineScope.launch(dispatcherProvider.io()) { + if (isMainProcess || processName == ":autofill") { + exceptions.clear() + exceptions.addAll(autofillServiceFeature.self().getExceptions().map { it.domain }) + } + } } } diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/service/store/AutofillServiceModule.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/service/store/AutofillServiceModule.kt index 9309d0546696..53095faf24a4 100644 --- a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/service/store/AutofillServiceModule.kt +++ b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/service/store/AutofillServiceModule.kt @@ -21,7 +21,6 @@ import android.view.autofill.AutofillManager import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.preferencesDataStore -import androidx.room.Room import com.duckduckgo.di.scopes.AppScope import com.squareup.anvil.annotations.ContributesTo import dagger.Module @@ -44,15 +43,6 @@ class AutofillServiceModule { return context.autofillServiceStore } - @SingleInstanceIn(AppScope::class) - @Provides - fun provideAutofillServiceDatabase(context: Context): AutofillServiceDatabase { - return Room.databaseBuilder(context, AutofillServiceDatabase::class.java, "autofillService.db") - .fallbackToDestructiveMigration() - .addMigrations(*ALL_MIGRATIONS) - .build() - } - @Provides fun providesAutofillManager(context: Context): AutofillManager? { return kotlin.runCatching { context.getSystemService(AutofillManager::class.java) as AutofillManager }.getOrNull() diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/service/store/ExceptionsDao.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/service/store/ExceptionsDao.kt deleted file mode 100644 index 6cbe33966c81..000000000000 --- a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/service/store/ExceptionsDao.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2025 DuckDuckGo - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.duckduckgo.autofill.impl.service.store - -import androidx.room.Dao -import androidx.room.Insert -import androidx.room.OnConflictStrategy -import androidx.room.Query -import androidx.room.Transaction - -@Dao -abstract class ExceptionsDao { - - @Insert(onConflict = OnConflictStrategy.REPLACE) - abstract fun insertAll(exceptions: List) - - @Transaction - open fun updateAll(exceptions: List) { - deleteAll() - insertAll(exceptions) - } - - @Query("select * from autofill_service_exceptions where domain = :domain") - abstract fun get(domain: String): AutofillServiceException - - @Query("select * from autofill_service_exceptions") - abstract fun getAll(): List - - @Query("delete from autofill_service_exceptions") - abstract fun deleteAll() -} diff --git a/autofill/autofill-impl/src/test/java/com/duckduckgo/autofill/impl/RealAutofillTest.kt b/autofill/autofill-impl/src/test/java/com/duckduckgo/autofill/impl/RealAutofillTest.kt index 1fffbc36cb3b..90680e0d6f7e 100644 --- a/autofill/autofill-impl/src/test/java/com/duckduckgo/autofill/impl/RealAutofillTest.kt +++ b/autofill/autofill-impl/src/test/java/com/duckduckgo/autofill/impl/RealAutofillTest.kt @@ -17,8 +17,8 @@ package com.duckduckgo.autofill.impl import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.duckduckgo.autofill.store.feature.AutofillFeatureRepository -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.autofill.impl.feature.plugin.AutofillFeatureRepository +import com.duckduckgo.feature.toggles.api.FeatureException import com.duckduckgo.privacy.config.api.UnprotectedTemporary import java.util.concurrent.CopyOnWriteArrayList import org.junit.Assert.* diff --git a/autofill/autofill-impl/src/test/java/com/duckduckgo/autofill/impl/email/remoteconfig/RealEmailProtectionInContextFeatureRepositoryTest.kt b/autofill/autofill-impl/src/test/java/com/duckduckgo/autofill/impl/email/remoteconfig/RealEmailProtectionInContextFeatureRepositoryTest.kt new file mode 100644 index 000000000000..d8c154ed39b3 --- /dev/null +++ b/autofill/autofill-impl/src/test/java/com/duckduckgo/autofill/impl/email/remoteconfig/RealEmailProtectionInContextFeatureRepositoryTest.kt @@ -0,0 +1,57 @@ +package com.duckduckgo.autofill.impl.email.remoteconfig + +import android.annotation.SuppressLint +import com.duckduckgo.autofill.impl.email.incontext.EmailProtectionInContextSignupFeature +import com.duckduckgo.common.test.CoroutineTestRule +import com.duckduckgo.feature.toggles.api.FakeFeatureToggleFactory +import com.duckduckgo.feature.toggles.api.FeatureException +import com.duckduckgo.feature.toggles.api.Toggle +import kotlinx.coroutines.test.runTest +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Rule +import org.junit.Test + +@SuppressLint("DenyListedApi") // setRawStoredState +class RealEmailProtectionInContextFeatureRepositoryTest { + @get:Rule + var coroutineRule = CoroutineTestRule() + + private val feature = FakeFeatureToggleFactory.create(EmailProtectionInContextSignupFeature::class.java) + + @Before + fun setup() { + feature.self().setRawStoredState(Toggle.State(exceptions = exceptions)) + } + + @Test + fun whenRepositoryIsCreatedThenExceptionsLoadIntoMemory() = runTest { + val repository = RealEmailProtectionInContextFeatureRepository( + feature, + coroutineRule.testScope, + coroutineRule.testDispatcherProvider, + true, + ) + + assertEquals(exceptions.map { it.domain }, repository.exceptions) + } + + @Test + fun whenRemoteConfigUpdateThenExceptionsUpdated() = runTest { + val repository = RealEmailProtectionInContextFeatureRepository( + feature, + coroutineRule.testScope, + coroutineRule.testDispatcherProvider, + true, + ) + + assertEquals(exceptions.map { it.domain }, repository.exceptions) + feature.self().setRawStoredState(Toggle.State(exceptions = emptyList())) + repository.onPrivacyConfigDownloaded() + assertEquals(emptyList(), repository.exceptions) + } + + companion object { + val exceptions = listOf(FeatureException("example.com", "reason")) + } +} diff --git a/autofill/autofill-impl/src/test/java/com/duckduckgo/autofill/impl/feature/plugin/RealAutofillFeatureRepositoryTest.kt b/autofill/autofill-impl/src/test/java/com/duckduckgo/autofill/impl/feature/plugin/RealAutofillFeatureRepositoryTest.kt new file mode 100644 index 000000000000..3899768aa482 --- /dev/null +++ b/autofill/autofill-impl/src/test/java/com/duckduckgo/autofill/impl/feature/plugin/RealAutofillFeatureRepositoryTest.kt @@ -0,0 +1,57 @@ +package com.duckduckgo.autofill.impl.feature.plugin + +import android.annotation.SuppressLint +import com.duckduckgo.autofill.api.AutofillFeature +import com.duckduckgo.common.test.CoroutineTestRule +import com.duckduckgo.feature.toggles.api.FakeFeatureToggleFactory +import com.duckduckgo.feature.toggles.api.FeatureException +import com.duckduckgo.feature.toggles.api.Toggle +import kotlinx.coroutines.test.runTest +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Rule +import org.junit.Test + +@SuppressLint("DenyListedApi") // setRawStoredState +class RealAutofillFeatureRepositoryTest { + @get:Rule + var coroutineRule = CoroutineTestRule() + + private val feature = FakeFeatureToggleFactory.create(AutofillFeature::class.java) + + @Before + fun setup() { + feature.self().setRawStoredState(Toggle.State(exceptions = exceptions)) + } + + @Test + fun whenRepositoryIsCreatedThenExceptionsLoadIntoMemory() = runTest { + val repository = RealAutofillFeatureRepository( + feature, + coroutineRule.testScope, + coroutineRule.testDispatcherProvider, + true, + ) + + assertEquals(exceptions, repository.exceptions) + } + + @Test + fun whenRemoteConfigUpdateThenExceptionsUpdated() = runTest { + val repository = RealAutofillFeatureRepository( + feature, + coroutineRule.testScope, + coroutineRule.testDispatcherProvider, + true, + ) + + assertEquals(exceptions, repository.exceptions) + feature.self().setRawStoredState(Toggle.State(exceptions = emptyList())) + repository.onPrivacyConfigDownloaded() + assertEquals(emptyList(), repository.exceptions) + } + + companion object { + val exceptions = listOf(FeatureException("example.com", "reason")) + } +} diff --git a/autofill/autofill-impl/src/test/java/com/duckduckgo/autofill/impl/reporting/AutofillBreakageReportCanShowRulesImplTest.kt b/autofill/autofill-impl/src/test/java/com/duckduckgo/autofill/impl/reporting/AutofillBreakageReportCanShowRulesImplTest.kt index 767d6f36aa1a..bf5a04155f8d 100644 --- a/autofill/autofill-impl/src/test/java/com/duckduckgo/autofill/impl/reporting/AutofillBreakageReportCanShowRulesImplTest.kt +++ b/autofill/autofill-impl/src/test/java/com/duckduckgo/autofill/impl/reporting/AutofillBreakageReportCanShowRulesImplTest.kt @@ -3,9 +3,9 @@ package com.duckduckgo.autofill.impl.reporting import androidx.test.ext.junit.runners.AndroidJUnit4 import com.duckduckgo.autofill.impl.encoding.UrlUnicodeNormalizerImpl import com.duckduckgo.autofill.impl.reporting.remoteconfig.AutofillSiteBreakageReportingFeature +import com.duckduckgo.autofill.impl.reporting.remoteconfig.AutofillSiteBreakageReportingFeatureRepository import com.duckduckgo.autofill.impl.time.TimeProvider import com.duckduckgo.autofill.impl.urlmatcher.AutofillDomainNameUrlMatcher -import com.duckduckgo.autofill.store.reporting.AutofillSiteBreakageReportingFeatureRepository import com.duckduckgo.common.test.CoroutineTestRule import com.duckduckgo.feature.toggles.api.FakeFeatureToggleFactory import com.duckduckgo.feature.toggles.api.Toggle.State diff --git a/autofill/autofill-impl/src/test/java/com/duckduckgo/autofill/impl/reporting/remoteconfig/AutofillSiteBreakageReportingFeatureRepositoryImplTest.kt b/autofill/autofill-impl/src/test/java/com/duckduckgo/autofill/impl/reporting/remoteconfig/AutofillSiteBreakageReportingFeatureRepositoryImplTest.kt new file mode 100644 index 000000000000..cb9ca4d4ef30 --- /dev/null +++ b/autofill/autofill-impl/src/test/java/com/duckduckgo/autofill/impl/reporting/remoteconfig/AutofillSiteBreakageReportingFeatureRepositoryImplTest.kt @@ -0,0 +1,56 @@ +package com.duckduckgo.autofill.impl.reporting.remoteconfig + +import android.annotation.SuppressLint +import com.duckduckgo.common.test.CoroutineTestRule +import com.duckduckgo.feature.toggles.api.FakeFeatureToggleFactory +import com.duckduckgo.feature.toggles.api.FeatureException +import com.duckduckgo.feature.toggles.api.Toggle +import kotlinx.coroutines.test.runTest +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Rule +import org.junit.Test + +@SuppressLint("DenyListedApi") // setRawStoredState +class AutofillSiteBreakageReportingFeatureRepositoryImplTest { + @get:Rule + var coroutineRule = CoroutineTestRule() + + private val feature = FakeFeatureToggleFactory.create(AutofillSiteBreakageReportingFeature::class.java) + + @Before + fun setup() { + feature.self().setRawStoredState(Toggle.State(exceptions = exceptions)) + } + + @Test + fun whenRepositoryIsCreatedThenExceptionsLoadIntoMemory() = runTest { + val repository = AutofillSiteBreakageReportingFeatureRepositoryImpl( + feature, + coroutineRule.testScope, + coroutineRule.testDispatcherProvider, + true, + ) + + assertEquals(exceptions.map { it.domain }, repository.exceptions) + } + + @Test + fun whenRemoteConfigUpdateThenExceptionsUpdated() = runTest { + val repository = AutofillSiteBreakageReportingFeatureRepositoryImpl( + feature, + coroutineRule.testScope, + coroutineRule.testDispatcherProvider, + true, + ) + + assertEquals(exceptions.map { it.domain }, repository.exceptions) + feature.self().setRawStoredState(Toggle.State(exceptions = emptyList())) + repository.onPrivacyConfigDownloaded() + assertEquals(emptyList(), repository.exceptions) + } + + companion object { + val exceptions = listOf(FeatureException("example.com", "reason")) + } +} diff --git a/autofill/autofill-impl/src/test/java/com/duckduckgo/autofill/impl/store/RealAutofillServiceFeatureRepositoryTest.kt b/autofill/autofill-impl/src/test/java/com/duckduckgo/autofill/impl/store/RealAutofillServiceFeatureRepositoryTest.kt new file mode 100644 index 000000000000..693f948e058a --- /dev/null +++ b/autofill/autofill-impl/src/test/java/com/duckduckgo/autofill/impl/store/RealAutofillServiceFeatureRepositoryTest.kt @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2025 DuckDuckGo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.duckduckgo.autofill.impl.store + +import android.annotation.SuppressLint +import com.duckduckgo.autofill.impl.service.AutofillServiceFeature +import com.duckduckgo.autofill.impl.service.store.RealAutofillServiceFeatureRepository +import com.duckduckgo.common.test.CoroutineTestRule +import com.duckduckgo.feature.toggles.api.FakeFeatureToggleFactory +import com.duckduckgo.feature.toggles.api.FeatureException +import com.duckduckgo.feature.toggles.api.Toggle +import kotlinx.coroutines.test.runTest +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Rule +import org.junit.Test + +@SuppressLint("DenyListedApi") // setRawStoredState +class RealAutofillServiceFeatureRepositoryTest { + @get:Rule + var coroutineRule = CoroutineTestRule() + + private val autofillServiceFeature = FakeFeatureToggleFactory.create(AutofillServiceFeature::class.java) + + @Before + fun setup() { + autofillServiceFeature.self().setRawStoredState(Toggle.State(exceptions = listOf(exception))) + } + + @Test + fun whenRepositoryIsCreatedThenExceptionsLoadIntoMemory() = runTest { + val repository = RealAutofillServiceFeatureRepository( + true, + "processName", + coroutineRule.testScope, + coroutineRule.testDispatcherProvider, + autofillServiceFeature, + ) + + assertEquals(listOf(exception.domain), repository.exceptions) + } + + @Test + fun whenRemoteConfigUpdateThenExceptionsUpdated() = runTest { + val repository = RealAutofillServiceFeatureRepository( + true, + "processName", + coroutineRule.testScope, + coroutineRule.testDispatcherProvider, + autofillServiceFeature, + ) + + assertEquals(listOf(exception.domain), repository.exceptions) + autofillServiceFeature.self().setRawStoredState(Toggle.State(exceptions = emptyList())) + repository.onPrivacyConfigDownloaded() + assertEquals(emptyList(), repository.exceptions) + } + + companion object { + val exception = FeatureException("example.com", "reason") + } +} diff --git a/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/AutofillDao.kt b/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/AutofillDao.kt deleted file mode 100644 index 1a9df43749ec..000000000000 --- a/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/AutofillDao.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2021 DuckDuckGo - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.duckduckgo.autofill.store - -import androidx.room.Dao -import androidx.room.Insert -import androidx.room.OnConflictStrategy -import androidx.room.Query -import androidx.room.Transaction - -@Dao -abstract class AutofillDao { - - @Insert(onConflict = OnConflictStrategy.REPLACE) - abstract fun insertAll(domains: List) - - @Transaction - open fun updateAll(domains: List) { - deleteAll() - insertAll(domains) - } - - @Query("select * from autofill_exceptions where domain = :domain") - abstract fun get(domain: String): AutofillExceptionEntity - - @Query("select * from autofill_exceptions") - abstract fun getAll(): List - - @Query("delete from autofill_exceptions") - abstract fun deleteAll() -} diff --git a/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/AutofillDatabase.kt b/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/AutofillDatabase.kt index 505418933fe2..31f1e309b6eb 100644 --- a/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/AutofillDatabase.kt +++ b/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/AutofillDatabase.kt @@ -23,14 +23,12 @@ import androidx.sqlite.db.SupportSQLiteDatabase @Database( exportSchema = true, - version = 2, + version = 3, entities = [ - AutofillExceptionEntity::class, CredentialsSyncMetadataEntity::class, ], ) abstract class AutofillDatabase : RoomDatabase() { - abstract fun autofillDao(): AutofillDao abstract fun credentialsSyncDao(): CredentialsSyncMetadataDao } @@ -46,4 +44,10 @@ val MIGRATION_1_2 = object : Migration(1, 2) { } } -val ALL_MIGRATIONS = arrayOf(MIGRATION_1_2) +val MIGRATION_2_3 = object : Migration(2, 3) { + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL("DROP TABLE `autofill_exceptions`") + } +} + +val ALL_MIGRATIONS = arrayOf(MIGRATION_1_2, MIGRATION_2_3) diff --git a/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/AutofillDatabaseModels.kt b/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/AutofillDatabaseModels.kt deleted file mode 100644 index 594ed1b2e3e7..000000000000 --- a/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/AutofillDatabaseModels.kt +++ /dev/null @@ -1,31 +0,0 @@ -// ktlint-disable filename -/* - * Copyright (c) 2023 DuckDuckGo - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.duckduckgo.autofill.store - -import androidx.room.Entity -import androidx.room.PrimaryKey -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException - -@Entity(tableName = "autofill_exceptions") -data class AutofillExceptionEntity( - @PrimaryKey val domain: String, - val reason: String, -) - -fun AutofillExceptionEntity.toFeatureException(): FeatureException { - return FeatureException(domain = this.domain, reason = this.reason) -} diff --git a/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/feature/AutofillFeatureRepository.kt b/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/feature/AutofillFeatureRepository.kt deleted file mode 100644 index 18c61845cfbd..000000000000 --- a/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/feature/AutofillFeatureRepository.kt +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2023 DuckDuckGo - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.duckduckgo.autofill.store.feature - -import com.duckduckgo.autofill.store.AutofillDao -import com.duckduckgo.autofill.store.AutofillDatabase -import com.duckduckgo.autofill.store.AutofillExceptionEntity -import com.duckduckgo.autofill.store.toFeatureException -import com.duckduckgo.common.utils.DispatcherProvider -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException -import java.util.concurrent.CopyOnWriteArrayList -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.launch - -interface AutofillFeatureRepository { - fun updateAllExceptions(exceptions: List) - val exceptions: CopyOnWriteArrayList -} - -class RealAutofillFeatureRepository( - val database: AutofillDatabase, - coroutineScope: CoroutineScope, - dispatcherProvider: DispatcherProvider, - isMainProcess: Boolean, -) : AutofillFeatureRepository { - - private val autofillDao: AutofillDao = database.autofillDao() - override val exceptions = CopyOnWriteArrayList() - - init { - coroutineScope.launch(dispatcherProvider.io()) { - if (isMainProcess) { - loadToMemory() - } - } - } - - override fun updateAllExceptions(exceptions: List) { - autofillDao.updateAll(exceptions) - loadToMemory() - } - - private fun loadToMemory() { - exceptions.clear() - autofillDao.getAll().map { exceptions.add(it.toFeatureException()) } - } -} diff --git a/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/feature/email/incontext/EmailProtectionInContextDao.kt b/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/feature/email/incontext/EmailProtectionInContextDao.kt deleted file mode 100644 index 9f11b1bc4561..000000000000 --- a/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/feature/email/incontext/EmailProtectionInContextDao.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2023 DuckDuckGo - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.duckduckgo.autofill.store.feature.email.incontext - -import androidx.room.Dao -import androidx.room.Insert -import androidx.room.OnConflictStrategy -import androidx.room.Query -import androidx.room.Transaction - -@Dao -abstract class EmailProtectionInContextDao { - - @Insert(onConflict = OnConflictStrategy.REPLACE) - abstract fun insertAll(domains: List) - - @Transaction - open fun updateAll(domains: List) { - deleteAll() - insertAll(domains) - } - - @Query("select * from email_incontext_exceptions where domain = :domain") - abstract fun get(domain: String): EmailInContextExceptionEntity - - @Query("select * from email_incontext_exceptions") - abstract fun getAll(): List - - @Query("delete from email_incontext_exceptions") - abstract fun deleteAll() -} diff --git a/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/feature/email/incontext/EmailProtectionInContextDatabase.kt b/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/feature/email/incontext/EmailProtectionInContextDatabase.kt deleted file mode 100644 index f7a131370cbc..000000000000 --- a/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/feature/email/incontext/EmailProtectionInContextDatabase.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2023 DuckDuckGo - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.duckduckgo.autofill.store.feature.email.incontext - -import androidx.room.Database -import androidx.room.Entity -import androidx.room.PrimaryKey -import androidx.room.RoomDatabase -import androidx.room.migration.Migration - -@Database( - exportSchema = true, - version = 1, - entities = [ - EmailInContextExceptionEntity::class, - ], -) -abstract class EmailProtectionInContextDatabase : RoomDatabase() { - abstract fun emailInContextDao(): EmailProtectionInContextDao -} - -@Entity(tableName = "email_incontext_exceptions") -data class EmailInContextExceptionEntity( - @PrimaryKey val domain: String, - val reason: String, -) - -val ALL_MIGRATIONS = emptyArray() diff --git a/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/feature/email/incontext/EmailProtectionInContextFeatureRepository.kt b/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/feature/email/incontext/EmailProtectionInContextFeatureRepository.kt deleted file mode 100644 index 38c80aca19bf..000000000000 --- a/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/feature/email/incontext/EmailProtectionInContextFeatureRepository.kt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2023 DuckDuckGo - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.duckduckgo.autofill.store.feature.email.incontext - -import com.duckduckgo.common.utils.DispatcherProvider -import java.util.concurrent.CopyOnWriteArrayList -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.launch - -interface EmailProtectionInContextFeatureRepository { - fun updateAllExceptions(exceptions: List) - val exceptions: CopyOnWriteArrayList -} - -class RealEmailProtectionInContextFeatureRepository( - val database: EmailProtectionInContextDatabase, - coroutineScope: CoroutineScope, - dispatcherProvider: DispatcherProvider, - isMainProcess: Boolean, -) : EmailProtectionInContextFeatureRepository { - - private val dao = database.emailInContextDao() - override val exceptions = CopyOnWriteArrayList() - - init { - coroutineScope.launch(dispatcherProvider.io()) { - if (isMainProcess) { - loadToMemory() - } - } - } - - override fun updateAllExceptions(exceptions: List) { - dao.updateAll(exceptions) - loadToMemory() - } - - private fun loadToMemory() { - exceptions.clear() - dao.getAll().map { exceptions.add(it.domain) } - } -} diff --git a/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/reporting/AutofillSiteBreakageExceptionDatabase.kt b/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/reporting/AutofillSiteBreakageExceptionDatabase.kt deleted file mode 100644 index 40c915fb03e4..000000000000 --- a/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/reporting/AutofillSiteBreakageExceptionDatabase.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2024 DuckDuckGo - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.duckduckgo.autofill.store.reporting - -import androidx.room.Dao -import androidx.room.Database -import androidx.room.Entity -import androidx.room.Insert -import androidx.room.OnConflictStrategy -import androidx.room.PrimaryKey -import androidx.room.Query -import androidx.room.RoomDatabase -import androidx.room.Transaction -import androidx.room.migration.Migration - -@Database( - exportSchema = true, - version = 1, - entities = [ - AutofillSiteBreakageReportingEntity::class, - ], -) -abstract class AutofillSiteBreakageReportingDatabase : RoomDatabase() { - abstract fun dao(): AutofillSiteBreakageReportingDao -} - -@Entity(tableName = "autofill_site_breakage_reporting") -data class AutofillSiteBreakageReportingEntity( - @PrimaryKey val domain: String, - val reason: String, -) - -val ALL_MIGRATIONS = emptyArray() - -@Dao -abstract class AutofillSiteBreakageReportingDao { - - @Insert(onConflict = OnConflictStrategy.REPLACE) - abstract fun insertAll(domains: List) - - @Transaction - open fun updateAll(domains: List) { - deleteAll() - insertAll(domains) - } - - @Query("select * from autofill_site_breakage_reporting") - abstract fun getAll(): List - - @Query("delete from autofill_site_breakage_reporting") - abstract fun deleteAll() -} diff --git a/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/reporting/AutofillSiteBreakageReportingFeatureRepository.kt b/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/reporting/AutofillSiteBreakageReportingFeatureRepository.kt deleted file mode 100644 index c00f71d8ec50..000000000000 --- a/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/reporting/AutofillSiteBreakageReportingFeatureRepository.kt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2024 DuckDuckGo - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.duckduckgo.autofill.store.reporting - -import com.duckduckgo.common.utils.DispatcherProvider -import java.util.concurrent.CopyOnWriteArrayList -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.launch - -interface AutofillSiteBreakageReportingFeatureRepository { - fun updateAllExceptions(exceptions: List) - val exceptions: List -} - -class AutofillSiteBreakageReportingFeatureRepositoryImpl( - val database: AutofillSiteBreakageReportingDatabase, - coroutineScope: CoroutineScope, - dispatcherProvider: DispatcherProvider, - isMainProcess: Boolean, -) : AutofillSiteBreakageReportingFeatureRepository { - - private val dao = database.dao() - override val exceptions = CopyOnWriteArrayList() - - init { - coroutineScope.launch(dispatcherProvider.io()) { - if (isMainProcess) { - loadToMemory() - } - } - } - - override fun updateAllExceptions(exceptions: List) { - dao.updateAll(exceptions) - loadToMemory() - } - - private fun loadToMemory() { - exceptions.clear() - dao.getAll().map { exceptions.add(it.domain) } - } -} diff --git a/content-scope-scripts/content-scope-scripts-impl/src/main/java/com/duckduckgo/contentscopescripts/impl/RealContentScopeScripts.kt b/content-scope-scripts/content-scope-scripts-impl/src/main/java/com/duckduckgo/contentscopescripts/impl/RealContentScopeScripts.kt index 8b1397f37131..e35a2a934639 100644 --- a/content-scope-scripts/content-scope-scripts-impl/src/main/java/com/duckduckgo/contentscopescripts/impl/RealContentScopeScripts.kt +++ b/content-scope-scripts/content-scope-scripts-impl/src/main/java/com/duckduckgo/contentscopescripts/impl/RealContentScopeScripts.kt @@ -22,7 +22,7 @@ import com.duckduckgo.appbuildconfig.api.AppBuildConfig import com.duckduckgo.common.utils.plugins.PluginPoint import com.duckduckgo.contentscopescripts.api.ContentScopeConfigPlugin import com.duckduckgo.di.scopes.AppScope -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import com.duckduckgo.fingerprintprotection.api.FingerprintProtectionManager import com.duckduckgo.privacy.config.api.UnprotectedTemporary import com.squareup.anvil.annotations.ContributesBinding diff --git a/content-scope-scripts/content-scope-scripts-impl/src/test/java/com/duckduckgo/contentscopescripts/impl/RealContentScopeScriptsTest.kt b/content-scope-scripts/content-scope-scripts-impl/src/test/java/com/duckduckgo/contentscopescripts/impl/RealContentScopeScriptsTest.kt index 5f3b0373626a..b1afb5ed28bd 100644 --- a/content-scope-scripts/content-scope-scripts-impl/src/test/java/com/duckduckgo/contentscopescripts/impl/RealContentScopeScriptsTest.kt +++ b/content-scope-scripts/content-scope-scripts-impl/src/test/java/com/duckduckgo/contentscopescripts/impl/RealContentScopeScriptsTest.kt @@ -22,7 +22,7 @@ import com.duckduckgo.appbuildconfig.api.AppBuildConfig import com.duckduckgo.common.utils.plugins.PluginPoint import com.duckduckgo.contentscopescripts.api.ContentScopeConfigPlugin import com.duckduckgo.feature.toggles.api.FakeFeatureToggleFactory -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import com.duckduckgo.feature.toggles.api.Toggle.State import com.duckduckgo.fingerprintprotection.api.FingerprintProtectionManager import com.duckduckgo.privacy.config.api.UnprotectedTemporary diff --git a/cookies/cookies-impl/src/main/java/com/duckduckgo/cookies/impl/features/CookiesFeature.kt b/cookies/cookies-impl/src/main/java/com/duckduckgo/cookies/impl/features/CookiesFeature.kt index 8b15efc984b1..3626b341460f 100644 --- a/cookies/cookies-impl/src/main/java/com/duckduckgo/cookies/impl/features/CookiesFeature.kt +++ b/cookies/cookies-impl/src/main/java/com/duckduckgo/cookies/impl/features/CookiesFeature.kt @@ -16,7 +16,7 @@ package com.duckduckgo.cookies.impl.features -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException data class CookiesFeature( val state: String, diff --git a/cookies/cookies-store/src/main/java/com/duckduckgo/cookies/store/CookiesDatabaseModels.kt b/cookies/cookies-store/src/main/java/com/duckduckgo/cookies/store/CookiesDatabaseModels.kt index 3020a22851e1..db9d64dde786 100644 --- a/cookies/cookies-store/src/main/java/com/duckduckgo/cookies/store/CookiesDatabaseModels.kt +++ b/cookies/cookies-store/src/main/java/com/duckduckgo/cookies/store/CookiesDatabaseModels.kt @@ -18,7 +18,7 @@ package com.duckduckgo.cookies.store import androidx.room.Entity import androidx.room.PrimaryKey -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException @Entity(tableName = "first_party_cookie_policy") data class FirstPartyCookiePolicyEntity( diff --git a/cookies/cookies-store/src/main/java/com/duckduckgo/cookies/store/CookiesRepository.kt b/cookies/cookies-store/src/main/java/com/duckduckgo/cookies/store/CookiesRepository.kt index b8051b7e032c..9cebc482059e 100644 --- a/cookies/cookies-store/src/main/java/com/duckduckgo/cookies/store/CookiesRepository.kt +++ b/cookies/cookies-store/src/main/java/com/duckduckgo/cookies/store/CookiesRepository.kt @@ -18,7 +18,7 @@ package com.duckduckgo.cookies.store import com.duckduckgo.common.utils.DispatcherProvider import com.duckduckgo.cookies.store.thirdpartycookienames.ThirdPartyCookieNamesDao -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import java.util.concurrent.CopyOnWriteArrayList import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch diff --git a/feature-toggles/feature-toggles-api/src/main/java/com/duckduckgo/feature/toggles/api/FeatureExceptions.kt b/feature-toggles/feature-toggles-api/src/main/java/com/duckduckgo/feature/toggles/api/FeatureException.kt similarity index 67% rename from feature-toggles/feature-toggles-api/src/main/java/com/duckduckgo/feature/toggles/api/FeatureExceptions.kt rename to feature-toggles/feature-toggles-api/src/main/java/com/duckduckgo/feature/toggles/api/FeatureException.kt index 8741366b276d..ca5aad204121 100644 --- a/feature-toggles/feature-toggles-api/src/main/java/com/duckduckgo/feature/toggles/api/FeatureExceptions.kt +++ b/feature-toggles/feature-toggles-api/src/main/java/com/duckduckgo/feature/toggles/api/FeatureException.kt @@ -15,14 +15,4 @@ */ package com.duckduckgo.feature.toggles.api -object FeatureExceptions { - interface Store { - fun insertAll(exception: List) - } - - data class FeatureException(val domain: String, val reason: String?) - - val EMPTY_STORE = object : Store { - override fun insertAll(exception: List) {} - } -} +data class FeatureException(val domain: String, val reason: String?) diff --git a/feature-toggles/feature-toggles-api/src/main/java/com/duckduckgo/feature/toggles/api/FeatureToggles.kt b/feature-toggles/feature-toggles-api/src/main/java/com/duckduckgo/feature/toggles/api/FeatureToggles.kt index 53ea2544e96f..c7a03a76da86 100644 --- a/feature-toggles/feature-toggles-api/src/main/java/com/duckduckgo/feature/toggles/api/FeatureToggles.kt +++ b/feature-toggles/feature-toggles-api/src/main/java/com/duckduckgo/feature/toggles/api/FeatureToggles.kt @@ -16,7 +16,6 @@ package com.duckduckgo.feature.toggles.api -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException import com.duckduckgo.feature.toggles.api.Toggle.FeatureName import com.duckduckgo.feature.toggles.api.Toggle.State import com.duckduckgo.feature.toggles.api.Toggle.State.Cohort diff --git a/feature-toggles/feature-toggles-impl/src/test/java/com/duckduckgo/feature/toggles/codegen/ContributesRemoteFeatureCodeGeneratorBucketAssignmentTest.kt b/feature-toggles/feature-toggles-impl/src/test/java/com/duckduckgo/feature/toggles/codegen/ContributesRemoteFeatureCodeGeneratorBucketAssignmentTest.kt index 285b4e7b6bad..7d835a2b15cd 100644 --- a/feature-toggles/feature-toggles-impl/src/test/java/com/duckduckgo/feature/toggles/codegen/ContributesRemoteFeatureCodeGeneratorBucketAssignmentTest.kt +++ b/feature-toggles/feature-toggles-impl/src/test/java/com/duckduckgo/feature/toggles/codegen/ContributesRemoteFeatureCodeGeneratorBucketAssignmentTest.kt @@ -22,7 +22,6 @@ import com.duckduckgo.appbuildconfig.api.AppBuildConfig import com.duckduckgo.appbuildconfig.api.BuildFlavor.PLAY import com.duckduckgo.experiments.api.VariantManager import com.duckduckgo.feature.toggles.api.FakeToggleStore -import com.duckduckgo.feature.toggles.api.FeatureExceptions import com.duckduckgo.feature.toggles.api.FeatureSettings import com.duckduckgo.feature.toggles.api.FeatureToggles import com.duckduckgo.privacy.config.api.PrivacyFeaturePlugin @@ -125,14 +124,12 @@ class ContributesRemoteFeatureCodeGeneratorBucketAssignmentTest(private val test return Class .forName("com.duckduckgo.feature.toggles.codegen.TestTriggerFeature_RemoteFeature") .getConstructor( - FeatureExceptions.Store::class.java, FeatureSettings.Store::class.java, dagger.Lazy::class.java as Class<*>, AppBuildConfig::class.java, VariantManager::class.java, Context::class.java, ).newInstance( - FeatureExceptions.EMPTY_STORE, FeatureSettings.EMPTY_STORE, Lazy { testFeature }, appBuildConfig, diff --git a/feature-toggles/feature-toggles-impl/src/test/java/com/duckduckgo/feature/toggles/codegen/ContributesRemoteFeatureCodeGeneratorTest.kt b/feature-toggles/feature-toggles-impl/src/test/java/com/duckduckgo/feature/toggles/codegen/ContributesRemoteFeatureCodeGeneratorTest.kt index 92f09f170824..9479bcc5e0a2 100644 --- a/feature-toggles/feature-toggles-impl/src/test/java/com/duckduckgo/feature/toggles/codegen/ContributesRemoteFeatureCodeGeneratorTest.kt +++ b/feature-toggles/feature-toggles-impl/src/test/java/com/duckduckgo/feature/toggles/codegen/ContributesRemoteFeatureCodeGeneratorTest.kt @@ -24,8 +24,7 @@ import com.duckduckgo.appbuildconfig.api.BuildFlavor.* import com.duckduckgo.experiments.api.VariantConfig import com.duckduckgo.experiments.api.VariantManager import com.duckduckgo.feature.toggles.api.FakeToggleStore -import com.duckduckgo.feature.toggles.api.FeatureExceptions -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import com.duckduckgo.feature.toggles.api.FeatureSettings import com.duckduckgo.feature.toggles.api.FeatureToggles import com.duckduckgo.feature.toggles.api.RemoteFeatureStoreNamed @@ -321,14 +320,12 @@ class ContributesRemoteFeatureCodeGeneratorTest { return Class .forName("com.duckduckgo.feature.toggles.codegen.AnotherTestTriggerFeature_RemoteFeature") .getConstructor( - FeatureExceptions.Store::class.java, FeatureSettings.Store::class.java, dagger.Lazy::class.java as Class<*>, AppBuildConfig::class.java, VariantManager::class.java, Context::class.java, ).newInstance( - FeatureExceptions.EMPTY_STORE, FeatureSettings.EMPTY_STORE, Lazy { anotherTestFeature }, appBuildConfig, @@ -4206,14 +4203,12 @@ class ContributesRemoteFeatureCodeGeneratorTest { return Class .forName("com.duckduckgo.feature.toggles.codegen.TestTriggerFeature_RemoteFeature") .getConstructor( - FeatureExceptions.Store::class.java, FeatureSettings.Store::class.java, dagger.Lazy::class.java as Class<*>, AppBuildConfig::class.java, VariantManager::class.java, Context::class.java, ).newInstance( - FeatureExceptions.EMPTY_STORE, FeatureSettings.EMPTY_STORE, Lazy { testFeature }, appBuildConfig, diff --git a/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionFeature.kt b/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionFeature.kt index 2a9a88d0bdf9..6f5e706b0e1b 100644 --- a/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionFeature.kt +++ b/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/MaliciousSiteProtectionFeature.kt @@ -20,12 +20,10 @@ import com.duckduckgo.anvil.annotations.ContributesRemoteFeature import com.duckduckgo.di.scopes.AppScope import com.duckduckgo.feature.toggles.api.Toggle import com.duckduckgo.feature.toggles.api.Toggle.DefaultFeatureValue -import com.duckduckgo.malicioussiteprotection.impl.remoteconfig.MaliciousSiteProtectionExceptionsStore @ContributesRemoteFeature( scope = AppScope::class, featureName = "maliciousSiteProtection", - exceptionsStore = MaliciousSiteProtectionExceptionsStore::class, ) /** * This is the class that represents the maliciousSiteProtection feature flags diff --git a/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/data/db/MaliciousSiteDao.kt b/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/data/db/MaliciousSiteDao.kt index de45177ad60b..a94981232f41 100644 --- a/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/data/db/MaliciousSiteDao.kt +++ b/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/data/db/MaliciousSiteDao.kt @@ -161,19 +161,4 @@ interface MaliciousSiteDao { private suspend fun getLatestRevision(feed: Feed, type: Type): Int { return getLatestRevision(feed = feed.name, type = type.name)?.revision ?: 0 } - - @Transaction - fun updateAllExceptions(exceptions: List) { - deleteAllExceptions() - insertAllExceptions(exceptions) - } - - @Query("DELETE FROM featureExceptions") - fun deleteAllExceptions() {} - - @Insert(onConflict = OnConflictStrategy.REPLACE) - fun insertAllExceptions(exceptions: List) - - @Query("SELECT * FROM featureExceptions") - fun getExceptions(): List } diff --git a/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/data/db/MaliciousSitesDataEntities.kt b/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/data/db/MaliciousSitesDataEntities.kt index a5f34df99dff..5cb1d1fb79c6 100644 --- a/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/data/db/MaliciousSitesDataEntities.kt +++ b/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/data/db/MaliciousSitesDataEntities.kt @@ -44,10 +44,3 @@ data class FilterEntity( val regex: String, val type: String, ) - -@Entity(tableName = "featureExceptions") -data class FeatureExceptionEntity( - @PrimaryKey - val domain: String, - val reason: String?, -) diff --git a/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/data/db/MaliciousSitesDatabase.kt b/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/data/db/MaliciousSitesDatabase.kt index 3140c270c61b..8cb9e6e9d481 100644 --- a/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/data/db/MaliciousSitesDatabase.kt +++ b/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/data/db/MaliciousSitesDatabase.kt @@ -19,16 +19,22 @@ package com.duckduckgo.malicioussiteprotection.impl.data.db import androidx.room.Database import androidx.room.RoomDatabase import androidx.room.migration.Migration +import androidx.sqlite.db.SupportSQLiteDatabase @Database( exportSchema = true, - entities = [RevisionEntity::class, HashPrefixEntity::class, FilterEntity::class, FeatureExceptionEntity::class], - version = 2, + entities = [RevisionEntity::class, HashPrefixEntity::class, FilterEntity::class], + version = 3, ) abstract class MaliciousSitesDatabase : RoomDatabase() { abstract fun maliciousSiteDao(): MaliciousSiteDao companion object { - val ALL_MIGRATIONS = arrayOf() + internal val MIGRATION_2_3 = object : Migration(2, 3) { + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL("DROP TABLE IF EXISTS `featureExceptions`") + } + } + internal val ALL_MIGRATIONS = arrayOf(MIGRATION_2_3) } } diff --git a/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/remoteconfig/MaliciousSiteProtectionExceptionsStore.kt b/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/remoteconfig/MaliciousSiteProtectionExceptionsStore.kt deleted file mode 100644 index 97214e5f3bf2..000000000000 --- a/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/remoteconfig/MaliciousSiteProtectionExceptionsStore.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2024 DuckDuckGo - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.duckduckgo.malicioussiteprotection.impl.remoteconfig - -import com.duckduckgo.di.scopes.AppScope -import com.duckduckgo.feature.toggles.api.FeatureExceptions -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException -import com.duckduckgo.feature.toggles.api.RemoteFeatureStoreNamed -import com.duckduckgo.malicioussiteprotection.impl.MaliciousSiteProtectionFeature -import com.squareup.anvil.annotations.ContributesBinding -import javax.inject.Inject - -@ContributesBinding(AppScope::class) -@RemoteFeatureStoreNamed(MaliciousSiteProtectionFeature::class) -class MaliciousSiteProtectionExceptionsStore @Inject constructor( - private val maliciousSiteProtectionRCRepository: MaliciousSiteProtectionRCRepository, -) : FeatureExceptions.Store { - override fun insertAll(exception: List) { - maliciousSiteProtectionRCRepository.insertAllExceptions(exception) - } -} diff --git a/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/remoteconfig/MaliciousSiteProtectionRCRepository.kt b/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/remoteconfig/MaliciousSiteProtectionRCRepository.kt index dc2820026f4f..d8d030ae7289 100644 --- a/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/remoteconfig/MaliciousSiteProtectionRCRepository.kt +++ b/malicious-site-protection/malicious-site-protection-impl/src/main/kotlin/com/duckduckgo/malicioussiteprotection/impl/remoteconfig/MaliciousSiteProtectionRCRepository.kt @@ -20,41 +20,45 @@ import com.duckduckgo.app.di.AppCoroutineScope import com.duckduckgo.app.di.IsMainProcess import com.duckduckgo.common.utils.DispatcherProvider import com.duckduckgo.di.scopes.AppScope -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException -import com.duckduckgo.malicioussiteprotection.impl.data.db.FeatureExceptionEntity -import com.duckduckgo.malicioussiteprotection.impl.data.db.MaliciousSiteDao +import com.duckduckgo.feature.toggles.api.FeatureException +import com.duckduckgo.malicioussiteprotection.impl.MaliciousSiteProtectionFeature +import com.duckduckgo.privacy.config.api.PrivacyConfigCallbackPlugin import com.squareup.anvil.annotations.ContributesBinding +import com.squareup.anvil.annotations.ContributesMultibinding +import dagger.SingleInstanceIn import java.util.concurrent.CopyOnWriteArrayList import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch interface MaliciousSiteProtectionRCRepository { - fun insertAllExceptions(exceptions: List) fun isExempted(hostName: String): Boolean val exceptions: CopyOnWriteArrayList } -@ContributesBinding(AppScope::class) +@ContributesBinding( + scope = AppScope::class, + boundType = MaliciousSiteProtectionRCRepository::class, +) +@ContributesMultibinding( + scope = AppScope::class, + boundType = PrivacyConfigCallbackPlugin::class, +) +@SingleInstanceIn(AppScope::class) class RealMaliciousSiteProtectionRCRepository @Inject constructor( - @AppCoroutineScope coroutineScope: CoroutineScope, - dispatcherProvider: DispatcherProvider, - val dao: MaliciousSiteDao, - @IsMainProcess isMainProcess: Boolean, -) : MaliciousSiteProtectionRCRepository { + private val feature: MaliciousSiteProtectionFeature, + @AppCoroutineScope private val coroutineScope: CoroutineScope, + private val dispatcherProvider: DispatcherProvider, + @IsMainProcess private val isMainProcess: Boolean, +) : MaliciousSiteProtectionRCRepository, PrivacyConfigCallbackPlugin { override val exceptions = CopyOnWriteArrayList() init { - coroutineScope.launch(dispatcherProvider.io()) { - if (isMainProcess) { - loadToMemory() - } - } + loadToMemory() } - override fun insertAllExceptions(exceptions: List) { - dao.updateAllExceptions(exceptions.map { FeatureExceptionEntity(domain = it.domain, reason = it.reason) }) + override fun onPrivacyConfigDownloaded() { loadToMemory() } @@ -63,8 +67,11 @@ class RealMaliciousSiteProtectionRCRepository @Inject constructor( } private fun loadToMemory() { - exceptions.clear() - val exceptionsEntityList = dao.getExceptions() - exceptions.addAll(exceptionsEntityList.map { FeatureException(domain = it.domain, reason = it.reason) }) + coroutineScope.launch(dispatcherProvider.io()) { + if (isMainProcess) { + exceptions.clear() + exceptions.addAll(feature.self().getExceptions()) + } + } } } diff --git a/malicious-site-protection/malicious-site-protection-impl/src/test/kotlin/com/duckduckgo/malicioussiteprotection/impl/remoteconfig/RealMaliciousSiteProtectionRCRepositoryTest.kt b/malicious-site-protection/malicious-site-protection-impl/src/test/kotlin/com/duckduckgo/malicioussiteprotection/impl/remoteconfig/RealMaliciousSiteProtectionRCRepositoryTest.kt new file mode 100644 index 000000000000..f217b0182171 --- /dev/null +++ b/malicious-site-protection/malicious-site-protection-impl/src/test/kotlin/com/duckduckgo/malicioussiteprotection/impl/remoteconfig/RealMaliciousSiteProtectionRCRepositoryTest.kt @@ -0,0 +1,57 @@ +package com.duckduckgo.malicioussiteprotection.impl.remoteconfig + +import android.annotation.SuppressLint +import com.duckduckgo.common.test.CoroutineTestRule +import com.duckduckgo.feature.toggles.api.FakeFeatureToggleFactory +import com.duckduckgo.feature.toggles.api.FeatureException +import com.duckduckgo.feature.toggles.api.Toggle +import com.duckduckgo.malicioussiteprotection.impl.MaliciousSiteProtectionFeature +import kotlinx.coroutines.test.runTest +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Rule +import org.junit.Test + +@SuppressLint("DenyListedApi") // setRawStoredState +class RealMaliciousSiteProtectionRCRepositoryTest { + @get:Rule + var coroutineRule = CoroutineTestRule() + + private val feature = FakeFeatureToggleFactory.create(MaliciousSiteProtectionFeature::class.java) + + @Before + fun setup() { + feature.self().setRawStoredState(Toggle.State(exceptions = exceptions)) + } + + @Test + fun whenRepositoryIsCreatedThenExceptionsLoadIntoMemory() = runTest { + val repository = RealMaliciousSiteProtectionRCRepository( + feature, + coroutineRule.testScope, + coroutineRule.testDispatcherProvider, + true, + ) + + assertEquals(exceptions, repository.exceptions) + } + + @Test + fun whenRemoteConfigUpdateThenExceptionsUpdated() = runTest { + val repository = RealMaliciousSiteProtectionRCRepository( + feature, + coroutineRule.testScope, + coroutineRule.testDispatcherProvider, + true, + ) + + assertEquals(exceptions, repository.exceptions) + feature.self().setRawStoredState(Toggle.State(exceptions = emptyList())) + repository.onPrivacyConfigDownloaded() + assertEquals(emptyList(), repository.exceptions) + } + + companion object { + val exceptions = listOf(FeatureException("example.com", "reason")) + } +} diff --git a/privacy-config/privacy-config-api/src/main/java/com/duckduckgo/privacy/config/api/UnprotectedTemporary.kt b/privacy-config/privacy-config-api/src/main/java/com/duckduckgo/privacy/config/api/UnprotectedTemporary.kt index 1ba7391989f5..8a50a8dbd796 100644 --- a/privacy-config/privacy-config-api/src/main/java/com/duckduckgo/privacy/config/api/UnprotectedTemporary.kt +++ b/privacy-config/privacy-config-api/src/main/java/com/duckduckgo/privacy/config/api/UnprotectedTemporary.kt @@ -16,7 +16,7 @@ package com.duckduckgo.privacy.config.api -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException /** Public interface for the Unprotected Temporary feature */ interface UnprotectedTemporary { diff --git a/privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/features/amplinks/AmpLinksFeature.kt b/privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/features/amplinks/AmpLinksFeature.kt index 37a011932759..6ea3e4820959 100644 --- a/privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/features/amplinks/AmpLinksFeature.kt +++ b/privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/features/amplinks/AmpLinksFeature.kt @@ -16,7 +16,7 @@ package com.duckduckgo.privacy.config.impl.features.amplinks -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException data class AmpLinksFeature( val state: String, diff --git a/privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/features/contentblocking/ContentBlockingFeature.kt b/privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/features/contentblocking/ContentBlockingFeature.kt index 1293120ef987..fd8b8c041c5b 100644 --- a/privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/features/contentblocking/ContentBlockingFeature.kt +++ b/privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/features/contentblocking/ContentBlockingFeature.kt @@ -16,7 +16,7 @@ package com.duckduckgo.privacy.config.impl.features.contentblocking -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException data class ContentBlockingFeature( val state: String, diff --git a/privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/features/drm/DrmFeature.kt b/privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/features/drm/DrmFeature.kt index 8141666e7aec..63d37697af40 100644 --- a/privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/features/drm/DrmFeature.kt +++ b/privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/features/drm/DrmFeature.kt @@ -16,7 +16,7 @@ package com.duckduckgo.privacy.config.impl.features.drm -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException data class DrmFeature( val state: String, diff --git a/privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/features/https/HttpsFeature.kt b/privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/features/https/HttpsFeature.kt index 77c1aa14ee79..e38adcc3912a 100644 --- a/privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/features/https/HttpsFeature.kt +++ b/privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/features/https/HttpsFeature.kt @@ -16,7 +16,7 @@ package com.duckduckgo.privacy.config.impl.features.https -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException data class HttpsFeature( val state: String, diff --git a/privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/features/trackingparameters/TrackingParametersFeature.kt b/privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/features/trackingparameters/TrackingParametersFeature.kt index fb045312b8c0..86efc08ae51d 100644 --- a/privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/features/trackingparameters/TrackingParametersFeature.kt +++ b/privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/features/trackingparameters/TrackingParametersFeature.kt @@ -16,7 +16,7 @@ package com.duckduckgo.privacy.config.impl.features.trackingparameters -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException data class TrackingParametersFeature( val state: String, diff --git a/privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/features/unprotectedtemporary/RealUnprotectedTemporary.kt b/privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/features/unprotectedtemporary/RealUnprotectedTemporary.kt index c3e3b69ff9c2..25a9718d7fa9 100644 --- a/privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/features/unprotectedtemporary/RealUnprotectedTemporary.kt +++ b/privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/features/unprotectedtemporary/RealUnprotectedTemporary.kt @@ -18,7 +18,7 @@ package com.duckduckgo.privacy.config.impl.features.unprotectedtemporary import com.duckduckgo.app.browser.UriString import com.duckduckgo.di.scopes.AppScope -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import com.duckduckgo.privacy.config.api.UnprotectedTemporary import com.duckduckgo.privacy.config.store.features.unprotectedtemporary.UnprotectedTemporaryRepository import com.squareup.anvil.annotations.ContributesBinding diff --git a/privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/models/JsonPrivacyConfig.kt b/privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/models/JsonPrivacyConfig.kt index 471269aa4846..8b94774cff41 100644 --- a/privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/models/JsonPrivacyConfig.kt +++ b/privacy-config/privacy-config-impl/src/main/java/com/duckduckgo/privacy/config/impl/models/JsonPrivacyConfig.kt @@ -16,7 +16,7 @@ package com.duckduckgo.privacy.config.impl.models -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import org.json.JSONObject data class JsonPrivacyConfig( diff --git a/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/RealPrivacyConfigDownloaderTest.kt b/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/RealPrivacyConfigDownloaderTest.kt index 54cc12c6e90d..5e47176dd5a1 100644 --- a/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/RealPrivacyConfigDownloaderTest.kt +++ b/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/RealPrivacyConfigDownloaderTest.kt @@ -19,7 +19,7 @@ package com.duckduckgo.privacy.config.impl import androidx.test.ext.junit.runners.AndroidJUnit4 import com.duckduckgo.app.statistics.pixels.Pixel import com.duckduckgo.common.test.CoroutineTestRule -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import com.duckduckgo.privacy.config.impl.PrivacyConfigDownloader.ConfigDownloadResult.Error import com.duckduckgo.privacy.config.impl.PrivacyConfigDownloader.ConfigDownloadResult.Success import com.duckduckgo.privacy.config.impl.RealPrivacyConfigPersisterTest.FakeFakePrivacyConfigCallbackPluginPoint diff --git a/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/RealPrivacyConfigPersisterTest.kt b/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/RealPrivacyConfigPersisterTest.kt index 8b7cde4f2cb3..4a2a313b1d08 100644 --- a/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/RealPrivacyConfigPersisterTest.kt +++ b/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/RealPrivacyConfigPersisterTest.kt @@ -23,7 +23,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import com.duckduckgo.common.test.CoroutineTestRule import com.duckduckgo.common.test.api.InMemorySharedPreferences import com.duckduckgo.common.utils.plugins.PluginPoint -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import com.duckduckgo.privacy.config.api.PrivacyConfigCallbackPlugin import com.duckduckgo.privacy.config.api.PrivacyFeatureName import com.duckduckgo.privacy.config.api.PrivacyFeaturePlugin diff --git a/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/features/contentblocking/RealContentBlockingTest.kt b/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/features/contentblocking/RealContentBlockingTest.kt index c8ccc9f3030b..e7c07ae1cb0a 100644 --- a/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/features/contentblocking/RealContentBlockingTest.kt +++ b/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/features/contentblocking/RealContentBlockingTest.kt @@ -17,7 +17,7 @@ package com.duckduckgo.privacy.config.impl.features.contentblocking import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import com.duckduckgo.feature.toggles.api.FeatureToggle import com.duckduckgo.privacy.config.api.PrivacyFeatureName import com.duckduckgo.privacy.config.api.UnprotectedTemporary diff --git a/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/features/drm/RealDrmTest.kt b/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/features/drm/RealDrmTest.kt index 5aa4b057e620..b281f4a64e8e 100644 --- a/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/features/drm/RealDrmTest.kt +++ b/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/features/drm/RealDrmTest.kt @@ -18,7 +18,7 @@ package com.duckduckgo.privacy.config.impl.features.drm import androidx.test.ext.junit.runners.AndroidJUnit4 import com.duckduckgo.app.privacy.db.UserAllowListRepository -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import com.duckduckgo.feature.toggles.api.FeatureToggle import com.duckduckgo.privacy.config.api.PrivacyFeatureName import com.duckduckgo.privacy.config.api.UnprotectedTemporary diff --git a/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/features/https/RealHttpsTest.kt b/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/features/https/RealHttpsTest.kt index 051ba98344d6..4be7049b486f 100644 --- a/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/features/https/RealHttpsTest.kt +++ b/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/features/https/RealHttpsTest.kt @@ -18,7 +18,7 @@ package com.duckduckgo.privacy.config.impl.features.https import androidx.test.ext.junit.runners.AndroidJUnit4 import com.duckduckgo.app.privacy.db.UserAllowListRepository -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import com.duckduckgo.privacy.config.api.UnprotectedTemporary import com.duckduckgo.privacy.config.store.features.https.HttpsRepository import java.util.concurrent.CopyOnWriteArrayList diff --git a/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/features/trackingparameters/RealTrackingParametersTest.kt b/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/features/trackingparameters/RealTrackingParametersTest.kt index 72e60eb92c5c..51d13cd872d9 100644 --- a/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/features/trackingparameters/RealTrackingParametersTest.kt +++ b/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/features/trackingparameters/RealTrackingParametersTest.kt @@ -18,7 +18,7 @@ package com.duckduckgo.privacy.config.impl.features.trackingparameters import androidx.test.ext.junit.runners.AndroidJUnit4 import com.duckduckgo.app.privacy.db.UserAllowListRepository -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import com.duckduckgo.feature.toggles.api.FeatureToggle import com.duckduckgo.privacy.config.api.PrivacyFeatureName import com.duckduckgo.privacy.config.api.UnprotectedTemporary diff --git a/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/features/unprotectedtemporary/RealUnprotectedTemporaryTest.kt b/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/features/unprotectedtemporary/RealUnprotectedTemporaryTest.kt index 2ba347a2a5db..357067bc9cb0 100644 --- a/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/features/unprotectedtemporary/RealUnprotectedTemporaryTest.kt +++ b/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/features/unprotectedtemporary/RealUnprotectedTemporaryTest.kt @@ -17,7 +17,7 @@ package com.duckduckgo.privacy.config.impl.features.unprotectedtemporary import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import com.duckduckgo.privacy.config.store.features.unprotectedtemporary.UnprotectedTemporaryRepository import java.util.concurrent.CopyOnWriteArrayList import org.junit.Assert.* diff --git a/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/referencetests/amplinks/AmpFormatReferenceTest.kt b/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/referencetests/amplinks/AmpFormatReferenceTest.kt index 2d6d4c9e836c..393eb52b5f52 100644 --- a/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/referencetests/amplinks/AmpFormatReferenceTest.kt +++ b/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/referencetests/amplinks/AmpFormatReferenceTest.kt @@ -18,7 +18,7 @@ package com.duckduckgo.privacy.config.impl.referencetests.amplinks import com.duckduckgo.app.privacy.db.UserAllowListRepository import com.duckduckgo.common.test.FileUtilities -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import com.duckduckgo.feature.toggles.api.FeatureToggle import com.duckduckgo.privacy.config.api.AmpLinkType import com.duckduckgo.privacy.config.api.AmpLinks diff --git a/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/referencetests/amplinks/AmpKeywordReferenceTest.kt b/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/referencetests/amplinks/AmpKeywordReferenceTest.kt index dd9597002eeb..2eb1d4afe81a 100644 --- a/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/referencetests/amplinks/AmpKeywordReferenceTest.kt +++ b/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/referencetests/amplinks/AmpKeywordReferenceTest.kt @@ -18,7 +18,7 @@ package com.duckduckgo.privacy.config.impl.referencetests.amplinks import com.duckduckgo.app.privacy.db.UserAllowListRepository import com.duckduckgo.common.test.FileUtilities -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import com.duckduckgo.feature.toggles.api.FeatureToggle import com.duckduckgo.privacy.config.api.AmpLinks import com.duckduckgo.privacy.config.api.PrivacyFeatureName diff --git a/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/referencetests/trackingparameters/TrackingParameterReferenceTest.kt b/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/referencetests/trackingparameters/TrackingParameterReferenceTest.kt index 0b9979aaa30f..7a16f5dbea97 100644 --- a/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/referencetests/trackingparameters/TrackingParameterReferenceTest.kt +++ b/privacy-config/privacy-config-impl/src/test/java/com/duckduckgo/privacy/config/impl/referencetests/trackingparameters/TrackingParameterReferenceTest.kt @@ -18,7 +18,7 @@ package com.duckduckgo.privacy.config.impl.referencetests.trackingparameters import com.duckduckgo.app.privacy.db.UserAllowListRepository import com.duckduckgo.common.test.FileUtilities -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import com.duckduckgo.feature.toggles.api.FeatureToggle import com.duckduckgo.privacy.config.api.PrivacyFeatureName import com.duckduckgo.privacy.config.api.TrackingParameters diff --git a/privacy-config/privacy-config-store/src/main/java/com/duckduckgo/privacy/config/store/PrivacyConfigDatabaseModels.kt b/privacy-config/privacy-config-store/src/main/java/com/duckduckgo/privacy/config/store/PrivacyConfigDatabaseModels.kt index f8d1ee4cbc24..fca3ee915595 100644 --- a/privacy-config/privacy-config-store/src/main/java/com/duckduckgo/privacy/config/store/PrivacyConfigDatabaseModels.kt +++ b/privacy-config/privacy-config-store/src/main/java/com/duckduckgo/privacy/config/store/PrivacyConfigDatabaseModels.kt @@ -19,7 +19,7 @@ package com.duckduckgo.privacy.config.store import androidx.room.Entity import androidx.room.PrimaryKey import androidx.room.TypeConverter -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import com.duckduckgo.privacy.config.api.GpcException import com.duckduckgo.privacy.config.api.GpcHeaderEnabledSite import com.duckduckgo.privacy.config.api.PrivacyConfigData diff --git a/privacy-config/privacy-config-store/src/main/java/com/duckduckgo/privacy/config/store/features/amplinks/AmpLinksRepository.kt b/privacy-config/privacy-config-store/src/main/java/com/duckduckgo/privacy/config/store/features/amplinks/AmpLinksRepository.kt index 5faea6a5abd7..2a0b02575e48 100644 --- a/privacy-config/privacy-config-store/src/main/java/com/duckduckgo/privacy/config/store/features/amplinks/AmpLinksRepository.kt +++ b/privacy-config/privacy-config-store/src/main/java/com/duckduckgo/privacy/config/store/features/amplinks/AmpLinksRepository.kt @@ -17,7 +17,7 @@ package com.duckduckgo.privacy.config.store.features.amplinks import com.duckduckgo.common.utils.DispatcherProvider -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import com.duckduckgo.privacy.config.store.* import java.util.concurrent.CopyOnWriteArrayList import kotlinx.coroutines.CoroutineScope diff --git a/privacy-config/privacy-config-store/src/main/java/com/duckduckgo/privacy/config/store/features/contentblocking/ContentBlockingRepository.kt b/privacy-config/privacy-config-store/src/main/java/com/duckduckgo/privacy/config/store/features/contentblocking/ContentBlockingRepository.kt index a19e48f1e826..46f70bc4a9ce 100644 --- a/privacy-config/privacy-config-store/src/main/java/com/duckduckgo/privacy/config/store/features/contentblocking/ContentBlockingRepository.kt +++ b/privacy-config/privacy-config-store/src/main/java/com/duckduckgo/privacy/config/store/features/contentblocking/ContentBlockingRepository.kt @@ -17,7 +17,7 @@ package com.duckduckgo.privacy.config.store.features.contentblocking import com.duckduckgo.common.utils.DispatcherProvider -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import com.duckduckgo.privacy.config.store.ContentBlockingExceptionEntity import com.duckduckgo.privacy.config.store.PrivacyConfigDatabase import com.duckduckgo.privacy.config.store.toFeatureException diff --git a/privacy-config/privacy-config-store/src/main/java/com/duckduckgo/privacy/config/store/features/drm/DrmRepository.kt b/privacy-config/privacy-config-store/src/main/java/com/duckduckgo/privacy/config/store/features/drm/DrmRepository.kt index 6946cb02020c..3262300de702 100644 --- a/privacy-config/privacy-config-store/src/main/java/com/duckduckgo/privacy/config/store/features/drm/DrmRepository.kt +++ b/privacy-config/privacy-config-store/src/main/java/com/duckduckgo/privacy/config/store/features/drm/DrmRepository.kt @@ -17,7 +17,7 @@ package com.duckduckgo.privacy.config.store.features.drm import com.duckduckgo.common.utils.DispatcherProvider -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import com.duckduckgo.privacy.config.store.DrmExceptionEntity import com.duckduckgo.privacy.config.store.PrivacyConfigDatabase import com.duckduckgo.privacy.config.store.toFeatureException diff --git a/privacy-config/privacy-config-store/src/main/java/com/duckduckgo/privacy/config/store/features/https/HttpsRepository.kt b/privacy-config/privacy-config-store/src/main/java/com/duckduckgo/privacy/config/store/features/https/HttpsRepository.kt index 0daaa9f7e16b..0cc83e3ce21a 100644 --- a/privacy-config/privacy-config-store/src/main/java/com/duckduckgo/privacy/config/store/features/https/HttpsRepository.kt +++ b/privacy-config/privacy-config-store/src/main/java/com/duckduckgo/privacy/config/store/features/https/HttpsRepository.kt @@ -17,7 +17,7 @@ package com.duckduckgo.privacy.config.store.features.https import com.duckduckgo.common.utils.DispatcherProvider -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import com.duckduckgo.privacy.config.store.HttpsExceptionEntity import com.duckduckgo.privacy.config.store.PrivacyConfigDatabase import com.duckduckgo.privacy.config.store.toFeatureException diff --git a/privacy-config/privacy-config-store/src/main/java/com/duckduckgo/privacy/config/store/features/trackingparameters/TrackingParametersRepository.kt b/privacy-config/privacy-config-store/src/main/java/com/duckduckgo/privacy/config/store/features/trackingparameters/TrackingParametersRepository.kt index 852757645fc2..d7bddd12f1a7 100644 --- a/privacy-config/privacy-config-store/src/main/java/com/duckduckgo/privacy/config/store/features/trackingparameters/TrackingParametersRepository.kt +++ b/privacy-config/privacy-config-store/src/main/java/com/duckduckgo/privacy/config/store/features/trackingparameters/TrackingParametersRepository.kt @@ -17,7 +17,7 @@ package com.duckduckgo.privacy.config.store.features.trackingparameters import com.duckduckgo.common.utils.DispatcherProvider -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import com.duckduckgo.privacy.config.store.* import java.util.concurrent.CopyOnWriteArrayList import kotlinx.coroutines.CoroutineScope diff --git a/privacy-config/privacy-config-store/src/main/java/com/duckduckgo/privacy/config/store/features/unprotectedtemporary/UnprotectedTemporaryRepository.kt b/privacy-config/privacy-config-store/src/main/java/com/duckduckgo/privacy/config/store/features/unprotectedtemporary/UnprotectedTemporaryRepository.kt index af3aa1c24f6b..d6ad5de0a399 100644 --- a/privacy-config/privacy-config-store/src/main/java/com/duckduckgo/privacy/config/store/features/unprotectedtemporary/UnprotectedTemporaryRepository.kt +++ b/privacy-config/privacy-config-store/src/main/java/com/duckduckgo/privacy/config/store/features/unprotectedtemporary/UnprotectedTemporaryRepository.kt @@ -17,7 +17,7 @@ package com.duckduckgo.privacy.config.store.features.unprotectedtemporary import com.duckduckgo.common.utils.DispatcherProvider -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import com.duckduckgo.privacy.config.store.PrivacyConfigDatabase import com.duckduckgo.privacy.config.store.UnprotectedTemporaryEntity import com.duckduckgo.privacy.config.store.toFeatureException diff --git a/request-filterer/request-filterer-impl/src/main/java/com/duckduckgo/request/filterer/impl/RequestFiltererFeature.kt b/request-filterer/request-filterer-impl/src/main/java/com/duckduckgo/request/filterer/impl/RequestFiltererFeature.kt index aa26d2bae85b..072a4e3bc825 100644 --- a/request-filterer/request-filterer-impl/src/main/java/com/duckduckgo/request/filterer/impl/RequestFiltererFeature.kt +++ b/request-filterer/request-filterer-impl/src/main/java/com/duckduckgo/request/filterer/impl/RequestFiltererFeature.kt @@ -16,7 +16,7 @@ package com.duckduckgo.request.filterer.impl -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException data class RequestFiltererFeature( val state: String, diff --git a/request-filterer/request-filterer-impl/src/test/java/com/duckduckgo/request/filterer/impl/RequestFiltererImplTest.kt b/request-filterer/request-filterer-impl/src/test/java/com/duckduckgo/request/filterer/impl/RequestFiltererImplTest.kt index 982769eb0b30..83e73552bf51 100644 --- a/request-filterer/request-filterer-impl/src/test/java/com/duckduckgo/request/filterer/impl/RequestFiltererImplTest.kt +++ b/request-filterer/request-filterer-impl/src/test/java/com/duckduckgo/request/filterer/impl/RequestFiltererImplTest.kt @@ -19,7 +19,7 @@ package com.duckduckgo.request.filterer.impl import android.webkit.WebResourceRequest import androidx.test.ext.junit.runners.AndroidJUnit4 import com.duckduckgo.common.test.CoroutineTestRule -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import com.duckduckgo.feature.toggles.api.FeatureToggle import com.duckduckgo.privacy.config.api.UnprotectedTemporary import com.duckduckgo.request.filterer.api.RequestFiltererFeatureName diff --git a/request-filterer/request-filterer-store/src/main/java/com/duckduckgo/request/filterer/store/RequestFiltererDatabaseModels.kt b/request-filterer/request-filterer-store/src/main/java/com/duckduckgo/request/filterer/store/RequestFiltererDatabaseModels.kt index c70e404344ac..691b35a6f682 100644 --- a/request-filterer/request-filterer-store/src/main/java/com/duckduckgo/request/filterer/store/RequestFiltererDatabaseModels.kt +++ b/request-filterer/request-filterer-store/src/main/java/com/duckduckgo/request/filterer/store/RequestFiltererDatabaseModels.kt @@ -19,7 +19,7 @@ package com.duckduckgo.request.filterer.store import androidx.room.Entity import androidx.room.PrimaryKey -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException @Entity(tableName = "settings_entity") data class SettingsEntity( diff --git a/request-filterer/request-filterer-store/src/main/java/com/duckduckgo/request/filterer/store/RequestFiltererRepository.kt b/request-filterer/request-filterer-store/src/main/java/com/duckduckgo/request/filterer/store/RequestFiltererRepository.kt index 40494b49ee13..d6299683202c 100644 --- a/request-filterer/request-filterer-store/src/main/java/com/duckduckgo/request/filterer/store/RequestFiltererRepository.kt +++ b/request-filterer/request-filterer-store/src/main/java/com/duckduckgo/request/filterer/store/RequestFiltererRepository.kt @@ -17,7 +17,7 @@ package com.duckduckgo.request.filterer.store import com.duckduckgo.common.utils.DispatcherProvider -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import java.util.concurrent.CopyOnWriteArrayList import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch diff --git a/site-permissions/site-permissions-impl/build.gradle b/site-permissions/site-permissions-impl/build.gradle index 8166b55b59d6..f4893db80504 100644 --- a/site-permissions/site-permissions-impl/build.gradle +++ b/site-permissions/site-permissions-impl/build.gradle @@ -48,6 +48,7 @@ dependencies { implementation Square.retrofit2.converter.moshi testImplementation project(path: ':common-test') + testImplementation project(path: ':feature-toggles-test') testImplementation CashApp.turbine testImplementation Testing.junit4 testImplementation AndroidX.test.ext.junit diff --git a/site-permissions/site-permissions-impl/src/main/java/com/duckduckgo/site/permissions/impl/di/SitePermissionsModule.kt b/site-permissions/site-permissions-impl/src/main/java/com/duckduckgo/site/permissions/impl/di/SitePermissionsModule.kt index 29fb4c9e9daf..3176bb0820f2 100644 --- a/site-permissions/site-permissions-impl/src/main/java/com/duckduckgo/site/permissions/impl/di/SitePermissionsModule.kt +++ b/site-permissions/site-permissions-impl/src/main/java/com/duckduckgo/site/permissions/impl/di/SitePermissionsModule.kt @@ -23,7 +23,6 @@ import com.duckduckgo.site.permissions.store.ALL_MIGRATIONS import com.duckduckgo.site.permissions.store.SitePermissionsDatabase import com.duckduckgo.site.permissions.store.SitePermissionsPreferences import com.duckduckgo.site.permissions.store.SitePermissionsPreferencesImp -import com.duckduckgo.site.permissions.store.drmblock.DrmBlockDao import com.duckduckgo.site.permissions.store.sitepermissions.SitePermissionsDao import com.duckduckgo.site.permissions.store.sitepermissionsallowed.SitePermissionsAllowedDao import com.squareup.anvil.annotations.ContributesTo @@ -56,12 +55,6 @@ object SitePermissionsModule { return sitePermissionsDatabase.sitePermissionsAllowedDao() } - @Provides - @SingleInstanceIn(AppScope::class) - fun providesDrmBlockDao(sitePermissionsDatabase: SitePermissionsDatabase): DrmBlockDao { - return sitePermissionsDatabase.drmBlockDao() - } - @Provides fun providesSitePermissionsPreferences(context: Context): SitePermissionsPreferences { return SitePermissionsPreferencesImp(context) diff --git a/site-permissions/site-permissions-impl/src/main/java/com/duckduckgo/site/permissions/impl/drmblock/DrmBlockFeature.kt b/site-permissions/site-permissions-impl/src/main/java/com/duckduckgo/site/permissions/impl/drmblock/DrmBlockFeature.kt index 9f11501844ae..c2d21e8796f3 100644 --- a/site-permissions/site-permissions-impl/src/main/java/com/duckduckgo/site/permissions/impl/drmblock/DrmBlockFeature.kt +++ b/site-permissions/site-permissions-impl/src/main/java/com/duckduckgo/site/permissions/impl/drmblock/DrmBlockFeature.kt @@ -24,7 +24,6 @@ import com.duckduckgo.feature.toggles.api.Toggle.DefaultFeatureValue @ContributesRemoteFeature( scope = AppScope::class, featureName = "emeBlock", - exceptionsStore = DrmBlockFeatureExceptionStore::class, ) interface DrmBlockFeature { @Toggle.DefaultValue(DefaultFeatureValue.FALSE) diff --git a/site-permissions/site-permissions-impl/src/main/java/com/duckduckgo/site/permissions/impl/drmblock/DrmBlockFeatureExceptionStore.kt b/site-permissions/site-permissions-impl/src/main/java/com/duckduckgo/site/permissions/impl/drmblock/DrmBlockFeatureExceptionStore.kt deleted file mode 100644 index 15dbfae67e35..000000000000 --- a/site-permissions/site-permissions-impl/src/main/java/com/duckduckgo/site/permissions/impl/drmblock/DrmBlockFeatureExceptionStore.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2023 DuckDuckGo - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.duckduckgo.site.permissions.impl.drmblock - -import com.duckduckgo.di.scopes.AppScope -import com.duckduckgo.feature.toggles.api.FeatureExceptions -import com.duckduckgo.feature.toggles.api.RemoteFeatureStoreNamed -import com.duckduckgo.site.permissions.store.drmblock.DrmBlockExceptionEntity -import com.squareup.anvil.annotations.ContributesBinding -import javax.inject.Inject - -@ContributesBinding(AppScope::class) -@RemoteFeatureStoreNamed(DrmBlockFeature::class) -class DrmBlockFeatureExceptionStore @Inject constructor( - private val drmBlockRepository: DrmBlockRepository, -) : FeatureExceptions.Store { - override fun insertAll(exception: List) { - drmBlockRepository.updateAll( - exception.map { DrmBlockExceptionEntity(domain = it.domain) }, - ) - } -} diff --git a/site-permissions/site-permissions-impl/src/main/java/com/duckduckgo/site/permissions/impl/drmblock/DrmBlockRepository.kt b/site-permissions/site-permissions-impl/src/main/java/com/duckduckgo/site/permissions/impl/drmblock/DrmBlockRepository.kt index c2853731e540..e5482a5477fd 100644 --- a/site-permissions/site-permissions-impl/src/main/java/com/duckduckgo/site/permissions/impl/drmblock/DrmBlockRepository.kt +++ b/site-permissions/site-permissions-impl/src/main/java/com/duckduckgo/site/permissions/impl/drmblock/DrmBlockRepository.kt @@ -20,11 +20,10 @@ import com.duckduckgo.app.di.AppCoroutineScope import com.duckduckgo.app.di.IsMainProcess import com.duckduckgo.common.utils.DispatcherProvider import com.duckduckgo.di.scopes.AppScope -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException -import com.duckduckgo.site.permissions.store.drmblock.DrmBlockDao -import com.duckduckgo.site.permissions.store.drmblock.DrmBlockExceptionEntity -import com.duckduckgo.site.permissions.store.drmblock.toFeatureException +import com.duckduckgo.feature.toggles.api.FeatureException +import com.duckduckgo.privacy.config.api.PrivacyConfigCallbackPlugin import com.squareup.anvil.annotations.ContributesBinding +import com.squareup.anvil.annotations.ContributesMultibinding import dagger.SingleInstanceIn import java.util.concurrent.CopyOnWriteArrayList import javax.inject.Inject @@ -32,38 +31,41 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch interface DrmBlockRepository { - fun updateAll(exceptions: List) val exceptions: CopyOnWriteArrayList } -@ContributesBinding(AppScope::class) +@ContributesBinding( + scope = AppScope::class, + boundType = DrmBlockRepository::class, +) +@ContributesMultibinding( + scope = AppScope::class, + boundType = PrivacyConfigCallbackPlugin::class, +) @SingleInstanceIn(AppScope::class) class RealDrmBlockRepository @Inject constructor( - val drmBlockDao: DrmBlockDao, - @AppCoroutineScope appCoroutineScope: CoroutineScope, - dispatcherProvider: DispatcherProvider, - @IsMainProcess isMainProcess: Boolean, -) : DrmBlockRepository { + private val drmBlockFeature: DrmBlockFeature, + @AppCoroutineScope private val appCoroutineScope: CoroutineScope, + private val dispatcherProvider: DispatcherProvider, + @IsMainProcess private val isMainProcess: Boolean, +) : DrmBlockRepository, PrivacyConfigCallbackPlugin { override val exceptions = CopyOnWriteArrayList() init { - appCoroutineScope.launch(dispatcherProvider.io()) { - if (isMainProcess) { - loadToMemory() - } - } + loadToMemory() } - override fun updateAll(exceptions: List) { - drmBlockDao.updateAll(exceptions) + override fun onPrivacyConfigDownloaded() { loadToMemory() } private fun loadToMemory() { - exceptions.clear() - drmBlockDao.getAll().map { - exceptions.add(it.toFeatureException()) + appCoroutineScope.launch(dispatcherProvider.io()) { + if (isMainProcess) { + exceptions.clear() + exceptions.addAll(drmBlockFeature.self().getExceptions()) + } } } } diff --git a/site-permissions/site-permissions-impl/src/test/java/com/duckduckgo/site/permissions/impl/drmblock/RealDrmBlockRepositoryTest.kt b/site-permissions/site-permissions-impl/src/test/java/com/duckduckgo/site/permissions/impl/drmblock/RealDrmBlockRepositoryTest.kt new file mode 100644 index 000000000000..beebebc40c8c --- /dev/null +++ b/site-permissions/site-permissions-impl/src/test/java/com/duckduckgo/site/permissions/impl/drmblock/RealDrmBlockRepositoryTest.kt @@ -0,0 +1,55 @@ +package com.duckduckgo.site.permissions.impl.drmblock + +import android.annotation.SuppressLint +import com.duckduckgo.common.test.CoroutineTestRule +import com.duckduckgo.feature.toggles.api.FakeFeatureToggleFactory +import com.duckduckgo.feature.toggles.api.FeatureException +import com.duckduckgo.feature.toggles.api.Toggle +import kotlinx.coroutines.test.runTest +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Rule +import org.junit.Test + +@SuppressLint("DenyListedApi") // setRawStoredState +class RealDrmBlockRepositoryTest { + @get:Rule + var coroutineRule = CoroutineTestRule() + + private val drmBlockFeature = FakeFeatureToggleFactory.create(DrmBlockFeature::class.java) + + @Before + fun setup() { + drmBlockFeature.self().setRawStoredState(Toggle.State(exceptions = exceptions)) + } + + @Test + fun whenRepositoryIsCreatedThenExceptionsLoadIntoMemory() = runTest { + val repository = RealDrmBlockRepository( + drmBlockFeature, + coroutineRule.testScope, + coroutineRule.testDispatcherProvider, + true, + ) + assertEquals(exceptions, repository.exceptions) + } + + @Test + fun whenRemoteConfigUpdateThenExceptionsUpdated() = runTest { + val repository = RealDrmBlockRepository( + drmBlockFeature, + coroutineRule.testScope, + coroutineRule.testDispatcherProvider, + true, + ) + + assertEquals(exceptions, repository.exceptions) + drmBlockFeature.self().setRawStoredState(Toggle.State(exceptions = emptyList())) + repository.onPrivacyConfigDownloaded() + assertEquals(emptyList(), repository.exceptions) + } + + companion object { + val exceptions = listOf(FeatureException("example.com", "reason")) + } +} diff --git a/site-permissions/site-permissions-impl/src/test/java/com/duckduckgo/site/permissions/impl/drmblock/RealDrmBlockTest.kt b/site-permissions/site-permissions-impl/src/test/java/com/duckduckgo/site/permissions/impl/drmblock/RealDrmBlockTest.kt index 6439349aa4c3..55fefe0e8eca 100644 --- a/site-permissions/site-permissions-impl/src/test/java/com/duckduckgo/site/permissions/impl/drmblock/RealDrmBlockTest.kt +++ b/site-permissions/site-permissions-impl/src/test/java/com/duckduckgo/site/permissions/impl/drmblock/RealDrmBlockTest.kt @@ -18,7 +18,7 @@ package com.duckduckgo.site.permissions.impl.drmblock import androidx.test.ext.junit.runners.AndroidJUnit4 import com.duckduckgo.app.privacy.db.UserAllowListRepository -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import com.duckduckgo.feature.toggles.api.Toggle import com.duckduckgo.privacy.config.api.UnprotectedTemporary import com.nhaarman.mockitokotlin2.any diff --git a/site-permissions/site-permissions-store/src/main/java/com/duckduckgo/site/permissions/store/SitePermissionsDatabase.kt b/site-permissions/site-permissions-store/src/main/java/com/duckduckgo/site/permissions/store/SitePermissionsDatabase.kt index 76075db32c23..6477decffa96 100644 --- a/site-permissions/site-permissions-store/src/main/java/com/duckduckgo/site/permissions/store/SitePermissionsDatabase.kt +++ b/site-permissions/site-permissions-store/src/main/java/com/duckduckgo/site/permissions/store/SitePermissionsDatabase.kt @@ -20,8 +20,6 @@ import androidx.room.Database import androidx.room.RoomDatabase import androidx.room.migration.Migration import androidx.sqlite.db.SupportSQLiteDatabase -import com.duckduckgo.site.permissions.store.drmblock.DrmBlockDao -import com.duckduckgo.site.permissions.store.drmblock.DrmBlockExceptionEntity import com.duckduckgo.site.permissions.store.sitepermissions.SitePermissionsDao import com.duckduckgo.site.permissions.store.sitepermissions.SitePermissionsEntity import com.duckduckgo.site.permissions.store.sitepermissionsallowed.SitePermissionAllowedEntity @@ -29,18 +27,16 @@ import com.duckduckgo.site.permissions.store.sitepermissionsallowed.SitePermissi @Database( exportSchema = true, - version = 4, + version = 5, entities = [ SitePermissionsEntity::class, SitePermissionAllowedEntity::class, - DrmBlockExceptionEntity::class, ], ) abstract class SitePermissionsDatabase : RoomDatabase() { abstract fun sitePermissionsDao(): SitePermissionsDao abstract fun sitePermissionsAllowedDao(): SitePermissionsAllowedDao - abstract fun drmBlockDao(): DrmBlockDao } val MIGRATION_1_2 = object : Migration(1, 2) { @@ -55,4 +51,10 @@ val MIGRATION_3_4 = object : Migration(3, 4) { } } -val ALL_MIGRATIONS = arrayOf(MIGRATION_1_2, MIGRATION_3_4) +val MIGRATION_4_5 = object : Migration(4, 5) { + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL("DROP TABLE IF EXISTS `drm_block_exceptions`") + } +} + +val ALL_MIGRATIONS = arrayOf(MIGRATION_1_2, MIGRATION_3_4, MIGRATION_4_5) diff --git a/site-permissions/site-permissions-store/src/main/java/com/duckduckgo/site/permissions/store/drmblock/DrmBlockDao.kt b/site-permissions/site-permissions-store/src/main/java/com/duckduckgo/site/permissions/store/drmblock/DrmBlockDao.kt deleted file mode 100644 index ca25d1533a57..000000000000 --- a/site-permissions/site-permissions-store/src/main/java/com/duckduckgo/site/permissions/store/drmblock/DrmBlockDao.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2023 DuckDuckGo - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.duckduckgo.site.permissions.store.drmblock - -import androidx.room.Dao -import androidx.room.Insert -import androidx.room.OnConflictStrategy -import androidx.room.Query -import androidx.room.Transaction - -@Dao -abstract class DrmBlockDao { - - @Insert(onConflict = OnConflictStrategy.REPLACE) - abstract fun insertAll(domains: List) - - @Transaction - open fun updateAll(domains: List) { - deleteAll() - insertAll(domains) - } - - @Query("select * from drm_block_exceptions") - abstract fun getAll(): List - - @Query("delete from drm_block_exceptions") - abstract fun deleteAll() -} diff --git a/site-permissions/site-permissions-store/src/main/java/com/duckduckgo/site/permissions/store/drmblock/DrmBlockExceptionEntity.kt b/site-permissions/site-permissions-store/src/main/java/com/duckduckgo/site/permissions/store/drmblock/DrmBlockExceptionEntity.kt deleted file mode 100644 index 58165b69b367..000000000000 --- a/site-permissions/site-permissions-store/src/main/java/com/duckduckgo/site/permissions/store/drmblock/DrmBlockExceptionEntity.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2023 DuckDuckGo - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.duckduckgo.site.permissions.store.drmblock - -import androidx.room.Entity -import androidx.room.PrimaryKey -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException - -@Entity(tableName = "drm_block_exceptions") -data class DrmBlockExceptionEntity(@PrimaryKey val domain: String) - -fun DrmBlockExceptionEntity.toFeatureException(): FeatureException { - return FeatureException(domain = this.domain, reason = null) -} diff --git a/user-agent/user-agent-impl/src/main/java/com/duckduckgo/user/agent/impl/UserAgentFeature.kt b/user-agent/user-agent-impl/src/main/java/com/duckduckgo/user/agent/impl/UserAgentFeature.kt index c2a485c2a53b..d65ff6d104b7 100644 --- a/user-agent/user-agent-impl/src/main/java/com/duckduckgo/user/agent/impl/UserAgentFeature.kt +++ b/user-agent/user-agent-impl/src/main/java/com/duckduckgo/user/agent/impl/UserAgentFeature.kt @@ -16,7 +16,7 @@ package com.duckduckgo.user.agent.impl -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException data class UserAgentFeature( val state: String, diff --git a/user-agent/user-agent-impl/src/test/java/com/duckduckgo/user/agent/impl/RealUserAgentTest.kt b/user-agent/user-agent-impl/src/test/java/com/duckduckgo/user/agent/impl/RealUserAgentTest.kt index e181a65567f1..6776c1cc5745 100644 --- a/user-agent/user-agent-impl/src/test/java/com/duckduckgo/user/agent/impl/RealUserAgentTest.kt +++ b/user-agent/user-agent-impl/src/test/java/com/duckduckgo/user/agent/impl/RealUserAgentTest.kt @@ -17,7 +17,7 @@ package com.duckduckgo.user.agent.impl import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import com.duckduckgo.privacy.config.api.UnprotectedTemporary import com.duckduckgo.user.agent.store.UserAgentRepository import java.util.concurrent.CopyOnWriteArrayList diff --git a/user-agent/user-agent-store/src/main/java/com/duckduckgo/user/agent/store/UserAgentDatabaseModels.kt b/user-agent/user-agent-store/src/main/java/com/duckduckgo/user/agent/store/UserAgentDatabaseModels.kt index 7a3e77e6fa0a..0098bbb65819 100644 --- a/user-agent/user-agent-store/src/main/java/com/duckduckgo/user/agent/store/UserAgentDatabaseModels.kt +++ b/user-agent/user-agent-store/src/main/java/com/duckduckgo/user/agent/store/UserAgentDatabaseModels.kt @@ -18,7 +18,7 @@ package com.duckduckgo.user.agent.store import androidx.room.Entity import androidx.room.PrimaryKey -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException @Entity(tableName = "user_agent_exceptions") data class UserAgentExceptionEntity( diff --git a/user-agent/user-agent-store/src/main/java/com/duckduckgo/user/agent/store/UserAgentRepository.kt b/user-agent/user-agent-store/src/main/java/com/duckduckgo/user/agent/store/UserAgentRepository.kt index 599972f04d0e..ffdaaea4e8a5 100644 --- a/user-agent/user-agent-store/src/main/java/com/duckduckgo/user/agent/store/UserAgentRepository.kt +++ b/user-agent/user-agent-store/src/main/java/com/duckduckgo/user/agent/store/UserAgentRepository.kt @@ -17,7 +17,7 @@ package com.duckduckgo.user.agent.store import com.duckduckgo.common.utils.DispatcherProvider -import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException +import com.duckduckgo.feature.toggles.api.FeatureException import java.util.concurrent.CopyOnWriteArrayList import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch