commit 18f2c46cfc92856a7f5bdf1908d39bbeb34799b2 equwal <13551856+equwal@users.noreply.github.com> 2026-10-04 21:00:31 -0700 Treat any installer that opens fdroidrepos:// links as a F-Droid client
app/src/main/AndroidManifest.xml | 5 ++++ app/src/main/java/dev/equwal/inkupdate/Checker.kt | 30 ++++++++++++++++++---- app/src/main/java/dev/equwal/inkupdate/Decide.kt | 7 +++-- .../test/java/dev/equwal/inkupdate/DecideTest.kt | 10 ++++++++ 4 files changed, 45 insertions(+), 7 deletions(-)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 00283e6..845a0c1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -24,6 +24,11 @@ <package android:name="dev.equwal.inkupdate" /> <package android:name="org.fdroid.fdroid" /> <package android:name="com.android.vending" /> + <!-- Every F-Droid client opens these links. --> + <intent> + <action android:name="android.intent.action.VIEW" /> + <data android:scheme="fdroidrepos" /> + </intent> </queries> <application diff --git a/app/src/main/java/dev/equwal/inkupdate/Checker.kt b/app/src/main/java/dev/equwal/inkupdate/Checker.kt index 5956956..bec4e71 100644 --- a/app/src/main/java/dev/equwal/inkupdate/Checker.kt +++ b/app/src/main/java/dev/equwal/inkupdate/Checker.kt @@ -3,7 +3,9 @@ package dev.equwal.inkupdate import android.content.Context +import android.content.Intent import android.content.pm.PackageManager +import android.net.Uri /** * The check itself: what is installed, what the two hosts say, and what that @@ -21,7 +23,8 @@ object Checker { val watched: Watched, val versionName: String, val versionCode: Long, - val installer: String? + val installer: String?, + val byFdroid: Boolean = Decide.fromFdroidClient(installer) ) /** A row of the screen: an installed app and what the last check found. */ @@ -39,12 +42,14 @@ object Checker { } catch (e: Exception) { null } ?: continue + val installer = installerOf(pm, w.pkg) out.add( Installed( watched = w, versionName = info.versionName ?: "", versionCode = info.longVersionCode, - installer = installerOf(pm, w.pkg) + installer = installer, + byFdroid = fdroidClient(pm, installer) ) ) } @@ -94,12 +99,11 @@ object Checker { // Two cases make the GitHub request waste: F-Droid already has a newer // build, and the Play store updates the app by itself. val github = - if (fdroidWins || app.installer == Decide.PLAY_PACKAGE || - Decide.fromFdroidClient(app.installer)) GithubAnswer.None + if (fdroidWins || app.installer == Decide.PLAY_PACKAGE || app.byFdroid) GithubAnswer.None else askGithub(w) return Decide.source( - app.installer, fdroid, github, app.versionCode, app.versionName + app.installer, fdroid, github, app.versionCode, app.versionName, app.byFdroid ) } @@ -125,6 +129,22 @@ object Checker { } } + /** + * True when the installer is a F-Droid client. There are many clients, and + * each one opens fdroidrepos:// links, so the system can tell. + */ + private fun fdroidClient(pm: PackageManager, installer: String?): Boolean { + if (installer == null) return false + if (Decide.fromFdroidClient(installer)) return true + val view = Intent(Intent.ACTION_VIEW, Uri.parse("fdroidrepos://f-droid.org/repo")) + .setPackage(installer) + return try { + pm.queryIntentActivities(view, 0).isNotEmpty() + } catch (e: Exception) { + false + } + } + /** The package that installed the app, as the system knows it. */ private fun installerOf(pm: PackageManager, pkg: String): String? = try { pm.getInstallSourceInfo(pkg).installingPackageName diff --git a/app/src/main/java/dev/equwal/inkupdate/Decide.kt b/app/src/main/java/dev/equwal/inkupdate/Decide.kt index a346639..1a360de 100644 --- a/app/src/main/java/dev/equwal/inkupdate/Decide.kt +++ b/app/src/main/java/dev/equwal/inkupdate/Decide.kt @@ -93,19 +93,22 @@ object Decide { * 4. GitHub holds a newer release: take it. * * @param installer the package that installed the app, from the system. + * @param byFdroid the installer is a F-Droid client. Checker also asks the + * system whether the installer opens fdroidrepos:// links. */ fun source( installer: String?, fdroid: FdroidAnswer, github: GithubAnswer, installedCode: Long, - installedName: String + installedName: String, + byFdroid: Boolean = fromFdroidClient(installer) ): Result { if (fdroid is FdroidAnswer.Found && fdroid.versionCode > installedCode) { return Result.Update(FDROID, fdroid.versionName, fdroid.page, null) } if (installer == PLAY_PACKAGE) return Result.LeftToPlay - if (fromFdroidClient(installer)) return Result.UpToDate + if (byFdroid) return Result.UpToDate if (github is GithubAnswer.Found) { val theirs = Version.parse(github.tag) diff --git a/app/src/test/java/dev/equwal/inkupdate/DecideTest.kt b/app/src/test/java/dev/equwal/inkupdate/DecideTest.kt index 8605ff3..2e45f5d 100644 --- a/app/src/test/java/dev/equwal/inkupdate/DecideTest.kt +++ b/app/src/test/java/dev/equwal/inkupdate/DecideTest.kt @@ -58,6 +58,16 @@ class DecideTest { assertEquals(Result.UpToDate, r) } + /** A client that is not in the list, found by its fdroidrepos:// links. */ + @Test + fun otherFdroidClientInstallNeverOffersGithub() { + val r = Decide.source( + "com.looker.droidify", FdroidAnswer.NotThere, githubNewer(), 1L, "0.1.0", + byFdroid = true + ) + assertEquals(Result.UpToDate, r) + } + /** The Play store does not beat a newer build on F-Droid. */ @Test fun fdroidStillWinsOverPlay() {