Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eb26be9f authored by Sayantan Roychowdhury's avatar Sayantan Roychowdhury
Browse files

System apps repository

parent 05428c89
Loading
Loading
Loading
Loading
+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
+30 −0
Original line number Diff line number Diff line
@@ -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)
    }

}
+2 −0
Original line number Diff line number Diff line
@@ -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? {