From 184e4af9ddaf40cb1286317bcd938840aff3e215 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Thu, 10 Oct 2024 16:07:22 +0200 Subject: [PATCH 01/16] feature: Add new gitlab API client method also refactor SystemAppDefinitionApi to use const based placeholder in URL --- .../data/gitlab/SystemAppDefinitionApi.kt | 37 +++++++++++++++++-- .../gitlab/SystemAppsUpdatesRepository.kt | 2 +- 2 files changed, 34 insertions(+), 5 deletions(-) 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 index b5f7d48b4..79e98c148 100644 --- a/app/src/main/java/foundation/e/apps/data/gitlab/SystemAppDefinitionApi.kt +++ b/app/src/main/java/foundation/e/apps/data/gitlab/SystemAppDefinitionApi.kt @@ -22,17 +22,46 @@ import retrofit2.Response import retrofit2.http.GET import retrofit2.http.Path +/* +Those API method client must fit with gitlab releases API +https://docs.gitlab.com/ee/api/releases/#download-a-release-asset +TODO Option to consider at the end of the implementation: +Can we rename this interface into: GitlabReleaseApi ? + */ interface SystemAppDefinitionApi { companion object { const val BASE_URL = "https://gitlab.e.foundation/api/v4/projects/" + + private const val PROJECT_ID_PLACEHOLDER = "projectId" + private const val RELEASE_TYPE_PLACEHOLDER = "releaseType" + private const val TAG_NAME_PLACEHOLDER = "gitlabTagName" + + private const val LIST_RELEASES_URL_SEGMENT = + "{$PROJECT_ID_PLACEHOLDER}/releases" + private const val UPDATE_INFO_BY_TAG_URL_SEGMENT = + "{$PROJECT_ID_PLACEHOLDER}/releases/{$TAG_NAME_PLACEHOLDER}/downloads/json/{$RELEASE_TYPE_PLACEHOLDER}.json" + private const val LATEST_UPDATE_INFO_URL_SEGMENT = + "{$PROJECT_ID_PLACEHOLDER}/releases/permalink/latest/downloads/json/{$RELEASE_TYPE_PLACEHOLDER}.json" } - @GET("{projectId}/releases/permalink/latest/downloads/json/{releaseType}.json") - suspend fun getSystemAppUpdateInfo( - @Path("projectId") projectId: Int, - @Path("releaseType") releaseType: String, + + @GET(LIST_RELEASES_URL_SEGMENT) + suspend fun getSystemAppReleases( + @Path(PROJECT_ID_PLACEHOLDER) projectId: Int + )//: Response<@TODO> + + @GET(UPDATE_INFO_BY_TAG_URL_SEGMENT) + suspend fun getSystemAppUpdateInfoByTag( + @Path(PROJECT_ID_PLACEHOLDER) projectId: Int, + @Path(TAG_NAME_PLACEHOLDER) gitlabTagName: String, + @Path(RELEASE_TYPE_PLACEHOLDER) releaseType: String, ): Response + @GET(LATEST_UPDATE_INFO_URL_SEGMENT) + suspend fun getLatestSystemAppUpdateInfo( + @Path(PROJECT_ID_PLACEHOLDER) projectId: Int, + @Path(RELEASE_TYPE_PLACEHOLDER) releaseType: String, + ): Response } 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 53a642dec..3474fb9d4 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 @@ -103,7 +103,7 @@ class SystemAppsUpdatesRepository @Inject constructor( val projectId = systemAppProjectList.find { it.packageName == packageName }?.projectId ?: return null - val response = systemAppDefinitionApi.getSystemAppUpdateInfo(projectId, releaseType) + val response = systemAppDefinitionApi.getLatestSystemAppUpdateInfo(projectId, releaseType) val systemAppInfo = response.body() return if (systemAppInfo == null) { -- GitLab From 3ee5860ba20bb679a6cc9ea4132f3b29903401af Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Thu, 10 Oct 2024 16:40:41 +0200 Subject: [PATCH 02/16] feature: add GitlabReleaseInfo as data class. Use it as return type for SystemAppDefinitionApi.kt->getStstelAppReleases(...) --- .../e/apps/data/gitlab/SystemAppDefinitionApi.kt | 3 ++- .../e/apps/data/gitlab/models/GitlabReleaseInfo.kt | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/foundation/e/apps/data/gitlab/models/GitlabReleaseInfo.kt 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 index 79e98c148..7df0235e4 100644 --- a/app/src/main/java/foundation/e/apps/data/gitlab/SystemAppDefinitionApi.kt +++ b/app/src/main/java/foundation/e/apps/data/gitlab/SystemAppDefinitionApi.kt @@ -17,6 +17,7 @@ package foundation.e.apps.data.gitlab +import foundation.e.apps.data.gitlab.models.GitlabReleaseInfo import foundation.e.apps.data.gitlab.models.SystemAppInfo import retrofit2.Response import retrofit2.http.GET @@ -50,7 +51,7 @@ interface SystemAppDefinitionApi { @GET(LIST_RELEASES_URL_SEGMENT) suspend fun getSystemAppReleases( @Path(PROJECT_ID_PLACEHOLDER) projectId: Int - )//: Response<@TODO> + ): Response> @GET(UPDATE_INFO_BY_TAG_URL_SEGMENT) suspend fun getSystemAppUpdateInfoByTag( diff --git a/app/src/main/java/foundation/e/apps/data/gitlab/models/GitlabReleaseInfo.kt b/app/src/main/java/foundation/e/apps/data/gitlab/models/GitlabReleaseInfo.kt new file mode 100644 index 000000000..8cb4b58c4 --- /dev/null +++ b/app/src/main/java/foundation/e/apps/data/gitlab/models/GitlabReleaseInfo.kt @@ -0,0 +1,14 @@ +package foundation.e.apps.data.gitlab.models + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties +import com.squareup.moshi.Json +import java.util.Date + + +@JsonIgnoreProperties(ignoreUnknown = true) +data class GitlabReleaseInfo( + @Json(name = "tag_name") val tagName: String, + @Json(name = "name") val releaseName: String, + @Json(name = "created_at") val createdAt: Date, + @Json(name = "released_at") val releasedAt: Date, +) -- GitLab From b7928470a6af81f33e55832e8c45e57f9bcb271f Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Thu, 10 Oct 2024 16:47:11 +0200 Subject: [PATCH 03/16] refactor: extract code from fetch UpdatableSystemApps() into dedicated method: getUpdatableSystemAppEndPoint() --- .../data/gitlab/SystemAppsUpdatesRepository.kt | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 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 3474fb9d4..63e54a371 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 @@ -53,13 +53,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()) { @@ -75,6 +69,16 @@ class SystemAppsUpdatesRepository @Inject constructor( } } + private fun getUpdatableSystemAppEndPoint(): UpdatableSystemAppsApi.EndPoint { + val systemName = getFullSystemName() + return if (isEligibleToFetchAppListFromTest(systemName) + ) { + UpdatableSystemAppsApi.EndPoint.ENDPOINT_TEST + } else { + UpdatableSystemAppsApi.EndPoint.ENDPOINT_RELEASE + } + } + private fun isEligibleToFetchAppListFromTest(systemName: String) = systemName.isBlank() || systemName.contains("beta") || systemName.contains("rc") || -- GitLab From 24ac8eaef8476c6cb9b393d9fe0291c4fc7be822 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Thu, 10 Oct 2024 17:21:06 +0200 Subject: [PATCH 04/16] feature: add new property to SystemAppProject.kt to know if the apps depends on Android version --- .../foundation/e/apps/data/gitlab/models/SystemAppProject.kt | 1 + 1 file changed, 1 insertion(+) 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 index edc7f2bff..054a869f5 100644 --- 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 @@ -20,4 +20,5 @@ package foundation.e.apps.data.gitlab.models data class SystemAppProject( val packageName: String, val projectId: Int, + val dependsOnAndroidVersion: Boolean = false ) -- GitLab From 09862d43736af8786d56bfecbd051fc5e4465e10 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Thu, 10 Oct 2024 18:32:36 +0200 Subject: [PATCH 05/16] feature: add method to SystemAppUpdateRepository to fetch release for system app which depends on Android version --- .../gitlab/SystemAppsUpdatesRepository.kt | 58 +++++++++++++++++-- 1 file changed, 53 insertions(+), 5 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 63e54a371..46faee1a0 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 @@ -22,12 +22,14 @@ 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.GitlabReleaseInfo 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 retrofit2.Response import javax.inject.Inject import javax.inject.Singleton import timber.log.Timber @@ -40,7 +42,6 @@ class SystemAppsUpdatesRepository @Inject constructor( private val applicationDataManager: ApplicationDataManager, private val appLoungePackageManager: AppLoungePackageManager, ) { - private val systemAppProjectList = mutableListOf() private fun getUpdatableSystemApps(): List { @@ -104,11 +105,15 @@ class SystemAppsUpdatesRepository @Inject constructor( device: String, ): Application? { - val projectId = - systemAppProjectList.find { it.packageName == packageName }?.projectId ?: return null + val systemAppProject = systemAppProjectList.find { it.packageName == packageName } ?: return null + - val response = systemAppDefinitionApi.getLatestSystemAppUpdateInfo(projectId, releaseType) - val systemAppInfo = response.body() + val response = getSystemAppInfo(systemAppProject, releaseType) + if (response == null) { //todo refactor to avoid checking this + Timber.e("Can't get latest release for : $packageName") + return null + } + val systemAppInfo = response?.body() return if (systemAppInfo == null) { Timber.e("Null app info for: $packageName, response: ${response.errorBody()?.string()}") @@ -121,6 +126,49 @@ class SystemAppsUpdatesRepository @Inject constructor( } } + private suspend fun getSystemAppInfo(systemAppProject: SystemAppProject, releaseType: String): Response? { + val projectId = systemAppProject.projectId + + return if (systemAppProject.dependsOnAndroidVersion) { + val latestRelease = getLatestSystemAppReleaseByAndroidVersion(projectId) + if (latestRelease == null) { + null //todo replace by an error code to avoid to check for nullity in calling method ? + } else { + val releaseTag = latestRelease.tagName + systemAppDefinitionApi.getSystemAppUpdateInfoByTag(projectId, releaseTag, releaseType) + } + + } else { + systemAppDefinitionApi.getLatestSystemAppUpdateInfo(projectId, releaseType) + } + } + + //todo: rename & rewrite ? + private suspend fun getLatestSystemAppReleaseByAndroidVersion(projectId: Int): GitlabReleaseInfo? { + val gitlabReleaseList = systemAppDefinitionApi.getSystemAppReleases(projectId).body() + + val latestRelease = gitlabReleaseList?.filter { + it.tagName.contains("api${getAndroidVersion()}-") + }?.sortedByDescending { it.releasedAt }?.first() + + return latestRelease + } + + /* + todo: this method cannot match upper version. UPSIDE_DOWN_CAKE or VANILLA or note available + through BUILD.VERSIO_CODES (may be due to targeted SDK or minimum SDK.) + todo: This method shouldn't be called for each app. We need to define it only once! + */ + private fun getAndroidVersion(): String { + return when (Build.VERSION.SDK_INT) { + Build.VERSION_CODES.Q -> "Q" + Build.VERSION_CODES.R -> "R" + Build.VERSION_CODES.S -> "S" + Build.VERSION_CODES.TIRAMISU -> "T" + else -> "unknown" + } + } + private fun getFullSystemName(): String { return SystemInfoProvider.getSystemProperty(SystemInfoProvider.KEY_LINEAGE_VERSION) ?: "" } -- GitLab From f4b0b21be3410082faeb24c760c00d13e2dabbc5 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Fri, 11 Oct 2024 09:48:03 +0200 Subject: [PATCH 06/16] refactor: apply rabbit suggestion --- .../data/gitlab/SystemAppsUpdatesRepository.kt | 17 ++++++++--------- .../data/gitlab/models/GitlabReleaseInfo.kt | 11 +++++------ 2 files changed, 13 insertions(+), 15 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 46faee1a0..675b19729 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 @@ -44,6 +44,8 @@ class SystemAppsUpdatesRepository @Inject constructor( ) { private val systemAppProjectList = mutableListOf() + private val androidVersionCode by lazy { getAndroidVersionCodeChar() } + private fun getUpdatableSystemApps(): List { return systemAppProjectList.map { it.packageName } } @@ -130,7 +132,7 @@ class SystemAppsUpdatesRepository @Inject constructor( val projectId = systemAppProject.projectId return if (systemAppProject.dependsOnAndroidVersion) { - val latestRelease = getLatestSystemAppReleaseByAndroidVersion(projectId) + val latestRelease = getLatestReleaseByAndroidVersion(projectId) if (latestRelease == null) { null //todo replace by an error code to avoid to check for nullity in calling method ? } else { @@ -143,15 +145,12 @@ class SystemAppsUpdatesRepository @Inject constructor( } } - //todo: rename & rewrite ? - private suspend fun getLatestSystemAppReleaseByAndroidVersion(projectId: Int): GitlabReleaseInfo? { + private suspend fun getLatestReleaseByAndroidVersion(projectId: Int): GitlabReleaseInfo? { val gitlabReleaseList = systemAppDefinitionApi.getSystemAppReleases(projectId).body() - val latestRelease = gitlabReleaseList?.filter { - it.tagName.contains("api${getAndroidVersion()}-") - }?.sortedByDescending { it.releasedAt }?.first() - - return latestRelease + return gitlabReleaseList?.filter { + it.tagName.contains("api$androidVersionCode-") + }?.sortedByDescending { it.releasedAt }?.firstOrNull() } /* @@ -159,7 +158,7 @@ class SystemAppsUpdatesRepository @Inject constructor( through BUILD.VERSIO_CODES (may be due to targeted SDK or minimum SDK.) todo: This method shouldn't be called for each app. We need to define it only once! */ - private fun getAndroidVersion(): String { + private fun getAndroidVersionCodeChar(): String { return when (Build.VERSION.SDK_INT) { Build.VERSION_CODES.Q -> "Q" Build.VERSION_CODES.R -> "R" diff --git a/app/src/main/java/foundation/e/apps/data/gitlab/models/GitlabReleaseInfo.kt b/app/src/main/java/foundation/e/apps/data/gitlab/models/GitlabReleaseInfo.kt index 8cb4b58c4..2e93e7932 100644 --- a/app/src/main/java/foundation/e/apps/data/gitlab/models/GitlabReleaseInfo.kt +++ b/app/src/main/java/foundation/e/apps/data/gitlab/models/GitlabReleaseInfo.kt @@ -1,14 +1,13 @@ package foundation.e.apps.data.gitlab.models -import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.squareup.moshi.Json -import java.util.Date +import com.squareup.moshi.JsonClass +import java.time.Instant - -@JsonIgnoreProperties(ignoreUnknown = true) +@JsonClass(generateAdapter = true) data class GitlabReleaseInfo( @Json(name = "tag_name") val tagName: String, @Json(name = "name") val releaseName: String, - @Json(name = "created_at") val createdAt: Date, - @Json(name = "released_at") val releasedAt: Date, + @Json(name = "created_at") val createdAt: Instant, + @Json(name = "released_at") val releasedAt: Instant, ) -- GitLab From 5108c9adbcbc9a2a2111ae4970b8d7ca04cc126b Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Fri, 11 Oct 2024 11:29:25 +0200 Subject: [PATCH 07/16] refactor: SystemAppsUpdateRepository.getSystemAppInfo() --- .../e/apps/data/gitlab/SystemAppsUpdatesRepository.kt | 11 +++++------ 1 file changed, 5 insertions(+), 6 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 675b19729..94c3cf7ed 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 @@ -132,14 +132,13 @@ class SystemAppsUpdatesRepository @Inject constructor( val projectId = systemAppProject.projectId return if (systemAppProject.dependsOnAndroidVersion) { - val latestRelease = getLatestReleaseByAndroidVersion(projectId) - if (latestRelease == null) { - null //todo replace by an error code to avoid to check for nullity in calling method ? + val latestReleaseTag = getLatestReleaseByAndroidVersion(projectId)?.tagName + + if (latestReleaseTag == null) { + null } else { - val releaseTag = latestRelease.tagName - systemAppDefinitionApi.getSystemAppUpdateInfoByTag(projectId, releaseTag, releaseType) + systemAppDefinitionApi.getSystemAppUpdateInfoByTag(projectId, latestReleaseTag, releaseType) } - } else { systemAppDefinitionApi.getLatestSystemAppUpdateInfo(projectId, releaseType) } -- GitLab From 987f8a0a7a67822265db5e8b3ab7d640642362ed Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Fri, 11 Oct 2024 11:50:22 +0200 Subject: [PATCH 08/16] feature: Add InstantJsonParser class, to let moshi parse date from gitlab release API --- .../e/apps/di/network/InstantJsonAdapter.kt | 21 +++++++++++++++++++ .../e/apps/di/network/NetworkModule.kt | 1 + 2 files changed, 22 insertions(+) create mode 100644 app/src/main/java/foundation/e/apps/di/network/InstantJsonAdapter.kt diff --git a/app/src/main/java/foundation/e/apps/di/network/InstantJsonAdapter.kt b/app/src/main/java/foundation/e/apps/di/network/InstantJsonAdapter.kt new file mode 100644 index 000000000..4308873da --- /dev/null +++ b/app/src/main/java/foundation/e/apps/di/network/InstantJsonAdapter.kt @@ -0,0 +1,21 @@ +package foundation.e.apps.di.network + +import com.squareup.moshi.FromJson +import com.squareup.moshi.ToJson +import java.time.Instant +import java.time.format.DateTimeFormatter + +//todo Instant is not available in Android API 25 which is the minimum used. +// 3 option: replace Instant by another class, use a third party library to make retrocompatibility +// or update android minimum api to at least API 26 +class InstantJsonAdapter { + @ToJson + fun toJson(instant: Instant): String { + return DateTimeFormatter.ISO_INSTANT.format(instant) + } + + @FromJson + fun fromJson(instantString: String): Instant { + return Instant.parse(instantString) + } +} \ No newline at end of file diff --git a/app/src/main/java/foundation/e/apps/di/network/NetworkModule.kt b/app/src/main/java/foundation/e/apps/di/network/NetworkModule.kt index 6fbf75e99..9ec6d149b 100644 --- a/app/src/main/java/foundation/e/apps/di/network/NetworkModule.kt +++ b/app/src/main/java/foundation/e/apps/di/network/NetworkModule.kt @@ -49,6 +49,7 @@ object NetworkModule { @Provides fun getMoshi(): Moshi { return Moshi.Builder() + .add(InstantJsonAdapter()) .add(KotlinJsonAdapterFactory()) .build() } -- GitLab From 8b9a1d4547aa053f0af7178155fa85a55ef34c87 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Tue, 15 Oct 2024 15:44:59 +0200 Subject: [PATCH 09/16] refactor: refactor getAndroidVersionCodeChar() --- .../gitlab/SystemAppsUpdatesRepository.kt | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 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 94c3cf7ed..64ec36445 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 @@ -44,7 +44,13 @@ class SystemAppsUpdatesRepository @Inject constructor( ) { private val systemAppProjectList = mutableListOf() - private val androidVersionCode by lazy { getAndroidVersionCodeChar() } + private val androidVersionCode by lazy { + try { getAndroidVersionCodeChar() } + catch (exception: RuntimeException) { + Timber.w(exception.message) + "UnsupportedAndroidAPI" + } + } private fun getUpdatableSystemApps(): List { return systemAppProjectList.map { it.packageName } @@ -152,18 +158,15 @@ class SystemAppsUpdatesRepository @Inject constructor( }?.sortedByDescending { it.releasedAt }?.firstOrNull() } - /* - todo: this method cannot match upper version. UPSIDE_DOWN_CAKE or VANILLA or note available - through BUILD.VERSIO_CODES (may be due to targeted SDK or minimum SDK.) - todo: This method shouldn't be called for each app. We need to define it only once! - */ private fun getAndroidVersionCodeChar(): String { - return when (Build.VERSION.SDK_INT) { - Build.VERSION_CODES.Q -> "Q" - Build.VERSION_CODES.R -> "R" + val baseAPI = Build.VERSION_CODES.BASE + val lastUnsupportedAPI = Build.VERSION_CODES.R + + return when (val currentAPI = Build.VERSION.SDK_INT) { + in baseAPI.. lastUnsupportedAPI -> throw RuntimeException("Android $currentAPI is not supported anymore") Build.VERSION_CODES.S -> "S" Build.VERSION_CODES.TIRAMISU -> "T" - else -> "unknown" + else -> throw RuntimeException("Android $currentAPI and above is not yet supported") } } -- GitLab From a8b0271bcefe3727eb3432cdfe4295bc3ddbfcc4 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Wed, 16 Oct 2024 13:34:52 +0200 Subject: [PATCH 10/16] refactor: rewrite getSystemAppInfo & getSystemAppUpdateInfo from SystemAppsUpdatesRepository.kt The goal was to handle some potential NULL in a better way and also remove two unused import --- .../gitlab/SystemAppsUpdatesRepository.kt | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 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 64ec36445..b8f22a2fb 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 @@ -29,7 +29,6 @@ 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 retrofit2.Response import javax.inject.Inject import javax.inject.Singleton import timber.log.Timber @@ -115,18 +114,9 @@ class SystemAppsUpdatesRepository @Inject constructor( val systemAppProject = systemAppProjectList.find { it.packageName == packageName } ?: return null + val systemAppInfo = getSystemAppInfo(systemAppProject, releaseType) ?: return null - val response = getSystemAppInfo(systemAppProject, releaseType) - if (response == null) { //todo refactor to avoid checking this - Timber.e("Can't get latest release for : $packageName") - return null - } - val systemAppInfo = response?.body() - - 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 { @@ -134,20 +124,31 @@ class SystemAppsUpdatesRepository @Inject constructor( } } - private suspend fun getSystemAppInfo(systemAppProject: SystemAppProject, releaseType: String): Response? { - val projectId = systemAppProject.projectId + private suspend fun getSystemAppInfo( + systemAppProject: SystemAppProject, + releaseType: String + ): SystemAppInfo? { - return if (systemAppProject.dependsOnAndroidVersion) { - val latestReleaseTag = getLatestReleaseByAndroidVersion(projectId)?.tagName + val projectId = systemAppProject.projectId - if (latestReleaseTag == null) { - null - } else { - systemAppDefinitionApi.getSystemAppUpdateInfoByTag(projectId, latestReleaseTag, releaseType) + val response = if (systemAppProject.dependsOnAndroidVersion) { + val latestRelease = getLatestReleaseByAndroidVersion(projectId) ?: run { + Timber.e("No release found for project $projectId") + return null } + + systemAppDefinitionApi.getSystemAppUpdateInfoByTag(projectId, latestRelease.tagName, releaseType) + } else { systemAppDefinitionApi.getLatestSystemAppUpdateInfo(projectId, releaseType) } + + return if (response.isSuccessful ) { + response.body() + } else { + Timber.e("Can't get AppInfo for ${systemAppProject.packageName}, response: ${response.errorBody()?.string()}") + null + } } private suspend fun getLatestReleaseByAndroidVersion(projectId: Int): GitlabReleaseInfo? { @@ -222,5 +223,4 @@ class SystemAppsUpdatesRepository @Inject constructor( return updateList } - } -- GitLab From 93c4656f32f99d305c4930695530a686cb578e6c Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Wed, 16 Oct 2024 14:11:51 +0200 Subject: [PATCH 11/16] refactor: change parameter's order of SystemAppDefinitionApi.getSystemAppUpdateInfoByTag --- .../foundation/e/apps/data/gitlab/SystemAppDefinitionApi.kt | 2 +- .../e/apps/data/gitlab/SystemAppsUpdatesRepository.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 index 7df0235e4..8b2b6b159 100644 --- a/app/src/main/java/foundation/e/apps/data/gitlab/SystemAppDefinitionApi.kt +++ b/app/src/main/java/foundation/e/apps/data/gitlab/SystemAppDefinitionApi.kt @@ -56,8 +56,8 @@ interface SystemAppDefinitionApi { @GET(UPDATE_INFO_BY_TAG_URL_SEGMENT) suspend fun getSystemAppUpdateInfoByTag( @Path(PROJECT_ID_PLACEHOLDER) projectId: Int, - @Path(TAG_NAME_PLACEHOLDER) gitlabTagName: String, @Path(RELEASE_TYPE_PLACEHOLDER) releaseType: String, + @Path(TAG_NAME_PLACEHOLDER) gitlabTagName: String, ): Response @GET(LATEST_UPDATE_INFO_URL_SEGMENT) 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 b8f22a2fb..171c5558a 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 @@ -137,7 +137,7 @@ class SystemAppsUpdatesRepository @Inject constructor( return null } - systemAppDefinitionApi.getSystemAppUpdateInfoByTag(projectId, latestRelease.tagName, releaseType) + systemAppDefinitionApi.getSystemAppUpdateInfoByTag(projectId, releaseType, latestRelease.tagName) } else { systemAppDefinitionApi.getLatestSystemAppUpdateInfo(projectId, releaseType) -- GitLab From 99abc931949a8bf50dacbe8d16755d7afcd15913 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Wed, 16 Oct 2024 15:01:27 +0200 Subject: [PATCH 12/16] Refactor: Apply Rabbit Suggestion to InstantJsonAdapter --- .../foundation/e/apps/di/network/InstantJsonAdapter.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/foundation/e/apps/di/network/InstantJsonAdapter.kt b/app/src/main/java/foundation/e/apps/di/network/InstantJsonAdapter.kt index 4308873da..096833f25 100644 --- a/app/src/main/java/foundation/e/apps/di/network/InstantJsonAdapter.kt +++ b/app/src/main/java/foundation/e/apps/di/network/InstantJsonAdapter.kt @@ -9,9 +9,14 @@ import java.time.format.DateTimeFormatter // 3 option: replace Instant by another class, use a third party library to make retrocompatibility // or update android minimum api to at least API 26 class InstantJsonAdapter { + + companion object { + private val FORMATTER: DateTimeFormatter = DateTimeFormatter.ISO_INSTANT + } + @ToJson fun toJson(instant: Instant): String { - return DateTimeFormatter.ISO_INSTANT.format(instant) + return FORMATTER.format(instant) } @FromJson -- GitLab From 09dbb33ef353e2e3e67b96df829f0d8ba596016a Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Wed, 16 Oct 2024 15:18:29 +0200 Subject: [PATCH 13/16] chore: rename SystemAppDefinitionApi into GitlabReleaseApi --- .../{SystemAppDefinitionApi.kt => GitlabReleaseApi.kt} | 4 +--- .../e/apps/data/gitlab/SystemAppsUpdatesRepository.kt | 8 ++++---- .../foundation/e/apps/di/network/RetrofitApiModule.kt | 8 ++++---- 3 files changed, 9 insertions(+), 11 deletions(-) rename app/src/main/java/foundation/e/apps/data/gitlab/{SystemAppDefinitionApi.kt => GitlabReleaseApi.kt} (94%) diff --git a/app/src/main/java/foundation/e/apps/data/gitlab/SystemAppDefinitionApi.kt b/app/src/main/java/foundation/e/apps/data/gitlab/GitlabReleaseApi.kt similarity index 94% rename from app/src/main/java/foundation/e/apps/data/gitlab/SystemAppDefinitionApi.kt rename to app/src/main/java/foundation/e/apps/data/gitlab/GitlabReleaseApi.kt index 8b2b6b159..47461983c 100644 --- a/app/src/main/java/foundation/e/apps/data/gitlab/SystemAppDefinitionApi.kt +++ b/app/src/main/java/foundation/e/apps/data/gitlab/GitlabReleaseApi.kt @@ -26,10 +26,8 @@ import retrofit2.http.Path /* Those API method client must fit with gitlab releases API https://docs.gitlab.com/ee/api/releases/#download-a-release-asset -TODO Option to consider at the end of the implementation: -Can we rename this interface into: GitlabReleaseApi ? */ -interface SystemAppDefinitionApi { +interface GitlabReleaseApi { companion object { const val BASE_URL = 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 171c5558a..20ae7c4b7 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 @@ -37,7 +37,7 @@ import timber.log.Timber class SystemAppsUpdatesRepository @Inject constructor( @ApplicationContext private val context: Context, private val updatableSystemAppsApi: UpdatableSystemAppsApi, - private val systemAppDefinitionApi: SystemAppDefinitionApi, + private val gitlabReleaseApi: GitlabReleaseApi, private val applicationDataManager: ApplicationDataManager, private val appLoungePackageManager: AppLoungePackageManager, ) { @@ -137,10 +137,10 @@ class SystemAppsUpdatesRepository @Inject constructor( return null } - systemAppDefinitionApi.getSystemAppUpdateInfoByTag(projectId, releaseType, latestRelease.tagName) + gitlabReleaseApi.getSystemAppUpdateInfoByTag(projectId, releaseType, latestRelease.tagName) } else { - systemAppDefinitionApi.getLatestSystemAppUpdateInfo(projectId, releaseType) + gitlabReleaseApi.getLatestSystemAppUpdateInfo(projectId, releaseType) } return if (response.isSuccessful ) { @@ -152,7 +152,7 @@ class SystemAppsUpdatesRepository @Inject constructor( } private suspend fun getLatestReleaseByAndroidVersion(projectId: Int): GitlabReleaseInfo? { - val gitlabReleaseList = systemAppDefinitionApi.getSystemAppReleases(projectId).body() + val gitlabReleaseList = gitlabReleaseApi.getSystemAppReleases(projectId).body() return gitlabReleaseList?.filter { it.tagName.contains("api$androidVersionCode-") 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 56914f616..15d78d5ca 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 @@ -30,7 +30,7 @@ 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.UpdatableSystemAppsApi -import foundation.e.apps.data.gitlab.SystemAppDefinitionApi +import foundation.e.apps.data.gitlab.GitlabReleaseApi import foundation.e.apps.data.parentalcontrol.fdroid.FDroidMonitorApi import foundation.e.apps.data.parentalcontrol.googleplay.AgeGroupApi import foundation.e.apps.di.network.NetworkModule.getYamlFactory @@ -152,13 +152,13 @@ class RetrofitApiModule { fun provideSystemAppDefinitionApi( okHttpClient: OkHttpClient, moshi: Moshi, - ): SystemAppDefinitionApi { + ): GitlabReleaseApi { return Retrofit.Builder() - .baseUrl(SystemAppDefinitionApi.BASE_URL) + .baseUrl(GitlabReleaseApi.BASE_URL) .client(okHttpClient) .addConverterFactory(MoshiConverterFactory.create(moshi)) .build() - .create(SystemAppDefinitionApi::class.java) + .create(GitlabReleaseApi::class.java) } } -- GitLab From d11e6c6dc78ce8d796c94bcf23463292a04f2769 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Mon, 21 Oct 2024 15:33:57 +0200 Subject: [PATCH 14/16] chore: remove and update comments - InstantJsonParser - GitlabReleaseInfo --- .../java/foundation/e/apps/data/gitlab/GitlabReleaseApi.kt | 4 ++-- .../java/foundation/e/apps/di/network/InstantJsonAdapter.kt | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/data/gitlab/GitlabReleaseApi.kt b/app/src/main/java/foundation/e/apps/data/gitlab/GitlabReleaseApi.kt index 47461983c..0a9d709ff 100644 --- a/app/src/main/java/foundation/e/apps/data/gitlab/GitlabReleaseApi.kt +++ b/app/src/main/java/foundation/e/apps/data/gitlab/GitlabReleaseApi.kt @@ -24,8 +24,8 @@ import retrofit2.http.GET import retrofit2.http.Path /* -Those API method client must fit with gitlab releases API -https://docs.gitlab.com/ee/api/releases/#download-a-release-asset ++These API client methods must conform to the GitLab Releases API. ++See: https://docs.gitlab.com/ee/api/releases/#download-a-release-asset */ interface GitlabReleaseApi { diff --git a/app/src/main/java/foundation/e/apps/di/network/InstantJsonAdapter.kt b/app/src/main/java/foundation/e/apps/di/network/InstantJsonAdapter.kt index 096833f25..3699ebc81 100644 --- a/app/src/main/java/foundation/e/apps/di/network/InstantJsonAdapter.kt +++ b/app/src/main/java/foundation/e/apps/di/network/InstantJsonAdapter.kt @@ -5,9 +5,6 @@ import com.squareup.moshi.ToJson import java.time.Instant import java.time.format.DateTimeFormatter -//todo Instant is not available in Android API 25 which is the minimum used. -// 3 option: replace Instant by another class, use a third party library to make retrocompatibility -// or update android minimum api to at least API 26 class InstantJsonAdapter { companion object { -- GitLab From 2a0da393372ef0b59558d71911ea93e306b970f2 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Tue, 22 Oct 2024 09:46:42 +0200 Subject: [PATCH 15/16] refactor: add nullity check and apply android studio on SystemAppsUpdatesRepository --- .../apps/data/gitlab/SystemAppsUpdatesRepository.kt | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 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 20ae7c4b7..483e2991d 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 @@ -152,11 +152,19 @@ class SystemAppsUpdatesRepository @Inject constructor( } private suspend fun getLatestReleaseByAndroidVersion(projectId: Int): GitlabReleaseInfo? { - val gitlabReleaseList = gitlabReleaseApi.getSystemAppReleases(projectId).body() + val response = gitlabReleaseApi.getSystemAppReleases(projectId) + if (!response.isSuccessful) { + Timber.e("Failed to fetch releases for project $projectId: ${ + response.errorBody()?.string() + }") + return null + } + + val gitlabReleaseList = response.body() return gitlabReleaseList?.filter { it.tagName.contains("api$androidVersionCode-") - }?.sortedByDescending { it.releasedAt }?.firstOrNull() + }?.maxByOrNull { it.releasedAt } } private fun getAndroidVersionCodeChar(): String { -- GitLab From 5ea9a301fd08f50ba0396301886c0d212e8cdf0d Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Tue, 22 Oct 2024 10:12:04 +0200 Subject: [PATCH 16/16] chore: clean code style --- .../e/apps/data/gitlab/SystemAppsUpdatesRepository.kt | 3 +-- 1 file changed, 1 insertion(+), 2 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 483e2991d..e505aee46 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 @@ -79,8 +79,7 @@ class SystemAppsUpdatesRepository @Inject constructor( private fun getUpdatableSystemAppEndPoint(): UpdatableSystemAppsApi.EndPoint { val systemName = getFullSystemName() - return if (isEligibleToFetchAppListFromTest(systemName) - ) { + return if (isEligibleToFetchAppListFromTest(systemName)) { UpdatableSystemAppsApi.EndPoint.ENDPOINT_TEST } else { UpdatableSystemAppsApi.EndPoint.ENDPOINT_RELEASE -- GitLab