From 468b6717eee2b17bc2f88d52b321460f46dd2ce0 Mon Sep 17 00:00:00 2001 From: Peter Serwylo Date: Tue, 1 Apr 2014 21:19:27 +1100 Subject: [PATCH] After downloading index, remove apks no longer in the index. It adds an extra 600ms on my Nexus 4 with ~2000 apks from the F-Droid index. But I think it is the only way, as we really need to iterate over every single installed apk, to see if it is still wanted. The up side is that we can query for a large amount of them, rather than quering individually for each apk. NOTE: I haven't added a new status message yet, because we are about to do a stable release. After the stable release, I'll add a new status message to cover for this > half a second (on my relatively fast device). This will probably be part of an overhaul of the update process in general, including a proper progress dialog. --- src/org/fdroid/fdroid/UpdateService.java | 51 +++++++++++++++++---- src/org/fdroid/fdroid/data/ApkProvider.java | 31 ++++++++----- 2 files changed, 61 insertions(+), 21 deletions(-) diff --git a/src/org/fdroid/fdroid/UpdateService.java b/src/org/fdroid/fdroid/UpdateService.java index c7b46187d..405793f48 100644 --- a/src/org/fdroid/fdroid/UpdateService.java +++ b/src/org/fdroid/fdroid/UpdateService.java @@ -313,11 +313,14 @@ public class UpdateService extends IntentService implements ProgressListener { calcIconUrls(this, apksToUpdate, appsToUpdate, repos); calcCurrentApk(apksToUpdate, appsToUpdate); + // Need to do this BEFORE updating the apks, otherwise when it continually + // calls "get apks for repo X" then it will be getting the newly created apks + removeApksNoLongerInRepo(apksToUpdate, updatedRepos); + int totalInsertsUpdates = listOfAppsToUpdate.size() + apksToUpdate.size(); updateOrInsertApps(listOfAppsToUpdate, totalInsertsUpdates, 0); updateOrInsertApks(apksToUpdate, totalInsertsUpdates, listOfAppsToUpdate.size()); removeApksFromRepos(disabledRepos); - removeApksNoLongerInRepo(listOfAppsToUpdate, updatedRepos); removeAppsWithoutApks(); notifyContentProviders(); @@ -618,7 +621,7 @@ public class UpdateService extends IntentService implements ProgressListener { } /** - * Return list of apps from "fromApks" which are already in the database. + * Return list of apps from the "apks" argument which are already in the database. */ private List getKnownApks(List apks) { List knownApks = new ArrayList(); @@ -701,26 +704,54 @@ public class UpdateService extends IntentService implements ProgressListener { * belong to the repo which are not in the current list of apks that were * retrieved. */ - private void removeApksNoLongerInRepo(List appsToUpdate, - List updatedRepos) { + private void removeApksNoLongerInRepo(List apksToUpdate, List updatedRepos) { + + long startTime = System.currentTimeMillis(); + List toRemove = new ArrayList(); + + String[] fields = { + ApkProvider.DataColumns.APK_ID, + ApkProvider.DataColumns.VERSION_CODE, + ApkProvider.DataColumns.VERSION, + }; + for (Repo repo : updatedRepos) { - Log.d("FDroid", "Removing apks no longer in repo " + repo.address); - // TODO: Implement + List existingApks = ApkProvider.Helper.findByRepo(this, repo, fields); + for (Apk existingApk : existingApks) { + if (!isApkToBeUpdated(existingApk, apksToUpdate)) { + toRemove.add(existingApk); + } + } } + long duration = System.currentTimeMillis() - startTime; + Log.d("FDroid", "Found " + toRemove.size() + " apks no longer in the updated repos (took " + duration + "ms)"); + + if (toRemove.size() > 0) { + ApkProvider.Helper.deleteApks(this, toRemove); + } + } + + private static boolean isApkToBeUpdated(Apk existingApk, List apksToUpdate) { + for (Apk apkToUpdate : apksToUpdate) { + if (apkToUpdate.vercode == existingApk.vercode && apkToUpdate.id.equals(existingApk.id)) { + return true; + } + } + return false; } private void removeApksFromRepos(List repos) { for (Repo repo : repos) { - Log.d("FDroid", "Removing apks from repo " + repo.address); Uri uri = ApkProvider.getRepoUri(repo.getId()); - getContentResolver().delete(uri, null, null); + int numDeleted = getContentResolver().delete(uri, null, null); + Log.d("FDroid", "Removing " + numDeleted + " apks from repo " + repo.address); } } private void removeAppsWithoutApks() { - Log.d("FDroid", "Removing aps that don't have any apks"); - getContentResolver().delete(AppProvider.getNoApksUri(), null, null); + int numDeleted = getContentResolver().delete(AppProvider.getNoApksUri(), null, null); + Log.d("FDroid", "Removing " + numDeleted + " apks that don't have any apks"); } diff --git a/src/org/fdroid/fdroid/data/ApkProvider.java b/src/org/fdroid/fdroid/data/ApkProvider.java index 9ecff515a..942af616b 100644 --- a/src/org/fdroid/fdroid/data/ApkProvider.java +++ b/src/org/fdroid/fdroid/data/ApkProvider.java @@ -8,6 +8,7 @@ import android.database.Cursor; import android.net.Uri; import android.provider.BaseColumns; import android.util.Log; +import org.fdroid.fdroid.UpdateService; import java.util.*; @@ -59,6 +60,12 @@ public class ApkProvider extends FDroidProvider { resolver.delete(uri, null, null); } + public static void deleteApks(Context context, List apks) { + ContentResolver resolver = context.getContentResolver(); + Uri uri = getContentUri(apks); + resolver.delete(uri, null, null); + } + public static Apk find(Context context, String id, int versionCode) { return find(context, id, versionCode, DataColumns.ALL); } @@ -102,6 +109,13 @@ public class ApkProvider extends FDroidProvider { Cursor cursor = resolver.query(uri, fields, null, null, null); return cursorToList(cursor); } + + public static List findByRepo(Context context, Repo repo, String[] fields) { + ContentResolver resolver = context.getContentResolver(); + Uri uri = getRepoUri(repo.getId()); + Cursor cursor = resolver.query(uri, fields, null, null, null); + return cursorToList(cursor); + } } public interface DataColumns extends BaseColumns { @@ -392,20 +406,15 @@ public class ApkProvider extends FDroidProvider { query = query.add(queryApp(uri.getLastPathSegment())); break; - case CODE_LIST: - throw new UnsupportedOperationException( - "Can't delete all apks. " + - "Can only delete those belonging to an app, or a repo."); - case CODE_APKS: - throw new UnsupportedOperationException( - "Can't delete arbitrary apks. " + - "Can only delete those belonging to an app, or a repo."); + query = query.add(queryApks(uri.getLastPathSegment())); + break; + + case CODE_LIST: + throw new UnsupportedOperationException("Can't delete all apks."); case CODE_SINGLE: - throw new UnsupportedOperationException( - "Can't delete individual apks. " + - "Can only delete those belonging to an app, or a repo."); + throw new UnsupportedOperationException("Can't delete individual apks."); default: Log.e("FDroid", "Invalid URI for apk content provider: " + uri);