From 3e3fc846aa8fbf81f0902e1ff8bf756d6b4a27df Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Thu, 21 May 2026 09:13:37 -0300 Subject: [PATCH] Disable pre-approval for Chinese users as it is broken in many Chinese ROMs. In the future, we can gradually do extra checks for Chinese users and re-enable it for some of them. This is just way easier than trying to detect Chinese ROMs which is a research project of its own. --- .../download/FDroidMirrorParameterManager.kt | 16 +++------------ .../fdroid/install/SessionInstallManager.kt | 4 ++++ app/src/main/kotlin/org/fdroid/utils/Utils.kt | 17 ++++++++++++++++ .../install/SessionInstallManagerTest.kt | 20 +++++++++++++++++++ 4 files changed, 44 insertions(+), 13 deletions(-) diff --git a/app/src/main/kotlin/org/fdroid/download/FDroidMirrorParameterManager.kt b/app/src/main/kotlin/org/fdroid/download/FDroidMirrorParameterManager.kt index 5fd8dfcf8..f361991f0 100644 --- a/app/src/main/kotlin/org/fdroid/download/FDroidMirrorParameterManager.kt +++ b/app/src/main/kotlin/org/fdroid/download/FDroidMirrorParameterManager.kt @@ -1,15 +1,13 @@ package org.fdroid.download import android.content.Context -import android.telephony.TelephonyManager -import androidx.core.os.LocaleListCompat import dagger.hilt.android.qualifiers.ApplicationContext -import java.util.Locale import javax.inject.Inject import javax.inject.Singleton import kotlin.concurrent.atomics.ExperimentalAtomicApi import org.fdroid.settings.SettingsConstants import org.fdroid.settings.SettingsManager +import org.fdroid.utils.getCurrentLocation @OptIn(ExperimentalAtomicApi::class) @Singleton @@ -24,7 +22,7 @@ constructor( override fun cacheMirrorIpAddresses( mirrorUrl: String, ipv4Addresses: List, - ipv6Addresses: List + ipv6Addresses: List, ) { dnsWithCache.populateCacheWithStrings(mirrorUrl, ipv4Addresses, ipv6Addresses) } @@ -42,13 +40,5 @@ constructor( return settingsManager.mirrorChooser == SettingsConstants.MirrorChooserValues.PreferForeign } - override fun getCurrentLocation(): String { - val tm = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager - return tm.simCountryIso - ?: tm.networkCountryIso - ?: run { - val localeList = LocaleListCompat.getDefault() - localeList.get(0)?.country ?: Locale.getDefault().country - } - } + override fun getCurrentLocation(): String = getCurrentLocation(context) } diff --git a/app/src/main/kotlin/org/fdroid/install/SessionInstallManager.kt b/app/src/main/kotlin/org/fdroid/install/SessionInstallManager.kt index 9b252af1a..88e7cda95 100644 --- a/app/src/main/kotlin/org/fdroid/install/SessionInstallManager.kt +++ b/app/src/main/kotlin/org/fdroid/install/SessionInstallManager.kt @@ -38,6 +38,7 @@ import org.fdroid.database.AppMetadata import org.fdroid.index.v2.PackageVersion import org.fdroid.ui.utils.isAppInForeground import org.fdroid.utils.IoDispatcher +import org.fdroid.utils.isChina @Singleton class SessionInstallManager @@ -105,6 +106,9 @@ constructor( // should not be needed, so we say not supported log.info { "Can do auto-update pre-approval for ${app.packageName} not needed." } PreApprovalResult.NotSupported + } else if (isChina(context)) { + log.info { "Device is in China, pre-approval is broken." } + PreApprovalResult.NotSupported } else if (SDK_INT >= 34) { log.info { "Requesting pre-approval for ${app.packageName}..." } try { diff --git a/app/src/main/kotlin/org/fdroid/utils/Utils.kt b/app/src/main/kotlin/org/fdroid/utils/Utils.kt index 307e7a085..14283a06b 100644 --- a/app/src/main/kotlin/org/fdroid/utils/Utils.kt +++ b/app/src/main/kotlin/org/fdroid/utils/Utils.kt @@ -1,6 +1,8 @@ package org.fdroid.utils import android.content.Context +import android.telephony.TelephonyManager +import androidx.core.os.LocaleListCompat import java.security.MessageDigest import java.security.NoSuchAlgorithmException import java.text.SimpleDateFormat @@ -30,6 +32,21 @@ fun getLogName(context: Context): String { return "${context.packageName}-$time" } +fun getCurrentLocation(context: Context): String { + val tm = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager + return tm.simCountryIso + ?: tm.networkCountryIso + ?: run { + val localeList = LocaleListCompat.getDefault() + localeList.get(0)?.country ?: Locale.getDefault().country + } +} + +fun isChina(context: Context): Boolean { + val country = getCurrentLocation(context) + return country.equals("cn", ignoreCase = true) +} + val isFull: Boolean get() = FLAVOR.startsWith("full") val isBasic: Boolean diff --git a/app/src/test/java/org/fdroid/install/SessionInstallManagerTest.kt b/app/src/test/java/org/fdroid/install/SessionInstallManagerTest.kt index 19355e207..ac8386a18 100644 --- a/app/src/test/java/org/fdroid/install/SessionInstallManagerTest.kt +++ b/app/src/test/java/org/fdroid/install/SessionInstallManagerTest.kt @@ -10,6 +10,7 @@ import android.content.pm.PackageInstaller import android.content.pm.PackageInstaller.Session import android.content.pm.PackageManager import android.os.Build.VERSION.SDK_INT +import android.telephony.TelephonyManager import androidx.core.content.ContextCompat.registerReceiver import io.mockk.Runs import io.mockk.every @@ -62,6 +63,7 @@ internal class SessionInstallManagerTest { private val receiver: InstallBroadcastReceiver = mockk() private val pendingIntent: PendingIntent = mockk() private val session: Session = mockk() + private val telephonyManager: TelephonyManager = mockk(relaxed = true) private val sessionId = 123 private val packageName = "com.example.app" @@ -110,6 +112,7 @@ internal class SessionInstallManagerTest { every { anyConstructed().addFlags(any()) } returns mockk() every { context.packageManager } returns packageManager + every { context.getSystemService(any()) } returns telephonyManager every { packageManager.packageInstaller } returns packageInstaller every { packageInstaller.mySessions } returns emptyList() every { context.unregisterReceiver(any()) } just runs @@ -604,4 +607,21 @@ internal class SessionInstallManagerTest { listenerSlot.captured.invoke(receiver, packageInstallerResult, Intent("confirm"), msg) } } + + @Test + fun `requestPreapproval not supported in China`(): Unit = runBlocking { + every { telephonyManager.simCountryIso } returns "CN" + every { telephonyManager.networkCountryIso } returns null + every { context.isAppInForeground() } returns true + + val notSupportedResult = + sessionInstallManager.requestPreapproval( + app = appMetadata, + iconGetter = { null }, + isUpdate = false, + version = appVersion, + canRequestUserConfirmationNow = true, + ) + assertIs(notSupportedResult) + } }