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.
This commit is contained in:
Peter Serwylo 2014-04-01 21:19:27 +11:00
parent 05d8e409c4
commit 468b6717ee
2 changed files with 61 additions and 21 deletions

View File

@ -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<Apk> getKnownApks(List<Apk> apks) {
List<Apk> knownApks = new ArrayList<Apk>();
@ -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<App> appsToUpdate,
List<Repo> updatedRepos) {
private void removeApksNoLongerInRepo(List<Apk> apksToUpdate, List<Repo> updatedRepos) {
long startTime = System.currentTimeMillis();
List<Apk> toRemove = new ArrayList<Apk>();
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<Apk> 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<Apk> apksToUpdate) {
for (Apk apkToUpdate : apksToUpdate) {
if (apkToUpdate.vercode == existingApk.vercode && apkToUpdate.id.equals(existingApk.id)) {
return true;
}
}
return false;
}
private void removeApksFromRepos(List<Repo> 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");
}

View File

@ -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<Apk> 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<Apk> 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);