diff --git a/app/src/main/java/org/fdroid/fdroid/IndexV1Updater.java b/app/src/main/java/org/fdroid/fdroid/IndexV1Updater.java index b199ebbb4..046c7f38c 100644 --- a/app/src/main/java/org/fdroid/fdroid/IndexV1Updater.java +++ b/app/src/main/java/org/fdroid/fdroid/IndexV1Updater.java @@ -226,6 +226,12 @@ public class IndexV1Updater extends RepoUpdater { if (apks.size() > 0) { app.preferredSigner = apks.get(0).sig; + app.isApk = true; + for (Apk apk : apks) { + if (!apk.isApk()) { + app.isApk = false; + } + } } if (appCount % 50 == 0) { diff --git a/app/src/main/java/org/fdroid/fdroid/data/App.java b/app/src/main/java/org/fdroid/fdroid/data/App.java index 7f91f6113..e621fd23b 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/App.java +++ b/app/src/main/java/org/fdroid/fdroid/data/App.java @@ -104,6 +104,8 @@ public class App extends ValueObject implements Comparable, Parcelable { @JsonIgnore @NonNull public String preferredSigner; + @JsonIgnore + public boolean isApk; @JacksonInject("repoId") public long repoId; @@ -347,6 +349,9 @@ public class App extends ValueObject implements Comparable, Parcelable { case Cols.WEAR_SCREENSHOTS: wearScreenshots = Utils.parseCommaSeparatedString(cursor.getString(i)); break; + case Cols.IS_APK: + isApk = cursor.getInt(i) == 1; + break; case Cols.InstalledApp.VERSION_CODE: installedVersionCode = cursor.getInt(i); break; @@ -854,12 +859,19 @@ public class App extends ValueObject implements Comparable, Parcelable { values.put(Cols.TV_SCREENSHOTS, Utils.serializeCommaSeparatedString(tvScreenshots)); values.put(Cols.WEAR_SCREENSHOTS, Utils.serializeCommaSeparatedString(wearScreenshots)); values.put(Cols.IS_COMPATIBLE, compatible ? 1 : 0); + values.put(Cols.IS_APK, isApk ? 1 : 0); return values; } public boolean isInstalled(Context context) { - return installedVersionCode > 0 || isMediaInstalled(context); + // First check isApk() before isMediaInstalled() because the latter is quite expensive, + // hitting the database for each apk version, then the disk to check for installed media. + return installedVersionCode > 0 || (!isApk() && isMediaInstalled(context)); + } + + private boolean isApk() { + return isApk; } public boolean isMediaInstalled(Context context) { @@ -1064,6 +1076,7 @@ public class App extends ValueObject implements Comparable, Parcelable { dest.writeStringArray(this.tenInchScreenshots); dest.writeStringArray(this.tvScreenshots); dest.writeStringArray(this.wearScreenshots); + dest.writeByte(this.isApk ? (byte) 1 : (byte) 0); dest.writeString(this.installedVersionName); dest.writeInt(this.installedVersionCode); dest.writeParcelable(this.installedApk, flags); @@ -1114,6 +1127,7 @@ public class App extends ValueObject implements Comparable, Parcelable { this.tenInchScreenshots = in.createStringArray(); this.tvScreenshots = in.createStringArray(); this.wearScreenshots = in.createStringArray(); + this.isApk = in.readByte() != 0; this.installedVersionName = in.readString(); this.installedVersionCode = in.readInt(); this.installedApk = in.readParcelable(Apk.class.getClassLoader()); diff --git a/app/src/main/java/org/fdroid/fdroid/data/DBHelper.java b/app/src/main/java/org/fdroid/fdroid/data/DBHelper.java index 2e604392e..7dddc07b6 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/DBHelper.java +++ b/app/src/main/java/org/fdroid/fdroid/data/DBHelper.java @@ -151,6 +151,7 @@ class DBHelper extends SQLiteOpenHelper { + AppMetadataTable.Cols.TEN_INCH_SCREENSHOTS + " string," + AppMetadataTable.Cols.TV_SCREENSHOTS + " string," + AppMetadataTable.Cols.WEAR_SCREENSHOTS + " string," + + AppMetadataTable.Cols.IS_APK + " boolean," + "primary key(" + AppMetadataTable.Cols.PACKAGE_ID + ", " + AppMetadataTable.Cols.REPO_ID + "));"; private static final String CREATE_TABLE_APP_PREFS = "CREATE TABLE " + AppPrefsTable.NAME @@ -193,7 +194,7 @@ class DBHelper extends SQLiteOpenHelper { + InstalledAppTable.Cols.HASH + " TEXT NOT NULL" + " );"; - protected static final int DB_VERSION = 73; + protected static final int DB_VERSION = 74; private final Context context; @@ -281,6 +282,30 @@ class DBHelper extends SQLiteOpenHelper { addIntegerPrimaryKeyToInstalledApps(db, oldVersion); addPreferredSignerToApp(db, oldVersion); updatePreferredSignerIfEmpty(db, oldVersion); + addIsAppToApp(db, oldVersion); + } + + private void addIsAppToApp(SQLiteDatabase db, int oldVersion) { + if (oldVersion >= 74) { + return; + } + + if (!columnExists(db, AppMetadataTable.NAME, AppMetadataTable.Cols.IS_APK)) { + Log.i(TAG, "Figuring out whether each \"app\" is actually an app, or it represents other media."); + db.execSQL("alter table " + AppMetadataTable.NAME + " add column " + AppMetadataTable.Cols.IS_APK + " boolean;"); + + // Find all apks for which their filename DOESN'T end in ".apk", and if there is more than one, the + // corresponding app is updated to be marked as media. + String apkName = ApkTable.Cols.NAME; + String query = "UPDATE " + AppMetadataTable.NAME + " SET " + AppMetadataTable.Cols.IS_APK + " = (" + + " SELECT COUNT(*) FROM " + ApkTable.NAME + " AS apk" + + " WHERE " + + " " + ApkTable.Cols.APP_ID + " = " + AppMetadataTable.NAME + "." + AppMetadataTable.Cols.ROW_ID + + " AND SUBSTR(" + apkName + ", LENGTH(" + apkName + ") - 3) != '.apk'" + + ") = 0;"; + Log.i(TAG, query); + db.execSQL(query); + } } private void updatePreferredSignerIfEmpty(SQLiteDatabase db, int oldVersion) { diff --git a/app/src/main/java/org/fdroid/fdroid/data/Schema.java b/app/src/main/java/org/fdroid/fdroid/data/Schema.java index da3e80565..fcfdfd6a3 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/Schema.java +++ b/app/src/main/java/org/fdroid/fdroid/data/Schema.java @@ -156,6 +156,7 @@ public interface Schema { String TEN_INCH_SCREENSHOTS = "tenInchScreenshots"; String TV_SCREENSHOTS = "tvScreenshots"; String WEAR_SCREENSHOTS = "wearScreenshots"; + String IS_APK = "isApk"; interface SuggestedApk { String VERSION_NAME = "suggestedApkVersion"; @@ -195,7 +196,7 @@ public interface Schema { ANTI_FEATURES, REQUIREMENTS, ICON_URL, ICON_URL_LARGE, FEATURE_GRAPHIC, PROMO_GRAPHIC, TV_BANNER, PHONE_SCREENSHOTS, SEVEN_INCH_SCREENSHOTS, TEN_INCH_SCREENSHOTS, TV_SCREENSHOTS, WEAR_SCREENSHOTS, - PREFERRED_SIGNER, SUGGESTED_VERSION_CODE, + PREFERRED_SIGNER, SUGGESTED_VERSION_CODE, IS_APK, }; /** @@ -211,7 +212,7 @@ public interface Schema { ANTI_FEATURES, REQUIREMENTS, ICON_URL, ICON_URL_LARGE, FEATURE_GRAPHIC, PROMO_GRAPHIC, TV_BANNER, PHONE_SCREENSHOTS, SEVEN_INCH_SCREENSHOTS, TEN_INCH_SCREENSHOTS, TV_SCREENSHOTS, WEAR_SCREENSHOTS, - PREFERRED_SIGNER, SUGGESTED_VERSION_CODE, SuggestedApk.VERSION_NAME, + PREFERRED_SIGNER, SUGGESTED_VERSION_CODE, IS_APK, SuggestedApk.VERSION_NAME, InstalledApp.VERSION_CODE, InstalledApp.VERSION_NAME, InstalledApp.SIGNATURE, Package.PACKAGE_NAME, }; diff --git a/app/src/test/java/org/fdroid/fdroid/updater/IndexV1UpdaterTest.java b/app/src/test/java/org/fdroid/fdroid/updater/IndexV1UpdaterTest.java index 41df377df..c070fea20 100644 --- a/app/src/test/java/org/fdroid/fdroid/updater/IndexV1UpdaterTest.java +++ b/app/src/test/java/org/fdroid/fdroid/updater/IndexV1UpdaterTest.java @@ -304,6 +304,7 @@ public class IndexV1UpdaterTest extends FDroidProviderTest { "installedSig", "installedVersionCode", "installedVersionName", + "isApk", "preferredSigner", "prefs", "TAG", @@ -335,6 +336,7 @@ public class IndexV1UpdaterTest extends FDroidProviderTest { "hash", "hashType", "incompatibleReasons", + "isApk", "maxSdkVersion", "minSdkVersion", "nativecode",