diff --git a/app/src/main/java/org/fdroid/fdroid/FDroidApp.java b/app/src/main/java/org/fdroid/fdroid/FDroidApp.java index 92b0f8ce5..171655b57 100644 --- a/app/src/main/java/org/fdroid/fdroid/FDroidApp.java +++ b/app/src/main/java/org/fdroid/fdroid/FDroidApp.java @@ -342,13 +342,6 @@ public class FDroidApp extends Application implements androidx.work.Configuratio configureProxy(preferences); - // If the user changes the preference to do with filtering anti-feature apps, - // it is easier to just notify a change in the app provider, - // so that the newly updated list will correctly filter relevant apps. - preferences.registerAppsRequiringAntiFeaturesChangeListener(() -> { - // TODO check if anything else needs updating/reloading - }); - preferences.registerUnstableUpdatesChangeListener(() -> AppUpdateStatusManager.getInstance(FDroidApp.this).checkForUpdates()); diff --git a/app/src/main/java/org/fdroid/fdroid/Preferences.java b/app/src/main/java/org/fdroid/fdroid/Preferences.java index 3e900015d..a98140fa5 100644 --- a/app/src/main/java/org/fdroid/fdroid/Preferences.java +++ b/app/src/main/java/org/fdroid/fdroid/Preferences.java @@ -182,6 +182,7 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh private final List localRepoNameListeners = new ArrayList<>(); private final List localRepoHttpsListeners = new ArrayList<>(); private final List unstableUpdatesListeners = new ArrayList<>(); + private final List showIncompatibleListeners = new ArrayList<>(); private boolean isInitialized(String key) { return initialized.containsKey(key) && initialized.get(key); @@ -616,6 +617,14 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh unstableUpdatesListeners.add(listener); } + public void registerShowIncompatibleListener(ChangeListener listener) { + showIncompatibleListeners.add(listener); + } + + public void unregisterShowIncompatibleListener(ChangeListener listener) { + showIncompatibleListeners.remove(listener); + } + @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { Utils.debugLog(TAG, "Invalidating preference '" + key + "'."); @@ -642,6 +651,11 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh listener.onPreferenceChange(); } break; + case PREF_SHOW_INCOMPAT_VERSIONS: + for (ChangeListener listener : showIncompatibleListeners) { + listener.onPreferenceChange(); + } + break; } } diff --git a/app/src/main/java/org/fdroid/fdroid/views/main/LatestViewBinder.java b/app/src/main/java/org/fdroid/fdroid/views/main/LatestViewBinder.java index 1690a3190..d045363fc 100644 --- a/app/src/main/java/org/fdroid/fdroid/views/main/LatestViewBinder.java +++ b/app/src/main/java/org/fdroid/fdroid/views/main/LatestViewBinder.java @@ -57,11 +57,13 @@ class LatestViewBinder implements Observer>, ChangeListene @Override public void onCreate(@NonNull LifecycleOwner owner) { Preferences.get().registerAppsRequiringAntiFeaturesChangeListener(LatestViewBinder.this); + Preferences.get().registerShowIncompatibleListener(LatestViewBinder.this); } @Override public void onDestroy(@NonNull LifecycleOwner owner) { Preferences.get().unregisterAppsRequiringAntiFeaturesChangeListener(LatestViewBinder.this); + Preferences.get().unregisterShowIncompatibleListener(LatestViewBinder.this); } }); db = DBHelper.getDb(activity); @@ -135,11 +137,14 @@ class LatestViewBinder implements Observer>, ChangeListene Set shownAntiFeatures = Preferences.get().showAppsWithAntiFeatures(); String otherAntiFeatures = activity.getResources().getString(R.string.antiothers_key); boolean showOtherAntiFeatures = shownAntiFeatures.contains(otherAntiFeatures); + boolean hideIncompatibleVersions = !Preferences.get().showIncompatibleVersions(); Iterator iterator = items.iterator(); while (iterator.hasNext()) { AppOverviewItem item = iterator.next(); if (isFilteredByAntiFeature(item, antiFeatures, shownAntiFeatures, showOtherAntiFeatures)) { iterator.remove(); + } else if (hideIncompatibleVersions && !item.isCompatible()) { + iterator.remove(); } } } diff --git a/libs/database/src/dbTest/java/org/fdroid/database/AppOverviewItemsTest.kt b/libs/database/src/dbTest/java/org/fdroid/database/AppOverviewItemsTest.kt index a13a005d3..ad7aa0c72 100644 --- a/libs/database/src/dbTest/java/org/fdroid/database/AppOverviewItemsTest.kt +++ b/libs/database/src/dbTest/java/org/fdroid/database/AppOverviewItemsTest.kt @@ -10,8 +10,10 @@ import org.fdroid.test.TestVersionUtils.getRandomPackageVersionV2 import org.junit.Test import org.junit.runner.RunWith import kotlin.test.assertEquals +import kotlin.test.assertFalse import kotlin.test.assertNotNull import kotlin.test.assertNull +import kotlin.test.assertTrue @RunWith(AndroidJUnit4::class) internal class AppOverviewItemsTest : AppTest() { @@ -89,6 +91,50 @@ internal class AppOverviewItemsTest : AppTest() { assertEquals(3, appDao.getAppOverviewItems(42).getOrFail().size) } + @Test + fun testIncompatibleFlag() { + // insert two apps + val repoId = repoDao.insertOrReplace(getRandomRepo()) + appDao.insert(repoId, packageName1, app1, locales) + appDao.insert(repoId, packageName2, app2, locales) + + // both apps are not compatible + appDao.getAppOverviewItems().getOrFail().also { + assertEquals(2, it.size) + }.forEach { + assertFalse(it.isCompatible) + } + // both apps, in the same category, are not compatible + appDao.getAppOverviewItems("A").getOrFail().also { + assertEquals(2, it.size) + }.forEach { + assertFalse(it.isCompatible) + } + assertFalse(appDao.getAppOverviewItem(repoId, packageName1)!!.isCompatible) + assertFalse(appDao.getAppOverviewItem(repoId, packageName2)!!.isCompatible) + + // each app gets a version + versionDao.insert(repoId, packageName1, "1", getRandomPackageVersionV2(), true) + versionDao.insert(repoId, packageName2, "1", getRandomPackageVersionV2(), false) + + // updating compatibility for apps + appDao.updateCompatibility(repoId) + + // now only one is not compatible + appDao.getAppOverviewItems().getOrFail().also { + assertEquals(2, it.size) + assertFalse(it[0].isCompatible) + assertTrue(it[1].isCompatible) + } + appDao.getAppOverviewItems("A").getOrFail().also { + assertEquals(2, it.size) + assertFalse(it[0].isCompatible) + assertTrue(it[1].isCompatible) + } + assertTrue(appDao.getAppOverviewItem(repoId, packageName1)!!.isCompatible) + assertFalse(appDao.getAppOverviewItem(repoId, packageName2)!!.isCompatible) + } + @Test fun testGetByRepoWeight() { // insert one app with one version diff --git a/libs/database/src/main/java/org/fdroid/database/App.kt b/libs/database/src/main/java/org/fdroid/database/App.kt index 11e6f46ed..d75edbc2a 100644 --- a/libs/database/src/main/java/org/fdroid/database/App.kt +++ b/libs/database/src/main/java/org/fdroid/database/App.kt @@ -250,6 +250,10 @@ public data class AppOverviewItem internal constructor( entityColumn = "packageName", ) internal val localizedIcon: List? = null, + /** + * If true, this this app has at least one version that is compatible with this device. + */ + public val isCompatible: Boolean, ) : MinimalApp { public override fun getIcon(localeList: LocaleListCompat): FileV2? { return localizedIcon?.filter { icon -> diff --git a/libs/database/src/main/java/org/fdroid/database/AppDao.kt b/libs/database/src/main/java/org/fdroid/database/AppDao.kt index 7cdde6c25..2d2f5ea3a 100644 --- a/libs/database/src/main/java/org/fdroid/database/AppDao.kt +++ b/libs/database/src/main/java/org/fdroid/database/AppDao.kt @@ -326,7 +326,7 @@ internal interface AppDaoInt : AppDao { @Transaction @Query("""SELECT repoId, packageName, app.added, app.lastUpdated, localizedName, - localizedSummary, version.antiFeatures + localizedSummary, version.antiFeatures, app.isCompatible FROM ${AppMetadata.TABLE} AS app JOIN ${RepositoryPreferences.TABLE} AS pref USING (repoId) LEFT JOIN ${HighestVersion.TABLE} AS version USING (repoId, packageName) @@ -340,7 +340,7 @@ internal interface AppDaoInt : AppDao { @Transaction @Query("""SELECT repoId, packageName, app.added, app.lastUpdated, localizedName, - localizedSummary, version.antiFeatures + localizedSummary, version.antiFeatures, app.isCompatible FROM ${AppMetadata.TABLE} AS app JOIN ${RepositoryPreferences.TABLE} AS pref USING (repoId) LEFT JOIN ${HighestVersion.TABLE} AS version USING (repoId, packageName) @@ -358,7 +358,7 @@ internal interface AppDaoInt : AppDao { @Transaction @SuppressWarnings(CURSOR_MISMATCH) // no anti-features needed here @Query("""SELECT repoId, packageName, added, app.lastUpdated, localizedName, - localizedSummary + localizedSummary, app.isCompatible FROM ${AppMetadata.TABLE} AS app WHERE repoId = :repoId AND packageName = :packageName""") fun getAppOverviewItem(repoId: Long, packageName: String): AppOverviewItem? diff --git a/libs/database/src/main/java/org/fdroid/repo/RepoV2StreamReceiver.kt b/libs/database/src/main/java/org/fdroid/repo/RepoV2StreamReceiver.kt index 8f0683721..31011ce18 100644 --- a/libs/database/src/main/java/org/fdroid/repo/RepoV2StreamReceiver.kt +++ b/libs/database/src/main/java/org/fdroid/repo/RepoV2StreamReceiver.kt @@ -74,6 +74,7 @@ internal open class RepoV2StreamReceiver( ipfsCidV1 = file.ipfsCidV1, ) }, + isCompatible = true, // not concerned with compatibility at this point ) }