From a7fb26d3011dae329e0fbff2143337036f4d2d7c Mon Sep 17 00:00:00 2001 From: Sayantan Roychowdhury Date: Mon, 8 Jul 2024 20:18:29 +0530 Subject: [PATCH 01/10] add new source - GITLAB --- .../foundation/e/apps/data/application/home/HomeApiImpl.kt | 5 +++++ app/src/main/java/foundation/e/apps/data/enums/Source.kt | 2 ++ 2 files changed, 7 insertions(+) diff --git a/app/src/main/java/foundation/e/apps/data/application/home/HomeApiImpl.kt b/app/src/main/java/foundation/e/apps/data/application/home/HomeApiImpl.kt index d8b91b173..4f94e2afd 100644 --- a/app/src/main/java/foundation/e/apps/data/application/home/HomeApiImpl.kt +++ b/app/src/main/java/foundation/e/apps/data/application/home/HomeApiImpl.kt @@ -120,6 +120,10 @@ class HomeApiImpl @Inject constructor( Source.PWA -> handleNetworkResult { handleCleanApkHomes(priorList, SearchApi.APP_TYPE_PWA) } + + Source.GITLAB -> { + ResultSupreme.Error(message = "Gitlab source not allowed") + } } setHomeErrorMessage(result.getResultStatus(), source) @@ -223,6 +227,7 @@ class HomeApiImpl @Inject constructor( if (apiStatus != ResultStatus.OK) { apiStatus.message = when (source) { Source.GPLAY -> ("GPlay home loading error\n" + apiStatus.message).trim() + Source.GITLAB -> ("Gitlab home not allowed\n" + apiStatus.message).trim() Source.OPEN -> ("Open Source home loading error\n" + apiStatus.message).trim() Source.PWA -> ("PWA home loading error\n" + apiStatus.message).trim() } diff --git a/app/src/main/java/foundation/e/apps/data/enums/Source.kt b/app/src/main/java/foundation/e/apps/data/enums/Source.kt index 86fd9c631..c672015c8 100644 --- a/app/src/main/java/foundation/e/apps/data/enums/Source.kt +++ b/app/src/main/java/foundation/e/apps/data/enums/Source.kt @@ -19,6 +19,7 @@ package foundation.e.apps.data.enums enum class Source { GPLAY, + GITLAB, OPEN, PWA; @@ -27,6 +28,7 @@ enum class Source { return when (source) { "Open Source" -> OPEN "PWA" -> PWA + "GITLAB" -> GITLAB else -> GPLAY } } -- GitLab From 02fd2c97b2a744a1bf8f59c12eb354f52019c9de Mon Sep 17 00:00:00 2001 From: Sayantan Roychowdhury Date: Thu, 11 Jul 2024 20:25:00 +0530 Subject: [PATCH 02/10] Introduce new Origin - GITLAB --- .../e/apps/data/application/ApplicationDataManager.kt | 1 + .../application/downloadInfo/DownloadInfoApiImpl.kt | 11 +++++++++++ .../main/java/foundation/e/apps/data/enums/Origin.kt | 3 ++- .../e/apps/domain/ValidateAppAgeLimitUseCase.kt | 8 ++++++++ .../model/ApplicationScreenshotsRVAdapter.kt | 1 + .../ui/applicationlist/ApplicationListRVAdapter.kt | 5 +++++ 6 files changed, 28 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/foundation/e/apps/data/application/ApplicationDataManager.kt b/app/src/main/java/foundation/e/apps/data/application/ApplicationDataManager.kt index b5daea536..15090a362 100644 --- a/app/src/main/java/foundation/e/apps/data/application/ApplicationDataManager.kt +++ b/app/src/main/java/foundation/e/apps/data/application/ApplicationDataManager.kt @@ -62,6 +62,7 @@ class ApplicationDataManager @Inject constructor( application.package_name.isBlank() -> FilterLevel.UNKNOWN !application.isFree && application.price.isBlank() -> FilterLevel.UI application.origin == Origin.CLEANAPK -> FilterLevel.NONE + application.origin == Origin.GITLAB -> FilterLevel.NONE !isRestricted(application) -> FilterLevel.NONE authData == null -> FilterLevel.UNKNOWN // cannot determine for gplay app !isApplicationVisible(application) -> FilterLevel.DATA diff --git a/app/src/main/java/foundation/e/apps/data/application/downloadInfo/DownloadInfoApiImpl.kt b/app/src/main/java/foundation/e/apps/data/application/downloadInfo/DownloadInfoApiImpl.kt index 896510856..b72d882a3 100644 --- a/app/src/main/java/foundation/e/apps/data/application/downloadInfo/DownloadInfoApiImpl.kt +++ b/app/src/main/java/foundation/e/apps/data/application/downloadInfo/DownloadInfoApiImpl.kt @@ -68,6 +68,10 @@ class DownloadInfoApiImpl @Inject constructor( Origin.GPLAY -> { updateDownloadInfoFromGplay(appInstall, list) } + + Origin.GITLAB -> { + updateDownloadInfoFromGitlab(appInstall, list) + } } appInstall.downloadURLList = list @@ -98,6 +102,13 @@ class DownloadInfoApiImpl @Inject constructor( appInstall.signature = downloadInfo?.download_data?.signature ?: "" } + private suspend fun updateDownloadInfoFromGitlab( + appInstall: AppInstall, + list: MutableList + ) { + // TODO + } + override suspend fun getOSSDownloadInfo(id: String, version: String?) = (appSources.cleanApkAppsRepo as CleanApkDownloadInfoFetcher) .getDownloadInfo(id, version) diff --git a/app/src/main/java/foundation/e/apps/data/enums/Origin.kt b/app/src/main/java/foundation/e/apps/data/enums/Origin.kt index b8bd98c83..eb2cdc782 100644 --- a/app/src/main/java/foundation/e/apps/data/enums/Origin.kt +++ b/app/src/main/java/foundation/e/apps/data/enums/Origin.kt @@ -20,5 +20,6 @@ package foundation.e.apps.data.enums enum class Origin { CLEANAPK, - GPLAY + GPLAY, + GITLAB, } diff --git a/app/src/main/java/foundation/e/apps/domain/ValidateAppAgeLimitUseCase.kt b/app/src/main/java/foundation/e/apps/domain/ValidateAppAgeLimitUseCase.kt index 994289f21..f852766c5 100644 --- a/app/src/main/java/foundation/e/apps/domain/ValidateAppAgeLimitUseCase.kt +++ b/app/src/main/java/foundation/e/apps/domain/ValidateAppAgeLimitUseCase.kt @@ -56,6 +56,10 @@ class ValidateAppAgeLimitUseCase @Inject constructor( data = ContentRatingValidity(true) ) + isGitlabApp(app) -> ResultSupreme.Success( + data = ContentRatingValidity(true) + ) + isKnownNsfwApp(app) -> ResultSupreme.Success(data = ContentRatingValidity(false)) isCleanApkApp(app) -> ResultSupreme.Success( data = ContentRatingValidity(isValid = !isNsfwAppByCleanApkApi(app)) @@ -70,6 +74,10 @@ class ValidateAppAgeLimitUseCase @Inject constructor( } } + private fun isGitlabApp(app: AppInstall): Boolean { + return app.origin == Origin.GITLAB + } + private fun isCleanApkApp(app: AppInstall): Boolean { return app.id.isNotBlank() && app.origin == Origin.CLEANAPK diff --git a/app/src/main/java/foundation/e/apps/ui/application/model/ApplicationScreenshotsRVAdapter.kt b/app/src/main/java/foundation/e/apps/ui/application/model/ApplicationScreenshotsRVAdapter.kt index 9fefd43d0..b9d452f39 100644 --- a/app/src/main/java/foundation/e/apps/ui/application/model/ApplicationScreenshotsRVAdapter.kt +++ b/app/src/main/java/foundation/e/apps/ui/application/model/ApplicationScreenshotsRVAdapter.kt @@ -58,6 +58,7 @@ class ApplicationScreenshotsRVAdapter( Origin.GPLAY -> { imageView.load(oldList[position]) } + else -> {} } imageView.setOnClickListener { val action = diff --git a/app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListRVAdapter.kt b/app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListRVAdapter.kt index 43cd66851..4bf26d12b 100644 --- a/app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListRVAdapter.kt +++ b/app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListRVAdapter.kt @@ -175,6 +175,11 @@ class ApplicationListRVAdapter( placeholder(shimmerDrawable) } } + Origin.GITLAB -> { + appIcon.load(searchApp.icon_image_path) { + placeholder(shimmerDrawable) + } + } else -> Timber.wtf("${searchApp.package_name} is from an unknown origin") } } -- GitLab From b5d6e624e9aec76dcff0af6c0269ac80367337cc Mon Sep 17 00:00:00 2001 From: Sayantan Roychowdhury Date: Sat, 13 Jul 2024 00:01:30 +0530 Subject: [PATCH 03/10] API for system apps --- .../apps/data/application/data/Application.kt | 11 +- .../apps/data/gitlab/EligibleSystemAppsApi.kt | 34 +++++ .../data/gitlab/SystemAppDefinitionApi.kt | 38 +++++ .../gitlab/SystemAppsUpdatesRepository.kt | 136 ++++++++++++++++++ .../apps/data/gitlab/models/SystemAppInfo.kt | 55 +++++++ .../data/gitlab/models/SystemAppProject.kt | 23 +++ .../e/apps/di/network/RetrofitApiModule.kt | 30 ++++ .../e/apps/utils/SystemInfoProvider.kt | 2 + app/src/main/res/values/strings.xml | 1 + 9 files changed, 327 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/foundation/e/apps/data/gitlab/EligibleSystemAppsApi.kt create mode 100644 app/src/main/java/foundation/e/apps/data/gitlab/SystemAppDefinitionApi.kt create mode 100644 app/src/main/java/foundation/e/apps/data/gitlab/SystemAppsUpdatesRepository.kt create mode 100644 app/src/main/java/foundation/e/apps/data/gitlab/models/SystemAppInfo.kt create mode 100644 app/src/main/java/foundation/e/apps/data/gitlab/models/SystemAppProject.kt diff --git a/app/src/main/java/foundation/e/apps/data/application/data/Application.kt b/app/src/main/java/foundation/e/apps/data/application/data/Application.kt index 2ff78b947..6eadaa1ee 100644 --- a/app/src/main/java/foundation/e/apps/data/application/data/Application.kt +++ b/app/src/main/java/foundation/e/apps/data/application/data/Application.kt @@ -105,6 +105,8 @@ data class Application( var contentRating: ContentRating = ContentRating(), @SerializedName(value = "antifeatures") val antiFeatures: List> = emptyList(), + + var isSystemApp: Boolean = false, ) { fun updateType() { this.type = if (this.is_pwa) PWA else NATIVE @@ -112,9 +114,12 @@ data class Application( fun updateSource(context: Context) { this.apply { - source = if (origin != Origin.CLEANAPK) "" - else if (is_pwa) context.getString(R.string.pwa) - else context.getString(R.string.open_source) + source = when { + origin == Origin.GITLAB -> context.getString(R.string.system_app) + origin == Origin.GPLAY -> "" + is_pwa -> context.getString(R.string.pwa) + else -> context.getString(R.string.open_source) + } } } } diff --git a/app/src/main/java/foundation/e/apps/data/gitlab/EligibleSystemAppsApi.kt b/app/src/main/java/foundation/e/apps/data/gitlab/EligibleSystemAppsApi.kt new file mode 100644 index 000000000..86d59ca89 --- /dev/null +++ b/app/src/main/java/foundation/e/apps/data/gitlab/EligibleSystemAppsApi.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2019-2023 E FOUNDATION + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package foundation.e.apps.data.gitlab + +import foundation.e.apps.data.gitlab.models.SystemAppProject +import retrofit2.Response +import retrofit2.http.GET + +interface EligibleSystemAppsApi { + + companion object { + const val BASE_URL = + "https://gitlab.e.foundation/e/os/system-apps-update-info/-/raw/main/" + } + + @GET("updatable_system_apps.json?inline=false") + suspend fun getAllEligibleApps(): Response> + +} \ No newline at end of file diff --git a/app/src/main/java/foundation/e/apps/data/gitlab/SystemAppDefinitionApi.kt b/app/src/main/java/foundation/e/apps/data/gitlab/SystemAppDefinitionApi.kt new file mode 100644 index 000000000..1cfaa4d0e --- /dev/null +++ b/app/src/main/java/foundation/e/apps/data/gitlab/SystemAppDefinitionApi.kt @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2019-2023 E FOUNDATION + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package foundation.e.apps.data.gitlab + +import foundation.e.apps.data.gitlab.models.SystemAppInfo +import retrofit2.Response +import retrofit2.http.GET +import retrofit2.http.Path + +interface SystemAppDefinitionApi { + + companion object { + const val BASE_URL = + "https://gitlab.e.foundation/api/v4/projects/" + } + + @GET("{projectId}/releases/permalink/latest/downloads/json/{releaseType}.json") + suspend fun getSystemAppUpdateInfo( + @Path("projectId") projectId: Int, + @Path("releaseType") releaseType: String, + ): Response + +} \ No newline at end of file diff --git a/app/src/main/java/foundation/e/apps/data/gitlab/SystemAppsUpdatesRepository.kt b/app/src/main/java/foundation/e/apps/data/gitlab/SystemAppsUpdatesRepository.kt new file mode 100644 index 000000000..bc91a6e6c --- /dev/null +++ b/app/src/main/java/foundation/e/apps/data/gitlab/SystemAppsUpdatesRepository.kt @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2019-2023 E FOUNDATION + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package foundation.e.apps.data.gitlab + +import android.content.Context +import android.os.Build +import dagger.hilt.android.qualifiers.ApplicationContext +import foundation.e.apps.data.application.ApplicationDataManager +import foundation.e.apps.data.application.data.Application +import foundation.e.apps.data.gitlab.models.SystemAppInfo +import foundation.e.apps.data.gitlab.models.SystemAppProject +import foundation.e.apps.data.gitlab.models.toApplication +import foundation.e.apps.install.pkg.AppLoungePackageManager +import foundation.e.apps.utils.SystemInfoProvider +import javax.inject.Inject +import javax.inject.Singleton +import timber.log.Timber + +@Singleton +class SystemAppsUpdatesRepository @Inject constructor( + @ApplicationContext private val context: Context, + private val eligibleSystemAppsApi: EligibleSystemAppsApi, + private val systemAppDefinitionApi: SystemAppDefinitionApi, + private val applicationDataManager: ApplicationDataManager, + private val appLoungePackageManager: AppLoungePackageManager, +) { + + private var systemAppProjectList = mutableListOf() + + suspend fun fetchAllEligibleApps() { + val response = eligibleSystemAppsApi.getAllEligibleApps() + if (response.isSuccessful && !response.body().isNullOrEmpty()) { + response.body()?.let { systemAppProjectList.addAll(it) } + } + } + + fun getAllEligibleApps(): List { + return systemAppProjectList.map { it.packageName } + } + + private fun isSystemAppBlacklisted( + systemAppInfo: SystemAppInfo, + sdkLevel: Int, + device: String, + ): Boolean { + return systemAppInfo.run { + sdkLevel < minSdk || + blacklistedAndroid?.contains(sdkLevel) == true || + blacklistedDevices?.contains(device) == true || + blacklistedDevices?.contains("${device}@${sdkLevel}") == true + } + } + + private suspend fun getSystemAppUpdateInfo( + packageName: String, + releaseType: String, + sdkLevel: Int, + device: String, + ): Application? { + + val projectId = + systemAppProjectList.find { it.packageName == packageName }?.projectId ?: return null + + val response = systemAppDefinitionApi.getSystemAppUpdateInfo(projectId, releaseType) + if (!response.isSuccessful) { + Timber.e("Failed to fetch system app update definition for: $packageName, $releaseType") + return null + } + + val systemAppInfo = response.body() ?: return null + + if (isSystemAppBlacklisted(systemAppInfo, sdkLevel, device)) { + Timber.e("Blacklisted system app: $packageName, $systemAppInfo") + return null + } + + return systemAppInfo.toApplication() + } + + private fun getSdkLevel(): Int { + return Build.VERSION.SDK_INT + } + + private fun getDevice(): String { + return SystemInfoProvider.getSystemProperty(SystemInfoProvider.KEY_LINEAGE_DEVICE) ?: "" + } + + private fun getSystemReleaseType(): String { + return SystemInfoProvider.getSystemProperty(SystemInfoProvider.KEY_LINEAGE_RELEASE_TYPE) ?: "" + } + + suspend fun getSystemUpdates(): List { + val updateList = mutableListOf() + val releaseType = getSystemReleaseType() + val sdkLevel = getSdkLevel() + val device = getDevice() + + val eligibleApps = getAllEligibleApps() + eligibleApps.forEach { + + if (!appLoungePackageManager.isInstalled(it)) { + // Don't install for system apps which are removed (by root or otherwise) + return@forEach + } + + getSystemAppUpdateInfo( + it, + releaseType, + sdkLevel, + device, + )?.run { + applicationDataManager.updateStatus(this) + updateList.add(this) + updateSource(context) + } + } + + return updateList + } + +} \ No newline at end of file diff --git a/app/src/main/java/foundation/e/apps/data/gitlab/models/SystemAppInfo.kt b/app/src/main/java/foundation/e/apps/data/gitlab/models/SystemAppInfo.kt new file mode 100644 index 000000000..e661b788a --- /dev/null +++ b/app/src/main/java/foundation/e/apps/data/gitlab/models/SystemAppInfo.kt @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2019-2023 E FOUNDATION + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package foundation.e.apps.data.gitlab.models + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties +import com.squareup.moshi.Json +import foundation.e.apps.data.application.data.Application +import foundation.e.apps.data.enums.FilterLevel +import foundation.e.apps.data.enums.Origin +import java.util.UUID + +@JsonIgnoreProperties(ignoreUnknown = true) +data class SystemAppInfo( + val name: String, + @Json(name = "package_name") val packageName: String, + @Json(name = "version_code") val versionCode: Int, + @Json(name = "min_sdk") val minSdk: Int, + @Json(name = "version_name") val versionName: String, + @Json(name = "url") val downloadUrl: String, + val priority: Boolean?, + @Json(name = "blacklisted_android") val blacklistedAndroid: List?, + @Json(name = "blacklisted_devices") val blacklistedDevices: List?, +) + +fun SystemAppInfo.toApplication(): Application { + return Application( + _id = UUID.randomUUID().toString(), + author = "Murena SAS", + description = "", + latest_version_code = versionCode, + latest_version_number = versionName, + name = name, + package_name = packageName, + origin = Origin.GITLAB, + originalSize = 1, // so that the app is not filtered out, + url = downloadUrl, + isSystemApp = true, + filterLevel = FilterLevel.NONE, + ) +} \ No newline at end of file diff --git a/app/src/main/java/foundation/e/apps/data/gitlab/models/SystemAppProject.kt b/app/src/main/java/foundation/e/apps/data/gitlab/models/SystemAppProject.kt new file mode 100644 index 000000000..b6c0a723d --- /dev/null +++ b/app/src/main/java/foundation/e/apps/data/gitlab/models/SystemAppProject.kt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2019-2023 E FOUNDATION + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package foundation.e.apps.data.gitlab.models + +data class SystemAppProject( + val packageName: String, + val projectId: Int, +) diff --git a/app/src/main/java/foundation/e/apps/di/network/RetrofitApiModule.kt b/app/src/main/java/foundation/e/apps/di/network/RetrofitApiModule.kt index 576302cc9..d0e3ff85c 100644 --- a/app/src/main/java/foundation/e/apps/di/network/RetrofitApiModule.kt +++ b/app/src/main/java/foundation/e/apps/di/network/RetrofitApiModule.kt @@ -29,6 +29,8 @@ import foundation.e.apps.data.cleanapk.CleanApkRetrofit import foundation.e.apps.data.ecloud.EcloudApiInterface import foundation.e.apps.data.exodus.ExodusTrackerApi import foundation.e.apps.data.fdroid.FdroidApiInterface +import foundation.e.apps.data.gitlab.EligibleSystemAppsApi +import foundation.e.apps.data.gitlab.SystemAppDefinitionApi import foundation.e.apps.data.parentalcontrol.fdroid.FDroidMonitorApi import foundation.e.apps.data.parentalcontrol.googleplay.AgeGroupApi import foundation.e.apps.di.network.NetworkModule.getYamlFactory @@ -131,4 +133,32 @@ class RetrofitApiModule { .create(FDroidMonitorApi::class.java) } + @Singleton + @Provides + fun provideEligibleSystemAppsApi( + okHttpClient: OkHttpClient, + moshi: Moshi, + ): EligibleSystemAppsApi { + return Retrofit.Builder() + .baseUrl(EligibleSystemAppsApi.BASE_URL) + .client(okHttpClient) + .addConverterFactory(MoshiConverterFactory.create(moshi)) + .build() + .create(EligibleSystemAppsApi::class.java) + } + + @Singleton + @Provides + fun provideSystemAppDefinitionApi( + okHttpClient: OkHttpClient, + moshi: Moshi, + ): SystemAppDefinitionApi { + return Retrofit.Builder() + .baseUrl(SystemAppDefinitionApi.BASE_URL) + .client(okHttpClient) + .addConverterFactory(MoshiConverterFactory.create(moshi)) + .build() + .create(SystemAppDefinitionApi::class.java) + } + } diff --git a/app/src/main/java/foundation/e/apps/utils/SystemInfoProvider.kt b/app/src/main/java/foundation/e/apps/utils/SystemInfoProvider.kt index 68b72945d..bf9fe2efe 100644 --- a/app/src/main/java/foundation/e/apps/utils/SystemInfoProvider.kt +++ b/app/src/main/java/foundation/e/apps/utils/SystemInfoProvider.kt @@ -25,6 +25,8 @@ import org.json.JSONObject object SystemInfoProvider { const val KEY_LINEAGE_VERSION = "ro.lineage.version" + const val KEY_LINEAGE_RELEASE_TYPE = "ro.lineage.releasetype" + const val KEY_LINEAGE_DEVICE = "ro.lineage.device" @SuppressLint("PrivateApi") fun getSystemProperty(key: String?): String? { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 85f7f2bb8..993dcea40 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -120,6 +120,7 @@ Open Source apps Some proprietary apps may also have an Open Source version. Whenever this happens App Lounge shows the Open Source version only, in order to avoid duplicates. Downloading… + System app Additional file for %s Having troubles? https://doc.e.foundation/support-topics/app_lounge_troubleshooting -- GitLab From cb6be449f2d0d2a6c78974efccf794fdf3dc957c Mon Sep 17 00:00:00 2001 From: Sayantan Roychowdhury Date: Sat, 13 Jul 2024 00:11:32 +0530 Subject: [PATCH 04/10] init from MainActivityViewModel --- app/src/main/java/foundation/e/apps/MainActivity.kt | 1 + .../java/foundation/e/apps/ui/MainActivityViewModel.kt | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/app/src/main/java/foundation/e/apps/MainActivity.kt b/app/src/main/java/foundation/e/apps/MainActivity.kt index f4f0988ec..d6d5522d3 100644 --- a/app/src/main/java/foundation/e/apps/MainActivity.kt +++ b/app/src/main/java/foundation/e/apps/MainActivity.kt @@ -125,6 +125,7 @@ class MainActivity : AppCompatActivity() { viewModel.updateAppWarningList() viewModel.updateContentRatings() + viewModel.updateEligibleSystemAppsList() observeEvents() diff --git a/app/src/main/java/foundation/e/apps/ui/MainActivityViewModel.kt b/app/src/main/java/foundation/e/apps/ui/MainActivityViewModel.kt index 474308fee..d1c94c499 100644 --- a/app/src/main/java/foundation/e/apps/ui/MainActivityViewModel.kt +++ b/app/src/main/java/foundation/e/apps/ui/MainActivityViewModel.kt @@ -39,6 +39,7 @@ import foundation.e.apps.data.ecloud.EcloudRepository import foundation.e.apps.data.enums.User import foundation.e.apps.data.enums.isInitialized import foundation.e.apps.data.enums.isUnFiltered +import foundation.e.apps.data.gitlab.SystemAppsUpdatesRepository import foundation.e.apps.data.install.AppManagerWrapper import foundation.e.apps.data.install.models.AppInstall import foundation.e.apps.data.parentalcontrol.fdroid.FDroidAntiFeatureRepository @@ -64,6 +65,7 @@ class MainActivityViewModel @Inject constructor( private val gPlayContentRatingRepository: GPlayContentRatingRepository, private val fDroidAntiFeatureRepository: FDroidAntiFeatureRepository, private val appInstallProcessor: AppInstallProcessor, + private val systemAppsUpdatesRepository: SystemAppsUpdatesRepository, ) : ViewModel() { val tocStatus: LiveData = appLoungeDataStore.tocStatus.asLiveData() @@ -247,6 +249,12 @@ class MainActivityViewModel @Inject constructor( } } + fun updateEligibleSystemAppsList() { + viewModelScope.launch { + systemAppsUpdatesRepository.fetchAllEligibleApps() + } + } + fun getAppNameByPackageName(packageName: String): String { return appLoungePackageManager.getAppNameFromPackageName(packageName) } -- GitLab From f21de93ec6ca0b40fb1780d0a6317fedf55bc6e4 Mon Sep 17 00:00:00 2001 From: Sayantan Roychowdhury Date: Sat, 13 Jul 2024 00:13:38 +0530 Subject: [PATCH 05/10] fetch system apps updates from UpdatesManagerImpl --- .../e/apps/data/updates/UpdatesManagerImpl.kt | 32 +++++++++++++++++-- .../install/updates/UpdatesWorkManager.kt | 7 ++-- .../e/apps/install/updates/UpdatesWorker.kt | 9 ++++++ 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/data/updates/UpdatesManagerImpl.kt b/app/src/main/java/foundation/e/apps/data/updates/UpdatesManagerImpl.kt index 7cc60ac31..3e075ef2d 100644 --- a/app/src/main/java/foundation/e/apps/data/updates/UpdatesManagerImpl.kt +++ b/app/src/main/java/foundation/e/apps/data/updates/UpdatesManagerImpl.kt @@ -34,6 +34,7 @@ import foundation.e.apps.data.playstore.PlayStoreRepositoryImpl import foundation.e.apps.data.application.ApplicationRepository import foundation.e.apps.data.application.search.SearchApi.Companion.APP_TYPE_ANY import foundation.e.apps.data.application.data.Application +import foundation.e.apps.data.gitlab.SystemAppsUpdatesRepository import foundation.e.apps.data.handleNetworkResult import foundation.e.apps.data.preference.AppLoungePreference import foundation.e.apps.install.pkg.AppLoungePackageManager @@ -53,6 +54,7 @@ class UpdatesManagerImpl @Inject constructor( private val appLoungePreference: AppLoungePreference, private val fdroidRepository: FdroidRepository, private val blockedAppRepository: BlockedAppRepository, + private val systemAppsUpdatesRepository: SystemAppsUpdatesRepository, ) { companion object { @@ -123,8 +125,12 @@ class UpdatesManagerImpl @Inject constructor( status = if (status == ResultStatus.OK) status else gplayStatus } + val systemApps = getSystemUpdates() val nonFaultyUpdateList = faultyAppRepository.removeFaultyApps(updateList) - return Pair(nonFaultyUpdateList, status) + + arrangeWithSystemApps(updateList, nonFaultyUpdateList, systemApps) + + return Pair(updateList, status) } suspend fun getUpdatesOSS(): Pair, ResultStatus> { @@ -157,8 +163,30 @@ class UpdatesManagerImpl @Inject constructor( }, updateList) } + val systemApps = getSystemUpdates() val nonFaultyUpdateList = faultyAppRepository.removeFaultyApps(updateList) - return Pair(nonFaultyUpdateList, status) + + arrangeWithSystemApps(updateList, nonFaultyUpdateList, systemApps) + + return Pair(updateList, status) + } + + private suspend fun getSystemUpdates(): List { + val systemApps = mutableListOf() + getUpdatesFromApi({ + Pair(systemAppsUpdatesRepository.getSystemUpdates(), ResultStatus.OK) + }, systemApps) + return systemApps + } + + private fun arrangeWithSystemApps( + updateList: MutableList, + nonFaultyApps: List, + systemApps: List, + ) { + updateList.clear() + updateList.addAll(nonFaultyApps) + updateList.addAll(systemApps) } /** diff --git a/app/src/main/java/foundation/e/apps/install/updates/UpdatesWorkManager.kt b/app/src/main/java/foundation/e/apps/install/updates/UpdatesWorkManager.kt index fa41365ed..9cac39769 100644 --- a/app/src/main/java/foundation/e/apps/install/updates/UpdatesWorkManager.kt +++ b/app/src/main/java/foundation/e/apps/install/updates/UpdatesWorkManager.kt @@ -47,8 +47,11 @@ object UpdatesWorkManager { return OneTimeWorkRequest.Builder(UpdatesWorker::class.java).apply { setConstraints(buildWorkerConstraints()) addTag(USER_TAG) - }.setInputData(Data.Builder().putBoolean(UpdatesWorker.IS_AUTO_UPDATE, false).build()) - .build() + }.setInputData( + Data.Builder() + .putBoolean(UpdatesWorker.IS_AUTO_UPDATE, false) + .build() + ).build() } private fun buildWorkerConstraints() = Constraints.Builder().apply { diff --git a/app/src/main/java/foundation/e/apps/install/updates/UpdatesWorker.kt b/app/src/main/java/foundation/e/apps/install/updates/UpdatesWorker.kt index ee181a81a..88acbb49a 100644 --- a/app/src/main/java/foundation/e/apps/install/updates/UpdatesWorker.kt +++ b/app/src/main/java/foundation/e/apps/install/updates/UpdatesWorker.kt @@ -20,6 +20,7 @@ import foundation.e.apps.data.blockedApps.BlockedAppRepository import foundation.e.apps.data.enums.ResultStatus import foundation.e.apps.data.enums.User import foundation.e.apps.data.application.data.Application +import foundation.e.apps.data.gitlab.SystemAppsUpdatesRepository import foundation.e.apps.data.login.AuthenticatorRepository import foundation.e.apps.data.preference.DataStoreManager import foundation.e.apps.data.updates.UpdatesManagerRepository @@ -40,6 +41,7 @@ class UpdatesWorker @AssistedInject constructor( private val authenticatorRepository: AuthenticatorRepository, private val appInstallProcessor: AppInstallProcessor, private val blockedAppRepository: BlockedAppRepository, + private val systemAppsUpdatesRepository: SystemAppsUpdatesRepository, ) : CoroutineWorker(context, params) { companion object { @@ -62,6 +64,7 @@ class UpdatesWorker @AssistedInject constructor( } refreshBlockedAppList() + refreshEligibleSystemApps() checkForUpdates() Result.success() } catch (e: Throwable) { @@ -80,6 +83,12 @@ class UpdatesWorker @AssistedInject constructor( } } + private suspend fun refreshEligibleSystemApps() { + if (systemAppsUpdatesRepository.getAllEligibleApps().isEmpty()) { + systemAppsUpdatesRepository.fetchAllEligibleApps() + } + } + private suspend fun checkManualUpdateRunning(): Boolean { val workInfos = withContext(Dispatchers.IO) { -- GitLab From 98961cda173d13b32919e435f821b2d89f629ff1 Mon Sep 17 00:00:00 2001 From: Sayantan Roychowdhury Date: Sat, 13 Jul 2024 00:15:16 +0530 Subject: [PATCH 06/10] fixes for downloading system apps --- .../data/application/downloadInfo/DownloadInfoApiImpl.kt | 9 +-------- .../e/apps/install/workmanager/AppInstallProcessor.kt | 2 +- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/data/application/downloadInfo/DownloadInfoApiImpl.kt b/app/src/main/java/foundation/e/apps/data/application/downloadInfo/DownloadInfoApiImpl.kt index b72d882a3..5e64b98c6 100644 --- a/app/src/main/java/foundation/e/apps/data/application/downloadInfo/DownloadInfoApiImpl.kt +++ b/app/src/main/java/foundation/e/apps/data/application/downloadInfo/DownloadInfoApiImpl.kt @@ -70,7 +70,7 @@ class DownloadInfoApiImpl @Inject constructor( } Origin.GITLAB -> { - updateDownloadInfoFromGitlab(appInstall, list) + return // nothing to do as downloadURLList is already set } } @@ -102,13 +102,6 @@ class DownloadInfoApiImpl @Inject constructor( appInstall.signature = downloadInfo?.download_data?.signature ?: "" } - private suspend fun updateDownloadInfoFromGitlab( - appInstall: AppInstall, - list: MutableList - ) { - // TODO - } - override suspend fun getOSSDownloadInfo(id: String, version: String?) = (appSources.cleanApkAppsRepo as CleanApkDownloadInfoFetcher) .getDownloadInfo(id, version) diff --git a/app/src/main/java/foundation/e/apps/install/workmanager/AppInstallProcessor.kt b/app/src/main/java/foundation/e/apps/install/workmanager/AppInstallProcessor.kt index 83d9d7e94..1ede4bffc 100644 --- a/app/src/main/java/foundation/e/apps/install/workmanager/AppInstallProcessor.kt +++ b/app/src/main/java/foundation/e/apps/install/workmanager/AppInstallProcessor.kt @@ -97,7 +97,7 @@ class AppInstallProcessor @Inject constructor( it.contentRating = application.contentRating } - if (appInstall.type == Type.PWA) { + if (appInstall.type == Type.PWA || application.isSystemApp) { appInstall.downloadURLList = mutableListOf(application.url) } -- GitLab From fea022a54c1b2d89f985539b08949bad2c26f212 Mon Sep 17 00:00:00 2001 From: Sayantan Roychowdhury Date: Sat, 13 Jul 2024 00:15:36 +0530 Subject: [PATCH 07/10] UI changes --- .../ApplicationListRVAdapter.kt | 30 +++++++++++++++++-- .../e/apps/ui/updates/UpdatesFragment.kt | 9 +++++- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListRVAdapter.kt b/app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListRVAdapter.kt index 4bf26d12b..dd5010bee 100644 --- a/app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListRVAdapter.kt +++ b/app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListRVAdapter.kt @@ -20,8 +20,10 @@ package foundation.e.apps.ui.applicationlist import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.ImageView import androidx.core.content.ContextCompat import androidx.core.view.children +import androidx.core.view.isVisible import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData @@ -176,14 +178,24 @@ class ApplicationListRVAdapter( } } Origin.GITLAB -> { - appIcon.load(searchApp.icon_image_path) { - placeholder(shimmerDrawable) - } + setSystemAppIcon(appIcon, searchApp) } else -> Timber.wtf("${searchApp.package_name} is from an unknown origin") } } + private fun setSystemAppIcon(imageView: ImageView, app: Application) { + if (!app.isSystemApp) return + try { + imageView.run { + setImageDrawable(context.packageManager.getApplicationIcon(app.package_name)) + } + } catch (e: Exception) { + Timber.w("Icon could not be set for system app - ${app.package_name} - ${e.message}") + e.printStackTrace() + } + } + private fun ApplicationListItemBinding.updateAppInfo(searchApp: Application) { appTitle.text = searchApp.name appInfoFetchViewModel.getAuthorName(searchApp).observe(lifecycleOwner!!) { @@ -192,6 +204,11 @@ class ApplicationListRVAdapter( } private fun ApplicationListItemBinding.updateRating(searchApp: Application) { + if (searchApp.isSystemApp) { + iconStar.isVisible = false + appRating.isVisible = false + return + } if (searchApp.ratings.usageQualityScore != -1.0) { appRating.text = searchApp.ratings.usageQualityScore.toString() } else { @@ -203,6 +220,10 @@ class ApplicationListRVAdapter( searchApp: Application, view: View ) { + if (searchApp.isSystemApp) { + appPrivacyScoreLayout.isVisible = false + return + } if (searchApp.ratings.privacyScore != -1.0) { appPrivacyScore.text = view.context.getString( R.string.privacy_rating_out_of, @@ -224,6 +245,9 @@ class ApplicationListRVAdapter( searchApp: Application, view: View ) { + if (searchApp.isSystemApp) { + return + } val catText = searchApp.category.ifBlank { optionalCategory } val action = when (currentDestinationId) { R.id.applicationListFragment -> { diff --git a/app/src/main/java/foundation/e/apps/ui/updates/UpdatesFragment.kt b/app/src/main/java/foundation/e/apps/ui/updates/UpdatesFragment.kt index fc68ab0b2..e0ced31eb 100644 --- a/app/src/main/java/foundation/e/apps/ui/updates/UpdatesFragment.kt +++ b/app/src/main/java/foundation/e/apps/ui/updates/UpdatesFragment.kt @@ -133,7 +133,14 @@ class UpdatesFragment : TimeoutFragment(R.layout.fragment_updates), ApplicationI private fun observeUpdateList(listAdapter: ApplicationListRVAdapter?) { updatesViewModel.updatesList.observe(viewLifecycleOwner) { - listAdapter?.setData(it.first) + + val updateList = it.first + + // Put system apps on top + val appsToDisplay = updateList.filter { it.isSystemApp } + + updateList.filter { !it.isSystemApp } + + listAdapter?.setData(appsToDisplay) if (!isDownloadObserverAdded) { handleStateNoUpdates(it.first) observeDownloadList() -- GitLab From 7cdf58bad42c5424dccfab13d2c519ce98c0e571 Mon Sep 17 00:00:00 2001 From: Sayantan Roychowdhury Date: Mon, 15 Jul 2024 21:04:03 +0530 Subject: [PATCH 08/10] reduce return statements --- .../gitlab/SystemAppsUpdatesRepository.kt | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/data/gitlab/SystemAppsUpdatesRepository.kt b/app/src/main/java/foundation/e/apps/data/gitlab/SystemAppsUpdatesRepository.kt index bc91a6e6c..c6e762011 100644 --- a/app/src/main/java/foundation/e/apps/data/gitlab/SystemAppsUpdatesRepository.kt +++ b/app/src/main/java/foundation/e/apps/data/gitlab/SystemAppsUpdatesRepository.kt @@ -76,20 +76,18 @@ class SystemAppsUpdatesRepository @Inject constructor( val projectId = systemAppProjectList.find { it.packageName == packageName }?.projectId ?: return null - val response = systemAppDefinitionApi.getSystemAppUpdateInfo(projectId, releaseType) - if (!response.isSuccessful) { - Timber.e("Failed to fetch system app update definition for: $packageName, $releaseType") - return null - } - - val systemAppInfo = response.body() ?: return null + val systemAppInfo = + systemAppDefinitionApi.getSystemAppUpdateInfo(projectId, releaseType).body() - if (isSystemAppBlacklisted(systemAppInfo, sdkLevel, device)) { + return if (systemAppInfo == null) { + Timber.e("Null app info for: $packageName") + null + } else if (isSystemAppBlacklisted(systemAppInfo, sdkLevel, device)) { Timber.e("Blacklisted system app: $packageName, $systemAppInfo") - return null + null + } else { + systemAppInfo.toApplication() } - - return systemAppInfo.toApplication() } private fun getSdkLevel(): Int { -- GitLab From cf8efa72827ffc5410152a861d947de6496e3583 Mon Sep 17 00:00:00 2001 From: Sayantan Roychowdhury Date: Mon, 15 Jul 2024 21:07:30 +0530 Subject: [PATCH 09/10] wrap in handleNetworkResult --- .../gitlab/SystemAppsUpdatesRepository.kt | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/data/gitlab/SystemAppsUpdatesRepository.kt b/app/src/main/java/foundation/e/apps/data/gitlab/SystemAppsUpdatesRepository.kt index c6e762011..b4ac63964 100644 --- a/app/src/main/java/foundation/e/apps/data/gitlab/SystemAppsUpdatesRepository.kt +++ b/app/src/main/java/foundation/e/apps/data/gitlab/SystemAppsUpdatesRepository.kt @@ -25,6 +25,7 @@ import foundation.e.apps.data.application.data.Application import foundation.e.apps.data.gitlab.models.SystemAppInfo import foundation.e.apps.data.gitlab.models.SystemAppProject import foundation.e.apps.data.gitlab.models.toApplication +import foundation.e.apps.data.handleNetworkResult import foundation.e.apps.install.pkg.AppLoungePackageManager import foundation.e.apps.utils.SystemInfoProvider import javax.inject.Inject @@ -43,9 +44,11 @@ class SystemAppsUpdatesRepository @Inject constructor( private var systemAppProjectList = mutableListOf() suspend fun fetchAllEligibleApps() { - val response = eligibleSystemAppsApi.getAllEligibleApps() - if (response.isSuccessful && !response.body().isNullOrEmpty()) { - response.body()?.let { systemAppProjectList.addAll(it) } + handleNetworkResult { + val response = eligibleSystemAppsApi.getAllEligibleApps() + if (response.isSuccessful && !response.body().isNullOrEmpty()) { + response.body()?.let { systemAppProjectList.addAll(it) } + } } } @@ -116,16 +119,24 @@ class SystemAppsUpdatesRepository @Inject constructor( return@forEach } - getSystemAppUpdateInfo( - it, - releaseType, - sdkLevel, - device, - )?.run { + val result = handleNetworkResult { + getSystemAppUpdateInfo( + it, + releaseType, + sdkLevel, + device, + ) + } + + result.data?.run { applicationDataManager.updateStatus(this) updateList.add(this) updateSource(context) } + + if (!result.isSuccess()) { + Timber.e("Failed to get system app info for $it - ${result.message}") + } } return updateList -- GitLab From 2778855d5140f901dd43b7a2d3c925db05e836a6 Mon Sep 17 00:00:00 2001 From: Sayantan Roychowdhury Date: Mon, 15 Jul 2024 21:08:15 +0530 Subject: [PATCH 10/10] fix tests --- .../e/apps/UpdateManagerImptTest.kt | 76 ++++++++++++++++--- 1 file changed, 66 insertions(+), 10 deletions(-) diff --git a/app/src/test/java/foundation/e/apps/UpdateManagerImptTest.kt b/app/src/test/java/foundation/e/apps/UpdateManagerImptTest.kt index 214e3ee21..e22dbe538 100644 --- a/app/src/test/java/foundation/e/apps/UpdateManagerImptTest.kt +++ b/app/src/test/java/foundation/e/apps/UpdateManagerImptTest.kt @@ -30,6 +30,7 @@ import foundation.e.apps.data.fdroid.FdroidRepository import foundation.e.apps.data.application.ApplicationRepository import foundation.e.apps.data.application.search.SearchApi import foundation.e.apps.data.application.data.Application +import foundation.e.apps.data.gitlab.SystemAppsUpdatesRepository import foundation.e.apps.data.updates.UpdatesManagerImpl import foundation.e.apps.util.MainCoroutineRule import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -78,6 +79,9 @@ class UpdateManagerImptTest { @Mock private lateinit var fdroidRepository: FdroidRepository + @Mock + private lateinit var systemAppsUpdatesRepository: SystemAppsUpdatesRepository + val authData = AuthData("e@e.email", "AtadyMsIAtadyM") @Before @@ -93,27 +97,40 @@ class UpdateManagerImptTest { faultyAppRepository, preferenceModule, fdroidRepository, - blockedAppRepository + blockedAppRepository, + systemAppsUpdatesRepository, ) } + private fun getSystemApps(status: Status = Status.UPDATABLE) = mutableListOf( + Application( + status = status, + name = "Demo Four", + package_name = "foundation.e.demofour", + origin = Origin.GITLAB, + filterLevel = FilterLevel.NONE + ) + ) + @Test fun getUpdateWhenUpdateIsAvailable() = runTest { val gplayApps = getGplayApps() val openSourceApps = getOpenSourceApps(Status.UPDATABLE) + val systemAppUpdates = getSystemApps() val openSourceUpdates = Pair(openSourceApps, ResultStatus.OK) val gplayUpdates = Pair(gplayApps, ResultStatus.OK) setupMockingForFetchingUpdates( openSourceUpdates, - gplayUpdates + gplayUpdates, + systemAppUpdates ) val updateResult = updatesManagerImpl.getUpdates(authData) System.out.println("===> updates: ${updateResult.first.map { it.package_name }}") - assertEquals("fetchUpdate", 2, updateResult.first.size) + assertEquals("fetchUpdate", 3, updateResult.first.size) } private fun getGplayApps(status: Status = Status.UPDATABLE) = mutableListOf( @@ -140,6 +157,8 @@ class UpdateManagerImptTest { val authData = AuthData("e@e.email", "AtadyMsIAtadyM") pkgManagerModule.applicationInfo.clear() + setupMockingSystemApps() + val updateResult = updatesManagerImpl.getUpdates(authData) System.out.println("===> updates: ${updateResult.first.map { it.package_name }}") @@ -150,13 +169,15 @@ class UpdateManagerImptTest { fun getUpdateWhenUpdateIsUnavailable() = runTest { val gplayApps = getGplayApps(Status.INSTALLED) val openSourceApps = getOpenSourceApps(Status.INSTALLED) + val systemAppUpdates = getSystemApps(Status.INSTALLED) val openSourceUpdates = Pair(openSourceApps, ResultStatus.OK) val gplayUpdates = Pair(gplayApps, ResultStatus.OK) setupMockingForFetchingUpdates( openSourceUpdates, - gplayUpdates + gplayUpdates, + systemAppUpdates, ) val updateResult = updatesManagerImpl.getUpdates(authData) @@ -169,36 +190,59 @@ class UpdateManagerImptTest { fun getUpdateWhenUpdateHasOnlyForOpenSourceApps() = runTest { val gplayApps = getGplayApps(Status.INSTALLED) val openSourceApps = getOpenSourceApps(Status.UPDATABLE) + val systemAppUpdates = getSystemApps(Status.INSTALLED) val openSourceUpdates = Pair(openSourceApps, ResultStatus.OK) val gplayUpdates = Pair(gplayApps, ResultStatus.OK) setupMockingForFetchingUpdates( openSourceUpdates, - gplayUpdates + gplayUpdates, + systemAppUpdates, ) val updateResult = updatesManagerImpl.getUpdates(authData) System.out.println("===> updates: ${updateResult.first.map { it.package_name }}") - assertFalse("fetchupdate", updateResult.first.any { it.origin == Origin.GPLAY }) + assertFalse("fetchupdate", updateResult.first.any { it.origin != Origin.CLEANAPK }) } @Test fun getUpdateWhenUpdateHasOnlyForGplayApps() = runTest { val gplayApps = getGplayApps(Status.UPDATABLE) val openSourceApps = getOpenSourceApps(Status.INSTALLED) + val systemAppUpdates = getSystemApps(Status.INSTALLED) val openSourceUpdates = Pair(openSourceApps, ResultStatus.OK) val gplayUpdates = Pair(gplayApps, ResultStatus.OK) setupMockingForFetchingUpdates( openSourceUpdates, - gplayUpdates + gplayUpdates, + systemAppUpdates, + ) + + val updateResult = updatesManagerImpl.getUpdates(authData) + assertFalse("fetchupdate", updateResult.first.any { it.origin != Origin.GPLAY }) + } + + @Test + fun getUpdateWhenUpdateHasOnlySystemApps() = runTest { + val gplayApps = getGplayApps(Status.INSTALLED) + val openSourceApps = getOpenSourceApps(Status.INSTALLED) + val systemAppUpdates = getSystemApps(Status.UPDATABLE) + + val openSourceUpdates = Pair(openSourceApps, ResultStatus.OK) + val gplayUpdates = Pair(gplayApps, ResultStatus.OK) + + setupMockingForFetchingUpdates( + openSourceUpdates, + gplayUpdates, + systemAppUpdates, ) val updateResult = updatesManagerImpl.getUpdates(authData) - assertFalse("fetchupdate", updateResult.first.any { it.origin == Origin.CLEANAPK }) + assertFalse("fetchupdate", updateResult.first.any { it.origin != Origin.GITLAB }) } @Test @@ -274,15 +318,17 @@ class UpdateManagerImptTest { fun getUpdatesOSSWhenUpdateIsAvailable() = runTest { val openSourceApps = getOpenSourceApps(Status.UPDATABLE) val gPlayApps = getGplayApps(Status.UPDATABLE) + val systemAppUpdates = getSystemApps() val openSourceUpdates = Pair(openSourceApps, ResultStatus.OK) val gplayUpdates = Pair(gPlayApps, ResultStatus.OK) - setupMockingForFetchingUpdates(openSourceUpdates, gplayUpdates) + setupMockingForFetchingUpdates(openSourceUpdates, gplayUpdates, systemAppUpdates) val updateResult = updatesManagerImpl.getUpdatesOSS() - assertEquals("UpdateOSS", 1, updateResult.first.size) + assertEquals("UpdateOSS", 2, updateResult.first.size) assertEquals("UpdateOSS", Origin.CLEANAPK, updateResult.first[0].origin) + assertEquals("UpdateOSS", Origin.GITLAB, updateResult.first[1].origin) } @Test @@ -317,6 +363,7 @@ class UpdateManagerImptTest { private suspend fun setupMockingForFetchingUpdates( openSourceUpdates: Pair, ResultStatus>, gplayUpdates: Pair, ResultStatus>, + systemAppUpdates: MutableList = mutableListOf(), selectedApplicationSources: List = mutableListOf( SearchApi.APP_TYPE_ANY, SearchApi.APP_TYPE_OPEN, @@ -334,6 +381,8 @@ class UpdateManagerImptTest { Mockito.`when`(applicationRepository.getSelectedAppTypes()) .thenReturn(selectedApplicationSources) + setupMockingSystemApps(systemAppUpdates) + if (gplayUpdates.first.isNotEmpty()) { Mockito.`when`( applicationRepository.getApplicationDetails( @@ -357,4 +406,11 @@ class UpdateManagerImptTest { ).thenReturn(Pair(Application(), ResultStatus.TIMEOUT)) } } + + private suspend fun setupMockingSystemApps( + systemAppUpdates: MutableList = mutableListOf() + ) { + Mockito.`when`(systemAppsUpdatesRepository.getSystemUpdates()) + .thenReturn(systemAppUpdates) + } } -- GitLab