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

Commit 35dbeb5e authored by Vincent Bourgmayer's avatar Vincent Bourgmayer
Browse files

Merge branch '2696-make-BL3-updatable-v2' into 'main'

feature: Allow update of project depending on specific Android API like BlissLauncher3

See merge request !502
parents 4430f8a5 df400e22
Loading
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -42,7 +42,7 @@ def getSentryDsn = { ->
}

android {
    compileSdk 33
    compileSdk 34

    defaultConfig {
        applicationId "foundation.e.apps"
+5 −3
Original line number Diff line number Diff line
@@ -17,11 +17,14 @@

package foundation.e.apps.data.gitlab

import foundation.e.apps.data.gitlab.models.ReleaseInfo
import foundation.e.apps.data.gitlab.models.GitLabReleaseInfo
import retrofit2.Response
import retrofit2.http.GET
import retrofit2.http.Path

/*
Provides GitLab API client method (https://docs.gitlab.com/ee/api/releases/)
 */
interface ReleaseInfoApi {

    companion object {
@@ -32,6 +35,5 @@ interface ReleaseInfoApi {
    @GET("{projectId}/releases")
    suspend fun getReleases(
        @Path("projectId") projectId: Int,
    ): Response<List<ReleaseInfo>>

    ): Response<List<GitLabReleaseInfo>>
}
+71 −22
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ 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.UpdatableSystemAppsApi.*
import foundation.e.apps.data.gitlab.models.OsReleaseType
import foundation.e.apps.data.gitlab.models.SystemAppInfo
import foundation.e.apps.data.gitlab.models.SystemAppProject
@@ -43,6 +44,15 @@ class SystemAppsUpdatesRepository @Inject constructor(
    private val releaseInfoApi: ReleaseInfoApi,
) {

    private val androidVersionCode by lazy {
        try { getAndroidVersionCodeChar() }
        catch (exception: UnsupportedAndroidApiException) {
            Timber.w(exception.message,
                "Android API isn't in supported range to update some system apps")
            "UnsupportedAndroidAPI"
        }
    }

    private val systemAppProjectList = mutableListOf<SystemAppProject>()

    private fun getUpdatableSystemApps(): List<String> {
@@ -55,13 +65,7 @@ class SystemAppsUpdatesRepository @Inject constructor(
                return@handleNetworkResult
            }

            val systemName = getFullSystemName()
            val endPoint = if (isEligibleToFetchAppListFromTest(systemName)) {
                UpdatableSystemAppsApi.EndPoint.ENDPOINT_TEST
            } else {
                UpdatableSystemAppsApi.EndPoint.ENDPOINT_RELEASE
            }

            val endPoint = getUpdatableSystemAppEndPoint()
            val response = updatableSystemAppsApi.getUpdatableSystemApps(endPoint)

            if (response.isSuccessful && !response.body().isNullOrEmpty()) {
@@ -77,6 +81,15 @@ class SystemAppsUpdatesRepository @Inject constructor(
        }
    }

    private fun getUpdatableSystemAppEndPoint(): EndPoint {
        val systemName = getFullSystemName()
        return if (isEligibleToFetchAppListFromTest(systemName)) {
            EndPoint.ENDPOINT_TEST
        } else {
            EndPoint.ENDPOINT_RELEASE
        }
    }

    private fun isEligibleToFetchAppListFromTest(systemName: String) = systemName.isBlank() ||
            systemName.contains("beta") ||
            systemName.contains("rc") ||
@@ -96,17 +109,23 @@ class SystemAppsUpdatesRepository @Inject constructor(
    }

    private suspend fun getReleaseDetailsUrl(
        projectId: Int,
        systemAppProject: SystemAppProject,
        releaseType: OsReleaseType,
    ): String? {
        val projectId = systemAppProject.projectId
        val releaseResponse = releaseInfoApi.getReleases(projectId)
        val releases = releaseResponse.body()
        var releases = releaseResponse.body()

        if (!releaseResponse.isSuccessful || releases == null) {
            Timber.e("Failed to fetch releases for project id - $projectId")
            return null
        }

        if (systemAppProject.dependsOnAndroidVersion) {
            val versionSuffix = "-$androidVersionCode"
            releases = releases.filter { isVersionedTag(it.tagName, versionSuffix) }
        }

        val sortedReleases = releases.sortedByDescending {
            it.releasedAt
        }
@@ -120,25 +139,23 @@ class SystemAppsUpdatesRepository @Inject constructor(
        return null
    }

    private suspend fun getSystemAppUpdateInfo(
    private fun isVersionedTag(tag: String, versionSuffix: String): Boolean {
        return tag.endsWith(suffix = versionSuffix, ignoreCase = true)
    }

    private suspend fun getApplication(
        packageName: String,
        releaseType: OsReleaseType,
        sdkLevel: Int,
        device: String,
    ): Application? {

        val projectId =
            systemAppProjectList.find { it.packageName == packageName }?.projectId ?: return null

        val detailsUrl = getReleaseDetailsUrl(projectId, releaseType) ?: return null
        val systemAppProject = systemAppProjectList.find { it.packageName == packageName } ?: return null
        val detailsUrl = getReleaseDetailsUrl(systemAppProject, releaseType) ?: return null

        val response = systemAppDefinitionApi.getSystemAppUpdateInfo(detailsUrl)
        val systemAppInfo = response.body()
        val systemAppInfo = getSystemAppInfo(packageName, detailsUrl) ?: return null

        return if (systemAppInfo == null) {
            Timber.e("Null app info for: $packageName, response: ${response.errorBody()?.string()}")
            null
        } else if (isSystemAppBlocked(systemAppInfo, sdkLevel, device)) {
        return if (isSystemAppBlocked(systemAppInfo, sdkLevel, device)) {
            Timber.e("Blocked system app: $packageName, details: $systemAppInfo")
            null
        } else {
@@ -146,6 +163,20 @@ class SystemAppsUpdatesRepository @Inject constructor(
        }
    }

    private suspend fun getSystemAppInfo(
        packageName: String,
        detailsUrl: String
    ): SystemAppInfo? {
        val response = systemAppDefinitionApi.getSystemAppUpdateInfo(detailsUrl)

        return if (response.isSuccessful) {
            response.body()
        } else {
            Timber.e("Can't get AppInfo for $packageName, response: ${response.errorBody()?.string()}")
            null
        }
    }

    private fun getFullSystemName(): String {
        return SystemInfoProvider.getSystemProperty(SystemInfoProvider.KEY_LINEAGE_VERSION) ?: ""
    }
@@ -164,6 +195,23 @@ class SystemAppsUpdatesRepository @Inject constructor(
        }
    }

    /**
     * This method must be updated when Murena or /e/ foundation support new Android version
     * or stop to support an old one
     */
    private fun getAndroidVersionCodeChar(): String {
        /* TODO manually add new supported android version when they will be supported.
        * VANILLA_ICE_CREAM (A15) => https://gitlab.e.foundation/e/os/backlog/-/issues/2772
        * BAKLAVA (A16) => https://gitlab.e.foundation/e/os/backlog/-/issues/2773
        */
        return when (val currentAPI = Build.VERSION.SDK_INT) {
            Build.VERSION_CODES.S, Build.VERSION_CODES.S_V2 -> "S"
            Build.VERSION_CODES.TIRAMISU -> "T"
            Build.VERSION_CODES.UPSIDE_DOWN_CAKE -> "U"
            else -> throw UnsupportedAndroidApiException("API level $currentAPI is not supported")
        }
    }

    suspend fun getSystemUpdates(): List<Application> {
        val updateList = mutableListOf<Application>()
        val releaseType = getSystemReleaseType()
@@ -179,7 +227,7 @@ class SystemAppsUpdatesRepository @Inject constructor(
            }

            val result = handleNetworkResult {
                getSystemAppUpdateInfo(
                getApplication(
                    it,
                    releaseType,
                    sdkLevel,
@@ -200,5 +248,6 @@ class SystemAppsUpdatesRepository @Inject constructor(

        return updateList
    }

}

private class UnsupportedAndroidApiException(message: String) : RuntimeException(message)
 No newline at end of file
+3 −3
Original line number Diff line number Diff line
@@ -19,10 +19,10 @@ package foundation.e.apps.data.gitlab.models

import com.squareup.moshi.Json

data class ReleaseInfo(
data class GitLabReleaseInfo(
    val name: String,
    @Json(name = "released_at")
    val releasedAt: String,
    @Json(name = "tag_name") val tagName: String,
    @Json(name = "released_at") val releasedAt: String,
    val assets: ReleaseAssets,
) {
    fun getAssetWebLink(assetName: String): String? {
+1 −0
Original line number Diff line number Diff line
@@ -20,4 +20,5 @@ package foundation.e.apps.data.gitlab.models
data class SystemAppProject(
    val packageName: String,
    val projectId: Int,
    val dependsOnAndroidVersion: Boolean = false
)