Loading app/src/main/java/foundation/e/apps/PrivacyInfoViewModel.kt +15 −7 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ import foundation.e.apps.api.Result import foundation.e.apps.api.exodus.models.AppPrivacyInfo import foundation.e.apps.api.exodus.repositories.IAppPrivacyInfoRepository import foundation.e.apps.api.fused.data.FusedApp import foundation.e.apps.utils.modules.CommonUtilsModule.LIST_OF_NULL import javax.inject.Inject import kotlin.math.ceil import kotlin.math.round Loading @@ -27,8 +28,8 @@ class PrivacyInfoViewModel @Inject constructor( private suspend fun fetchEmitAppPrivacyInfo( fusedApp: FusedApp ): Result<AppPrivacyInfo> { if (fusedApp.trackers.isNotEmpty() && fusedApp.perms.isNotEmpty()) { val appInfo = AppPrivacyInfo(fusedApp.trackers, fusedApp.perms) if (fusedApp.trackers.isNotEmpty() && fusedApp.permsFromExodus.isNotEmpty()) { val appInfo = AppPrivacyInfo(fusedApp.trackers, fusedApp.permsFromExodus) return Result.success(appInfo) } val appPrivacyPrivacyInfoResult = Loading @@ -51,10 +52,14 @@ class PrivacyInfoViewModel @Inject constructor( appPrivacyPrivacyInfoResult: Result<AppPrivacyInfo>, fusedApp: FusedApp ): Result<AppPrivacyInfo> { fusedApp.trackers = appPrivacyPrivacyInfoResult.data?.trackerList ?: listOf() if (fusedApp.perms.isEmpty()) { fusedApp.perms = appPrivacyPrivacyInfoResult.data?.permissionList ?: listOf() fusedApp.trackers = appPrivacyPrivacyInfoResult.data?.trackerList ?: LIST_OF_NULL fusedApp.permsFromExodus = appPrivacyPrivacyInfoResult.data?.permissionList ?: LIST_OF_NULL if (fusedApp.perms.isEmpty() && fusedApp.permsFromExodus != LIST_OF_NULL) { /* * fusedApp.perms is generally populated from remote source like Play Store. * If it is empty then set the value from permissions from exodus api. */ fusedApp.perms = fusedApp.permsFromExodus } return appPrivacyPrivacyInfoResult } Loading @@ -76,6 +81,9 @@ class PrivacyInfoViewModel @Inject constructor( } fun calculatePrivacyScore(fusedApp: FusedApp): Int { if (fusedApp.permsFromExodus == LIST_OF_NULL) { return -1 } val calculateTrackersScore = calculateTrackersScore(fusedApp.trackers.size) val calculatePermissionsScore = calculatePermissionsScore( countAndroidPermissions(fusedApp) Loading @@ -88,7 +96,7 @@ class PrivacyInfoViewModel @Inject constructor( } private fun countAndroidPermissions(fusedApp: FusedApp) = fusedApp.perms.filter { it.contains("android.permission") }.size fusedApp.permsFromExodus.filter { it.contains("android.permission") }.size private fun calculateTrackersScore(numberOfTrackers: Int): Int { return if (numberOfTrackers > 5) 0 else 9 - numberOfTrackers Loading app/src/main/java/foundation/e/apps/api/exodus/repositories/AppPrivacyInfoRepositoryImpl.kt +11 −1 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ import foundation.e.apps.api.exodus.Tracker import foundation.e.apps.api.exodus.TrackerDao import foundation.e.apps.api.exodus.models.AppPrivacyInfo import foundation.e.apps.api.getResult import foundation.e.apps.utils.modules.CommonUtilsModule.LIST_OF_NULL import javax.inject.Inject import javax.inject.Singleton Loading Loading @@ -70,8 +71,17 @@ class AppPrivacyInfoRepositoryImpl @Inject constructor( private fun getAppPrivacyInfo( appTrackerData: List<Report>, ): AppPrivacyInfo { /* * If the response is empty, that means there is no data on Exodus API about this app, * i.e. invalid data. * We signal this by list of "null". * It is not enough to send just empty lists, as an app can actually have zero trackers * and zero permissions. This is not to be confused with invalid data. * * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5136 */ if (appTrackerData.isEmpty()) { return AppPrivacyInfo() return AppPrivacyInfo(LIST_OF_NULL, LIST_OF_NULL) } val sortedTrackerData = appTrackerData.sortedByDescending { trackerData -> trackerData.versionCode.toLong() } Loading app/src/main/java/foundation/e/apps/api/fused/data/FusedApp.kt +12 −1 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ package foundation.e.apps.api.fused.data import foundation.e.apps.utils.enums.Origin import foundation.e.apps.utils.enums.Status import foundation.e.apps.utils.enums.Type import foundation.e.apps.utils.modules.CommonUtilsModule.LIST_OF_NULL data class FusedApp( val _id: String = String(), Loading Loading @@ -51,5 +52,15 @@ data class FusedApp( var pwaPlayerDbId: Long = -1, val url: String = String(), var type: Type = Type.NATIVE, var privacyScore: Int = -1 var privacyScore: Int = -1, /* * List of permissions from Exodus API. * This list is now used to calculate the privacy score instead of perms variable above. * If the value is LIST_OF_NULL - listOf("null"), it means no data is available in Exodus API for this package, * hence display "N/A" * * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5136 */ var permsFromExodus: List<String> = LIST_OF_NULL, ) app/src/main/java/foundation/e/apps/application/ApplicationFragment.kt +6 −2 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ import foundation.e.apps.manager.pkg.PkgManagerModule import foundation.e.apps.utils.enums.Origin import foundation.e.apps.utils.enums.Status import foundation.e.apps.utils.enums.User import foundation.e.apps.utils.modules.CommonUtilsModule.LIST_OF_NULL import foundation.e.apps.utils.modules.PWAManagerModule import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch Loading Loading @@ -231,10 +232,13 @@ class ApplicationFragment : Fragment(R.layout.fragment_application) { ).show(childFragmentManager, TAG) } appTrackers.setOnClickListener { val fusedApp = applicationViewModel.fusedApp.value var trackers = privacyInfoViewModel.getTrackerListText(applicationViewModel.fusedApp.value) privacyInfoViewModel.getTrackerListText(fusedApp) if (trackers.isNotEmpty()) { if (fusedApp?.trackers == LIST_OF_NULL) { trackers = getString(R.string.tracker_information_not_found) } else if (trackers.isNotEmpty()) { trackers += "<br /> <br />" + getString( R.string.privacy_computed_using_text, EXODUS_URL Loading app/src/main/java/foundation/e/apps/applicationlist/model/ApplicationListRVAdapter.kt +3 −2 Original line number Diff line number Diff line Loading @@ -246,8 +246,9 @@ class ApplicationListRVAdapter( ) { privacyInfoViewModel.getAppPrivacyInfoLiveData(searchApp).observe(lifecycleOwner) { showPrivacyScore() if (it.isSuccess()) { searchApp.privacyScore = privacyInfoViewModel.calculatePrivacyScore(searchApp) val calculatedScore = privacyInfoViewModel.calculatePrivacyScore(searchApp) if (it.isSuccess() && calculatedScore != -1) { searchApp.privacyScore = calculatedScore appPrivacyScore.text = view.context.getString( R.string.privacy_rating_out_of, searchApp.privacyScore.toString() Loading Loading
app/src/main/java/foundation/e/apps/PrivacyInfoViewModel.kt +15 −7 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ import foundation.e.apps.api.Result import foundation.e.apps.api.exodus.models.AppPrivacyInfo import foundation.e.apps.api.exodus.repositories.IAppPrivacyInfoRepository import foundation.e.apps.api.fused.data.FusedApp import foundation.e.apps.utils.modules.CommonUtilsModule.LIST_OF_NULL import javax.inject.Inject import kotlin.math.ceil import kotlin.math.round Loading @@ -27,8 +28,8 @@ class PrivacyInfoViewModel @Inject constructor( private suspend fun fetchEmitAppPrivacyInfo( fusedApp: FusedApp ): Result<AppPrivacyInfo> { if (fusedApp.trackers.isNotEmpty() && fusedApp.perms.isNotEmpty()) { val appInfo = AppPrivacyInfo(fusedApp.trackers, fusedApp.perms) if (fusedApp.trackers.isNotEmpty() && fusedApp.permsFromExodus.isNotEmpty()) { val appInfo = AppPrivacyInfo(fusedApp.trackers, fusedApp.permsFromExodus) return Result.success(appInfo) } val appPrivacyPrivacyInfoResult = Loading @@ -51,10 +52,14 @@ class PrivacyInfoViewModel @Inject constructor( appPrivacyPrivacyInfoResult: Result<AppPrivacyInfo>, fusedApp: FusedApp ): Result<AppPrivacyInfo> { fusedApp.trackers = appPrivacyPrivacyInfoResult.data?.trackerList ?: listOf() if (fusedApp.perms.isEmpty()) { fusedApp.perms = appPrivacyPrivacyInfoResult.data?.permissionList ?: listOf() fusedApp.trackers = appPrivacyPrivacyInfoResult.data?.trackerList ?: LIST_OF_NULL fusedApp.permsFromExodus = appPrivacyPrivacyInfoResult.data?.permissionList ?: LIST_OF_NULL if (fusedApp.perms.isEmpty() && fusedApp.permsFromExodus != LIST_OF_NULL) { /* * fusedApp.perms is generally populated from remote source like Play Store. * If it is empty then set the value from permissions from exodus api. */ fusedApp.perms = fusedApp.permsFromExodus } return appPrivacyPrivacyInfoResult } Loading @@ -76,6 +81,9 @@ class PrivacyInfoViewModel @Inject constructor( } fun calculatePrivacyScore(fusedApp: FusedApp): Int { if (fusedApp.permsFromExodus == LIST_OF_NULL) { return -1 } val calculateTrackersScore = calculateTrackersScore(fusedApp.trackers.size) val calculatePermissionsScore = calculatePermissionsScore( countAndroidPermissions(fusedApp) Loading @@ -88,7 +96,7 @@ class PrivacyInfoViewModel @Inject constructor( } private fun countAndroidPermissions(fusedApp: FusedApp) = fusedApp.perms.filter { it.contains("android.permission") }.size fusedApp.permsFromExodus.filter { it.contains("android.permission") }.size private fun calculateTrackersScore(numberOfTrackers: Int): Int { return if (numberOfTrackers > 5) 0 else 9 - numberOfTrackers Loading
app/src/main/java/foundation/e/apps/api/exodus/repositories/AppPrivacyInfoRepositoryImpl.kt +11 −1 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ import foundation.e.apps.api.exodus.Tracker import foundation.e.apps.api.exodus.TrackerDao import foundation.e.apps.api.exodus.models.AppPrivacyInfo import foundation.e.apps.api.getResult import foundation.e.apps.utils.modules.CommonUtilsModule.LIST_OF_NULL import javax.inject.Inject import javax.inject.Singleton Loading Loading @@ -70,8 +71,17 @@ class AppPrivacyInfoRepositoryImpl @Inject constructor( private fun getAppPrivacyInfo( appTrackerData: List<Report>, ): AppPrivacyInfo { /* * If the response is empty, that means there is no data on Exodus API about this app, * i.e. invalid data. * We signal this by list of "null". * It is not enough to send just empty lists, as an app can actually have zero trackers * and zero permissions. This is not to be confused with invalid data. * * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5136 */ if (appTrackerData.isEmpty()) { return AppPrivacyInfo() return AppPrivacyInfo(LIST_OF_NULL, LIST_OF_NULL) } val sortedTrackerData = appTrackerData.sortedByDescending { trackerData -> trackerData.versionCode.toLong() } Loading
app/src/main/java/foundation/e/apps/api/fused/data/FusedApp.kt +12 −1 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ package foundation.e.apps.api.fused.data import foundation.e.apps.utils.enums.Origin import foundation.e.apps.utils.enums.Status import foundation.e.apps.utils.enums.Type import foundation.e.apps.utils.modules.CommonUtilsModule.LIST_OF_NULL data class FusedApp( val _id: String = String(), Loading Loading @@ -51,5 +52,15 @@ data class FusedApp( var pwaPlayerDbId: Long = -1, val url: String = String(), var type: Type = Type.NATIVE, var privacyScore: Int = -1 var privacyScore: Int = -1, /* * List of permissions from Exodus API. * This list is now used to calculate the privacy score instead of perms variable above. * If the value is LIST_OF_NULL - listOf("null"), it means no data is available in Exodus API for this package, * hence display "N/A" * * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5136 */ var permsFromExodus: List<String> = LIST_OF_NULL, )
app/src/main/java/foundation/e/apps/application/ApplicationFragment.kt +6 −2 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ import foundation.e.apps.manager.pkg.PkgManagerModule import foundation.e.apps.utils.enums.Origin import foundation.e.apps.utils.enums.Status import foundation.e.apps.utils.enums.User import foundation.e.apps.utils.modules.CommonUtilsModule.LIST_OF_NULL import foundation.e.apps.utils.modules.PWAManagerModule import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch Loading Loading @@ -231,10 +232,13 @@ class ApplicationFragment : Fragment(R.layout.fragment_application) { ).show(childFragmentManager, TAG) } appTrackers.setOnClickListener { val fusedApp = applicationViewModel.fusedApp.value var trackers = privacyInfoViewModel.getTrackerListText(applicationViewModel.fusedApp.value) privacyInfoViewModel.getTrackerListText(fusedApp) if (trackers.isNotEmpty()) { if (fusedApp?.trackers == LIST_OF_NULL) { trackers = getString(R.string.tracker_information_not_found) } else if (trackers.isNotEmpty()) { trackers += "<br /> <br />" + getString( R.string.privacy_computed_using_text, EXODUS_URL Loading
app/src/main/java/foundation/e/apps/applicationlist/model/ApplicationListRVAdapter.kt +3 −2 Original line number Diff line number Diff line Loading @@ -246,8 +246,9 @@ class ApplicationListRVAdapter( ) { privacyInfoViewModel.getAppPrivacyInfoLiveData(searchApp).observe(lifecycleOwner) { showPrivacyScore() if (it.isSuccess()) { searchApp.privacyScore = privacyInfoViewModel.calculatePrivacyScore(searchApp) val calculatedScore = privacyInfoViewModel.calculatePrivacyScore(searchApp) if (it.isSuccess() && calculatedScore != -1) { searchApp.privacyScore = calculatedScore appPrivacyScore.text = view.context.getString( R.string.privacy_rating_out_of, searchApp.privacyScore.toString() Loading