Skip to content

Commit

Permalink
Move system app categories to remote config
Browse files Browse the repository at this point in the history
  • Loading branch information
karlenDimla committed Oct 4, 2024
1 parent 587ad2c commit eca935d
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import kotlinx.coroutines.launch
scope = AppScope::class,
featureName = "networkProtection",
toggleStore = VpnRemoteFeaturesStore::class,
settingsStore = VpnRemoteSettingsStore::class,
)
interface VpnRemoteFeatures {
@Toggle.DefaultValue(true)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* 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.networkprotection.impl

import com.duckduckgo.app.di.AppCoroutineScope
import com.duckduckgo.common.utils.DispatcherProvider
import com.duckduckgo.di.scopes.AppScope
import com.duckduckgo.feature.toggles.api.FeatureSettings
import com.duckduckgo.feature.toggles.api.RemoteFeatureStoreNamed
import com.duckduckgo.networkprotection.api.NetworkProtectionState
import com.duckduckgo.networkprotection.store.db.CategorizedSystemApp
import com.duckduckgo.networkprotection.store.db.CategorizedSystemAppsDao
import com.squareup.anvil.annotations.ContributesBinding
import com.squareup.moshi.Json
import com.squareup.moshi.Moshi
import dagger.SingleInstanceIn
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import logcat.LogPriority
import logcat.asLog
import logcat.logcat

@ContributesBinding(AppScope::class)
@RemoteFeatureStoreNamed(VpnRemoteFeatures::class)
@SingleInstanceIn(AppScope::class)
class VpnRemoteSettingsStore @Inject constructor(
@AppCoroutineScope private val coroutineScope: CoroutineScope,
private val dispatcherProvider: DispatcherProvider,
private val networkProtectionState: NetworkProtectionState,
private val categorizedSystemAppsDao: CategorizedSystemAppsDao,
) : FeatureSettings.Store {

private val jsonAdapter = Moshi.Builder().build().adapter(SettingsModel::class.java)

override fun store(jsonString: String) {
logcat { "Received configuration: $jsonString" }

runCatching {
jsonAdapter.fromJson(jsonString)?.let { model ->
model.systemAppCategories.also {
if (it.isNotEmpty()) {
categorizedSystemAppsDao.upsertSystemAppCategories(it)
}
}

// Restart VPN now that the lists were updated
coroutineScope.launch(dispatcherProvider.io()) {
networkProtectionState.restart()
}
}
}.onFailure {
logcat(LogPriority.WARN) { it.asLog() }
}
}

data class SettingsModel(
@field:Json(name = "systemAppCategories")
val systemAppCategories: List<CategorizedSystemApp>,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import com.duckduckgo.networkprotection.store.NetworkProtectionPrefs
import com.duckduckgo.networkprotection.store.RealNetPExclusionListRepository
import com.duckduckgo.networkprotection.store.RealNetPGeoswitchingRepository
import com.duckduckgo.networkprotection.store.RealNetworkProtectionPrefs
import com.duckduckgo.networkprotection.store.db.CategorizedSystemAppsDao
import com.duckduckgo.networkprotection.store.db.NetPDatabase
import com.duckduckgo.networkprotection.store.remote_config.NetPConfigTogglesDao
import com.squareup.anvil.annotations.ContributesTo
Expand Down Expand Up @@ -74,6 +75,14 @@ object DataModule {
): NetPGeoswitchingRepository {
return RealNetPGeoswitchingRepository(networkProtectionPrefs, database.geoswitchingDao(), dispatcherProvider)
}

@Provides
@SingleInstanceIn(AppScope::class)
fun provideCategorizedSystemAppsDao(
database: NetPDatabase,
): CategorizedSystemAppsDao {
return database.categorizedSystemAppsDao()
}
}

@Module
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import com.duckduckgo.networkprotection.impl.exclusion.systemapps.SystemAppsExcl
import com.duckduckgo.networkprotection.impl.exclusion.systemapps.SystemAppsExclusionRepository.SystemAppCategory.Networking
import com.duckduckgo.networkprotection.impl.exclusion.systemapps.SystemAppsExclusionRepository.SystemAppCategory.Others
import com.duckduckgo.networkprotection.impl.settings.NetPSettingsLocalConfig
import com.duckduckgo.networkprotection.store.db.CategorizedSystemAppsDao
import com.squareup.anvil.annotations.ContributesBinding
import dagger.SingleInstanceIn
import javax.inject.Inject
Expand Down Expand Up @@ -68,6 +69,7 @@ class RealSystemAppsExclusionRepository @Inject constructor(
private val packageManager: PackageManager,
private val systemAppOverridesProvider: SystemAppOverridesProvider,
private val dispatcherProvider: DispatcherProvider,
private val categorizedSystemAppsDao: CategorizedSystemAppsDao,
) : SystemAppsExclusionRepository {
private val preferences: SharedPreferences by lazy {
sharedPreferencesProvider.getSharedPreferences(
Expand Down Expand Up @@ -147,38 +149,16 @@ class RealSystemAppsExclusionRepository @Inject constructor(
includeCategory(Others)
}

private fun getCommunicationSystemApps(): Set<String> {
return setOf(
"com.android.calllogbackup",
"com.android.cellbroadcastreceiver",
"com.android.mms.service",
"com.android.phone",
"com.android.providers.contacts",
"com.android.providers.telephony",
"com.android.service.ims",
"com.google.android.apps.messaging",
"com.google.android.gms",
"com.google.android.telephony",
"org.codeaurora.ims",
)
private fun getCommunicationSystemApps(): List<String> {
return categorizedSystemAppsDao.getCommunicationSystemApps().map { it.packageName }
}

private fun getNetworkingSystemApps(): Set<String> {
return setOf(
"com.android.bluetooth",
"com.android.nfc",
"com.google.android.networkstack",
"com.google.android.networkstack.tethering",
)
private fun getNetworkingSystemApps(): List<String> {
return categorizedSystemAppsDao.getNetworkingSystemApps().map { it.packageName }
}

private fun getMediaSystemApps(): Set<String> {
return setOf(
"com.android.providers.media",
"com.google.android.providers.media.module",
"com.google.android.music",
"com.google.android.videos",
)
private fun getMediaSystemApps(): List<String> {
return categorizedSystemAppsDao.getMediaSystemApps().map { it.packageName }
}

private fun getOtherSystemApps(): Set<String> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* 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.networkprotection.store.db

import androidx.room.Dao
import androidx.room.Entity
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.PrimaryKey
import androidx.room.Query
import androidx.room.Transaction

@Dao
interface CategorizedSystemAppsDao {
@Query("SELECT * from netp_system_apps_categories where category = 'COMMUNICATION'")
fun getCommunicationSystemApps(): List<CategorizedSystemApp>

@Query("SELECT * from netp_system_apps_categories where category = 'NETWORKING'")
fun getNetworkingSystemApps(): List<CategorizedSystemApp>

@Query("SELECT * from netp_system_apps_categories where category = 'MEDIA'")
fun getMediaSystemApps(): List<CategorizedSystemApp>

@Transaction
fun upsertSystemAppCategories(
systemAppCategories: List<CategorizedSystemApp>,
) {
deleteSystemAppCategories()
insertSystemAppOverrides(systemAppCategories)
}

@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertSystemAppOverrides(
systemAppCategories: List<CategorizedSystemApp>,
)

@Query("DELETE from netp_system_apps_categories")
fun deleteSystemAppCategories()
}

@Entity(tableName = "netp_system_apps_categories")
data class CategorizedSystemApp(
@PrimaryKey val packageName: String,
val category: SystemAppCategory,
)

enum class SystemAppCategory {
COMMUNICATION,
NETWORKING,
MEDIA,
OTHERS,
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,20 @@ import com.squareup.moshi.Types

@Database(
exportSchema = true,
version = 3,
version = 4,
entities = [
NetPManuallyExcludedApp::class,
NetPConfigToggle::class,
NetPGeoswitchingLocation::class,
CategorizedSystemApp::class,
],
)
@TypeConverters(NetpDatabaseConverters::class)
abstract class NetPDatabase : RoomDatabase() {
abstract fun exclusionListDao(): NetPExclusionListDao
abstract fun configTogglesDao(): NetPConfigTogglesDao
abstract fun geoswitchingDao(): NetPGeoswitchingDao
abstract fun categorizedSystemAppsDao(): CategorizedSystemAppsDao

companion object {
val ALL_MIGRATIONS: List<Migration>
Expand All @@ -64,4 +66,18 @@ object NetpDatabaseConverters {
fun fromStringList(value: List<String>): String {
return stringListAdapter.toJson(value)
}

@TypeConverter
fun toSystemAppCategory(category: String): SystemAppCategory {
return try {
SystemAppCategory.valueOf(category)
} catch (ex: IllegalArgumentException) {
SystemAppCategory.OTHERS
}
}

@TypeConverter
fun fromStage(stage: SystemAppCategory): String {
return stage.name
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ enum class PrivacyFeatureName(val value: String) {
TrackingParametersFeatureName("trackingParameters"),
}

const val PRIVACY_REMOTE_CONFIG_URL = "https://staticcdn.duckduckgo.com/trackerblocking/config/v4/android-config.json"
const val PRIVACY_REMOTE_CONFIG_URL = "g"

0 comments on commit eca935d

Please sign in to comment.