Loading app/src/main/java/foundation/e/apps/data/gitlab/SystemAppsUpdatesRepository.kt 0 → 100644 +145 −0 Original line number Diff line number Diff line /* * 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 <https://www.gnu.org/licenses/>. */ 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.data.handleNetworkResult 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<SystemAppProject>() suspend fun fetchAllEligibleApps() { handleNetworkResult { val response = eligibleSystemAppsApi.getAllEligibleApps() if (response.isSuccessful && !response.body().isNullOrEmpty()) { response.body()?.let { systemAppProjectList.addAll(it) } } } } fun getAllEligibleApps(): List<String> { 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 systemAppInfo = systemAppDefinitionApi.getSystemAppUpdateInfo(projectId, releaseType).body() 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") null } else { 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<Application> { val updateList = mutableListOf<Application>() 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 } 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 } } No newline at end of file app/src/main/java/foundation/e/apps/di/network/RetrofitApiModule.kt +30 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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) } } app/src/main/java/foundation/e/apps/utils/SystemInfoProvider.kt +2 −0 Original line number Diff line number Diff line Loading @@ -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? { Loading Loading
app/src/main/java/foundation/e/apps/data/gitlab/SystemAppsUpdatesRepository.kt 0 → 100644 +145 −0 Original line number Diff line number Diff line /* * 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 <https://www.gnu.org/licenses/>. */ 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.data.handleNetworkResult 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<SystemAppProject>() suspend fun fetchAllEligibleApps() { handleNetworkResult { val response = eligibleSystemAppsApi.getAllEligibleApps() if (response.isSuccessful && !response.body().isNullOrEmpty()) { response.body()?.let { systemAppProjectList.addAll(it) } } } } fun getAllEligibleApps(): List<String> { 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 systemAppInfo = systemAppDefinitionApi.getSystemAppUpdateInfo(projectId, releaseType).body() 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") null } else { 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<Application> { val updateList = mutableListOf<Application>() 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 } 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 } } No newline at end of file
app/src/main/java/foundation/e/apps/di/network/RetrofitApiModule.kt +30 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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) } }
app/src/main/java/foundation/e/apps/utils/SystemInfoProvider.kt +2 −0 Original line number Diff line number Diff line Loading @@ -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? { Loading