diff --git a/next/src/main/AndroidManifest.xml b/next/src/main/AndroidManifest.xml index cfd6bec9f..13803d9ab 100644 --- a/next/src/main/AndroidManifest.xml +++ b/next/src/main/AndroidManifest.xml @@ -16,6 +16,7 @@ tools:ignore="RequestInstallPackagesPolicy" /> + InstallState.Error(preApprovalResult.errorMsg) is PreApprovalResult.UserAborted -> InstallState.UserAborted - else -> { + is PreApprovalResult.Success, PreApprovalResult.NotSupported -> { apps.checkAndUpdateApp(appMetadata.packageName) { InstallState.PreApproved( name = it.name, diff --git a/next/src/main/kotlin/org/fdroid/install/SessionInstallManager.kt b/next/src/main/kotlin/org/fdroid/install/SessionInstallManager.kt index e7c2340e6..6ce22d0b7 100644 --- a/next/src/main/kotlin/org/fdroid/install/SessionInstallManager.kt +++ b/next/src/main/kotlin/org/fdroid/install/SessionInstallManager.kt @@ -30,6 +30,7 @@ import kotlinx.coroutines.suspendCancellableCoroutine import mu.KotlinLogging import org.fdroid.LocaleChooser.getBestLocale import org.fdroid.database.AppMetadata +import org.fdroid.database.AppVersion import org.fdroid.utils.IoDispatcher import java.io.File import javax.inject.Inject @@ -60,11 +61,12 @@ class SessionInstallManager @Inject constructor( if (SDK_INT == 32 && targetSdk >= 29) return true if (SDK_INT == 33 && targetSdk >= 30) return true if (SDK_INT == 34 && targetSdk >= 31) return true + if (SDK_INT == 35 && targetSdk >= 33) return true // This needs to be adjusted as new Android versions are released // https://developer.android.com/reference/android/content/pm/PackageInstaller.SessionParams#setRequireUserAction(int) // https://cs.android.com/android/platform/superproject/+/android-16.0.0_r2:frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java;l=329;drc=73caa0299d9196ddeefe4f659f557fb880f6536d - // current code requires targetSdk 33 on SDK 35+ - return SDK_INT >= 35 && targetSdk >= 33 + // current code requires targetSdk 34 on SDK 36+ + return SDK_INT >= 36 && targetSdk >= 34 } } @@ -86,8 +88,16 @@ class SessionInstallManager @Inject constructor( /** * Requests installation pre-approval (if available on this device). */ - suspend fun requestPreapproval(app: AppMetadata, icon: Bitmap?): PreApprovalResult { - return if (SDK_INT >= 34) { + suspend fun requestPreapproval( + app: AppMetadata, + icon: Bitmap?, + isUpdate: Boolean, + version: AppVersion + ): PreApprovalResult { + return if (isUpdate && canDoAutoUpdate(version)) { + // should not be needed, so we say not supported + PreApprovalResult.NotSupported + } else if (SDK_INT >= 34) { try { preapproval(app, icon) } catch (e: Exception) { @@ -337,6 +347,31 @@ class SessionInstallManager @Inject constructor( return params } + private fun canDoAutoUpdate(version: AppVersion): Boolean { + if (SDK_INT < 31) return false + val targetSdkVersion = version.manifest.targetSdkVersion ?: return false + // docs: https://developer.android.com/reference/android/content/pm/PackageInstaller.SessionParams#setRequireUserAction(int) + return if (isAutoUpdateSupported(targetSdkVersion)) { + val ourPackageName = context.packageName + if (ourPackageName == version.packageName) return true + val sourceInfo = try { + context.packageManager.getInstallSourceInfo(version.packageName) + } catch (e: Exception) { + log.error(e) { "Could not get package info: " } + return false + } + if (SDK_INT >= 34 && sourceInfo.updateOwnerPackageName == ourPackageName) { + true + } else if (sourceInfo.installingPackageName == ourPackageName) { + true + } else { + false + } + } else { + false + } + } + private fun getInstallIntentSender( sessionId: Int, packageName: String,