diff --git a/app/src/androidTest/java/mock/MockInstallablePackageManager.java b/app/src/androidTest/java/mock/MockInstallablePackageManager.java index 4b95dcf60..1fcef1e86 100644 --- a/app/src/androidTest/java/mock/MockInstallablePackageManager.java +++ b/app/src/androidTest/java/mock/MockInstallablePackageManager.java @@ -38,6 +38,7 @@ public class MockInstallablePackageManager extends MockPackageManager { p.versionCode = version; p.versionName = versionName; p.applicationInfo = new MockApplicationInfo(p); + p.lastUpdateTime = System.currentTimeMillis(); info.add(p); } } diff --git a/app/src/androidTest/java/org/fdroid/fdroid/data/InstalledAppProviderTest.java b/app/src/androidTest/java/org/fdroid/fdroid/data/InstalledAppProviderTest.java index e06f7531d..7c96e66e2 100644 --- a/app/src/androidTest/java/org/fdroid/fdroid/data/InstalledAppProviderTest.java +++ b/app/src/androidTest/java/org/fdroid/fdroid/data/InstalledAppProviderTest.java @@ -2,6 +2,8 @@ package org.fdroid.fdroid.data; import android.content.ContentValues; import android.content.pm.PackageInfo; +import android.database.Cursor; +import android.net.Uri; import mock.MockContextSwappableComponents; import mock.MockInstallablePackageManager; @@ -81,6 +83,39 @@ public class InstalledAppProviderTest extends FDroidProviderTest 0); + assertTrue(lastUpdateTime < System.currentTimeMillis()); + cursor.close(); + + insertInstalledApp(packageName, 11, "1.1"); + cursor = getMockContentResolver().query(uri, projection, null, null, null); + assertNotNull(cursor); + assertEquals("App \"" + packageName + "\" not installed", 1, cursor.getCount()); + cursor.moveToFirst(); + assertTrue(lastUpdateTime < cursor.getLong(cursor.getColumnIndex(InstalledAppProvider.DataColumns.LAST_UPDATE_TIME))); + cursor.close(); + } + public void testDelete() { insertInstalledApp("com.example.app1", 10, "1.0"); @@ -156,6 +191,9 @@ public class InstalledAppProviderTest extends FDroidProviderTest= 51) { + /** + * If any column was added or removed, just drop the table, create it again + * and let the cache be filled from scratch by {@link InstalledAppProviderService} + * For DB versions older than 43, this will create the {@link InstalledAppProvider} + * table for the first time. + */ + private void recreateInstalledAppTable(SQLiteDatabase db, int oldVersion) { + if (oldVersion >= 57) { return; } + Utils.debugLog(TAG, "(re)creating 'installed app' database table."); db.execSQL(DROP_TABLE_INSTALLED_APP); - createInstalledApp(db); + db.execSQL(CREATE_TABLE_INSTALLED_APP); } private static boolean columnExists(SQLiteDatabase db, diff --git a/app/src/main/java/org/fdroid/fdroid/data/InstalledAppProvider.java b/app/src/main/java/org/fdroid/fdroid/data/InstalledAppProvider.java index 414e528f5..9b3d01877 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/InstalledAppProvider.java +++ b/app/src/main/java/org/fdroid/fdroid/data/InstalledAppProvider.java @@ -64,10 +64,13 @@ public class InstalledAppProvider extends FDroidProvider { String VERSION_NAME = "versionName"; String APPLICATION_LABEL = "applicationLabel"; String SIGNATURE = "sig"; + String LAST_UPDATE_TIME = "lastUpdateTime"; + String HASH_TYPE = "hashType"; + String HASH = "hash"; String[] ALL = { _ID, PACKAGE_NAME, VERSION_CODE, VERSION_NAME, APPLICATION_LABEL, - SIGNATURE, + SIGNATURE, LAST_UPDATE_TIME, HASH_TYPE, HASH, }; } @@ -89,6 +92,9 @@ public class InstalledAppProvider extends FDroidProvider { return Uri.parse("content://" + getAuthority()); } + /** + * @return the {@link Uri} that points to a specific installed app + */ public static Uri getAppUri(String packageName) { return Uri.withAppendedPath(getContentUri(), packageName); } diff --git a/app/src/main/java/org/fdroid/fdroid/data/InstalledAppProviderService.java b/app/src/main/java/org/fdroid/fdroid/data/InstalledAppProviderService.java index 175a78976..acd5a8d45 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/InstalledAppProviderService.java +++ b/app/src/main/java/org/fdroid/fdroid/data/InstalledAppProviderService.java @@ -155,6 +155,12 @@ public class InstalledAppProviderService extends IntentService { InstalledAppProvider.getApplicationLabel(context, packageInfo.packageName)); contentValues.put(InstalledAppProvider.DataColumns.SIGNATURE, InstalledAppProvider.getPackageSig(packageInfo)); + contentValues.put(InstalledAppProvider.DataColumns.LAST_UPDATE_TIME, packageInfo.lastUpdateTime); + + String hashType = "sha256"; + String hash = Utils.getBinaryHash(new File(packageInfo.applicationInfo.publicSourceDir), hashType); + contentValues.put(InstalledAppProvider.DataColumns.HASH_TYPE, hashType); + contentValues.put(InstalledAppProvider.DataColumns.HASH, hash); context.getContentResolver().insert(uri, contentValues); }