diff --git a/F-Droid/src/org/fdroid/fdroid/RepoPersister.java b/F-Droid/src/org/fdroid/fdroid/RepoPersister.java new file mode 100644 index 000000000..3f82422be --- /dev/null +++ b/F-Droid/src/org/fdroid/fdroid/RepoPersister.java @@ -0,0 +1,329 @@ +package org.fdroid.fdroid; + +import android.content.ContentProviderOperation; +import android.content.ContentValues; +import android.content.Context; +import android.content.OperationApplicationException; +import android.database.Cursor; +import android.net.Uri; +import android.os.RemoteException; +import android.support.annotation.NonNull; +import android.util.Log; + +import org.fdroid.fdroid.data.Apk; +import org.fdroid.fdroid.data.ApkProvider; +import org.fdroid.fdroid.data.App; +import org.fdroid.fdroid.data.AppProvider; +import org.fdroid.fdroid.data.Repo; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Saves app and apk information to the database after a {@link RepoUpdater} has processed the + * relevant index file. + */ +public class RepoPersister { + + private static final String TAG = "RepoPersister"; + + /** + * When an app already exists in the db, and we are updating it on the off chance that some + * values changed in the index, some fields should not be updated. Rather, they should be + * ignored, because they were explicitly set by the user, and hence can't be automatically + * overridden by the index. + * + * NOTE: In the future, these attributes will be moved to a join table, so that the app table + * is essentially completely transient, and can be nuked at any time. + */ + private static final String[] APP_FIELDS_TO_IGNORE = { + AppProvider.DataColumns.IGNORE_ALLUPDATES, + AppProvider.DataColumns.IGNORE_THISUPDATE, + }; + + @NonNull + private final Context context; + + private Map appsToUpdate = new HashMap<>(); + private List apksToUpdate = new ArrayList<>(); + private List repos = new ArrayList<>(); + + public RepoPersister(@NonNull Context context) { + this.context = context; + } + + public RepoPersister queueUpdater(RepoUpdater updater) { + queueApps(updater.getApps()); + queueApks(updater.getApks()); + repos.add(updater.repo); + return this; + } + + private void queueApps(List apps) { + for (final App app : apps) { + appsToUpdate.put(app.id, app); + } + } + + private void queueApks(List apks) { + apksToUpdate.addAll(apks); + } + + public void save(List disabledRepos) { + + List listOfAppsToUpdate = new ArrayList<>(); + listOfAppsToUpdate.addAll(appsToUpdate.values()); + + calcApkCompatibilityFlags(apksToUpdate); + + // Need to do this BEFORE updating the apks, otherwise when it continually + // calls "get existing apks for repo X" then it will be getting the newly + // created apks, rather than those from the fresh, juicy index we just processed. + removeApksNoLongerInRepo(apksToUpdate, repos); + + int totalInsertsUpdates = listOfAppsToUpdate.size() + apksToUpdate.size(); + updateOrInsertApps(listOfAppsToUpdate, totalInsertsUpdates, 0); + updateOrInsertApks(apksToUpdate, totalInsertsUpdates, listOfAppsToUpdate.size()); + removeApksFromRepos(disabledRepos); + removeAppsWithoutApks(); + + // This will sort out the icon urls, compatibility flags. and suggested version + // for each app. It used to happen here in Java code, but was moved to SQL when + // it became apparant we don't always have enough info (depending on which repos + // were updated). + AppProvider.Helper.calcDetailsFromIndex(context); + + } + + /** + * This cannot be offloaded to the database (as we did with the query which + * updates apps, depending on whether their apks are compatible or not). + * The reason is that we need to interact with the CompatibilityChecker + * in order to see if, and why an apk is not compatible. + */ + private void calcApkCompatibilityFlags(List apks) { + final CompatibilityChecker checker = new CompatibilityChecker(context); + for (final Apk apk : apks) { + final List reasons = checker.getIncompatibleReasons(apk); + if (reasons.size() > 0) { + apk.compatible = false; + apk.incompatibleReasons = Utils.CommaSeparatedList.make(reasons); + } else { + apk.compatible = true; + apk.incompatibleReasons = null; + } + } + } + + /** + * If a repo was updated (i.e. it is in use, and the index has changed + * since last time we did an update), then we want to remove any apks that + * belong to the repo which are not in the current list of apks that were + * retrieved. + */ + private void removeApksNoLongerInRepo(List apksToUpdate, List updatedRepos) { + + long startTime = System.currentTimeMillis(); + List toRemove = new ArrayList<>(); + + final String[] fields = { + ApkProvider.DataColumns.APK_ID, + ApkProvider.DataColumns.VERSION_CODE, + ApkProvider.DataColumns.VERSION, + }; + + for (final Repo repo : updatedRepos) { + final List existingApks = ApkProvider.Helper.findByRepo(context, repo, fields); + for (final Apk existingApk : existingApks) { + if (!isApkToBeUpdated(existingApk, apksToUpdate)) { + toRemove.add(existingApk); + } + } + } + + long duration = System.currentTimeMillis() - startTime; + Utils.debugLog(TAG, "Found " + toRemove.size() + " apks no longer in the updated repos (took " + duration + "ms)"); + + if (toRemove.size() > 0) { + ApkProvider.Helper.deleteApks(context, toRemove); + } + } + + private void updateOrInsertApps(List appsToUpdate, int totalUpdateCount, int currentCount) { + + List operations = new ArrayList<>(); + List knownAppIds = getKnownAppIds(appsToUpdate); + for (final App app : appsToUpdate) { + if (knownAppIds.contains(app.id)) { + operations.add(updateExistingApp(app)); + } else { + operations.add(insertNewApp(app)); + } + } + + Utils.debugLog(TAG, "Updating/inserting " + operations.size() + " apps."); + try { + executeBatchWithStatus(AppProvider.getAuthority(), operations, currentCount, totalUpdateCount); + } catch (RemoteException | OperationApplicationException e) { + Log.e(TAG, "Could not update or insert apps", e); + } + } + + private void executeBatchWithStatus(String providerAuthority, + List operations, + int currentCount, + int totalUpdateCount) + throws RemoteException, OperationApplicationException { + int i = 0; + while (i < operations.size()) { + int count = Math.min(operations.size() - i, 100); + ArrayList o = new ArrayList<>(operations.subList(i, i + count)); + UpdateService.sendStatus(context, UpdateService.STATUS_INFO, context.getString( + R.string.status_inserting, + (int) ((double) (currentCount + i) / totalUpdateCount * 100))); + context.getContentResolver().applyBatch(providerAuthority, o); + i += 100; + } + } + + /** + * Return list of apps from the "apks" argument which are already in the database. + */ + private List getKnownApks(List apks) { + final String[] fields = { + ApkProvider.DataColumns.APK_ID, + ApkProvider.DataColumns.VERSION, + ApkProvider.DataColumns.VERSION_CODE, + }; + return ApkProvider.Helper.knownApks(context, apks, fields); + } + + private void updateOrInsertApks(List apksToUpdate, int totalApksAppsCount, int currentCount) { + + List operations = new ArrayList<>(); + + List knownApks = getKnownApks(apksToUpdate); + for (final Apk apk : apksToUpdate) { + boolean known = false; + for (final Apk knownApk : knownApks) { + if (knownApk.id.equals(apk.id) && knownApk.vercode == apk.vercode) { + known = true; + break; + } + } + + if (known) { + operations.add(updateExistingApk(apk)); + } else { + operations.add(insertNewApk(apk)); + knownApks.add(apk); // In case another repo has the same version/id combo for this apk. + } + } + + Utils.debugLog(TAG, "Updating/inserting " + operations.size() + " apks."); + try { + executeBatchWithStatus(ApkProvider.getAuthority(), operations, currentCount, totalApksAppsCount); + } catch (RemoteException | OperationApplicationException e) { + Log.e(TAG, "Could not update/insert apps", e); + } + } + + private ContentProviderOperation updateExistingApk(final Apk apk) { + Uri uri = ApkProvider.getContentUri(apk); + ContentValues values = apk.toContentValues(); + return ContentProviderOperation.newUpdate(uri).withValues(values).build(); + } + + private ContentProviderOperation insertNewApk(final Apk apk) { + ContentValues values = apk.toContentValues(); + Uri uri = ApkProvider.getContentUri(); + return ContentProviderOperation.newInsert(uri).withValues(values).build(); + } + + private ContentProviderOperation updateExistingApp(App app) { + Uri uri = AppProvider.getContentUri(app); + ContentValues values = app.toContentValues(); + for (final String toIgnore : APP_FIELDS_TO_IGNORE) { + if (values.containsKey(toIgnore)) { + values.remove(toIgnore); + } + } + return ContentProviderOperation.newUpdate(uri).withValues(values).build(); + } + + private ContentProviderOperation insertNewApp(App app) { + ContentValues values = app.toContentValues(); + Uri uri = AppProvider.getContentUri(); + return ContentProviderOperation.newInsert(uri).withValues(values).build(); + } + + private static boolean isApkToBeUpdated(Apk existingApk, List apksToUpdate) { + for (final Apk apkToUpdate : apksToUpdate) { + if (apkToUpdate.vercode == existingApk.vercode && apkToUpdate.id.equals(existingApk.id)) { + return true; + } + } + return false; + } + + private void removeApksFromRepos(List repos) { + for (final Repo repo : repos) { + Uri uri = ApkProvider.getRepoUri(repo.getId()); + int numDeleted = context.getContentResolver().delete(uri, null, null); + Utils.debugLog(TAG, "Removing " + numDeleted + " apks from repo " + repo.address); + } + } + + private void removeAppsWithoutApks() { + int numDeleted = context.getContentResolver().delete(AppProvider.getNoApksUri(), null, null); + Utils.debugLog(TAG, "Removing " + numDeleted + " apks that don't have any apks"); + } + + private List getKnownAppIds(List apps) { + List knownAppIds = new ArrayList<>(); + if (apps.isEmpty()) { + return knownAppIds; + } + if (apps.size() > AppProvider.MAX_APPS_TO_QUERY) { + int middle = apps.size() / 2; + List apps1 = apps.subList(0, middle); + List apps2 = apps.subList(middle, apps.size()); + knownAppIds.addAll(getKnownAppIds(apps1)); + knownAppIds.addAll(getKnownAppIds(apps2)); + } else { + knownAppIds.addAll(getKnownAppIdsFromProvider(apps)); + } + return knownAppIds; + } + + /** + * Looks in the database to see which apps we already know about. Only + * returns ids of apps that are in the database if they are in the "apps" + * array. + */ + private List getKnownAppIdsFromProvider(List apps) { + + final Uri uri = AppProvider.getContentUri(apps); + final String[] fields = {AppProvider.DataColumns.APP_ID}; + Cursor cursor = context.getContentResolver().query(uri, fields, null, null, null); + + int knownIdCount = cursor != null ? cursor.getCount() : 0; + List knownIds = new ArrayList<>(knownIdCount); + if (cursor != null) { + if (knownIdCount > 0) { + cursor.moveToFirst(); + while (!cursor.isAfterLast()) { + knownIds.add(cursor.getString(0)); + cursor.moveToNext(); + } + } + cursor.close(); + } + + return knownIds; + } + +} + diff --git a/F-Droid/src/org/fdroid/fdroid/UpdateService.java b/F-Droid/src/org/fdroid/fdroid/UpdateService.java index 06872e5c7..9556523cd 100644 --- a/F-Droid/src/org/fdroid/fdroid/UpdateService.java +++ b/F-Droid/src/org/fdroid/fdroid/UpdateService.java @@ -23,19 +23,14 @@ import android.app.IntentService; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; -import android.content.ContentProviderOperation; -import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.OperationApplicationException; import android.content.SharedPreferences; import android.database.Cursor; import android.net.ConnectivityManager; import android.net.NetworkInfo; -import android.net.Uri; import android.os.Build; -import android.os.RemoteException; import android.os.SystemClock; import android.preference.PreferenceManager; import android.support.v4.app.NotificationCompat; @@ -45,7 +40,6 @@ import android.text.TextUtils; import android.util.Log; import android.widget.Toast; -import org.fdroid.fdroid.data.Apk; import org.fdroid.fdroid.data.ApkProvider; import org.fdroid.fdroid.data.App; import org.fdroid.fdroid.data.AppProvider; @@ -54,9 +48,7 @@ import org.fdroid.fdroid.data.RepoProvider; import org.fdroid.fdroid.net.Downloader; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; public class UpdateService extends IntentService implements ProgressListener { @@ -89,20 +81,6 @@ public class UpdateService extends IntentService implements ProgressListener { super("UpdateService"); } - /** - * When an app already exists in the db, and we are updating it on the off chance that some - * values changed in the index, some fields should not be updated. Rather, they should be - * ignored, because they were explicitly set by the user, and hence can't be automatically - * overridden by the index. - * - * NOTE: In the future, these attributes will be moved to a join table, so that the app table - * is essentially completely transient, and can be nuked at any time. - */ - private static final String[] APP_FIELDS_TO_IGNORE = { - AppProvider.DataColumns.IGNORE_ALLUPDATES, - AppProvider.DataColumns.IGNORE_THISUPDATE, - }; - public static void updateNow(Context context) { updateRepoNow(null, context); } @@ -178,16 +156,16 @@ public class UpdateService extends IntentService implements ProgressListener { localBroadcastManager.unregisterReceiver(updateStatusReceiver); } - protected void sendStatus(int statusCode) { - sendStatus(statusCode, null); + protected static void sendStatus(Context context, int statusCode) { + sendStatus(context, statusCode, null); } - protected void sendStatus(int statusCode, String message) { + protected static void sendStatus(Context context, int statusCode, String message) { Intent intent = new Intent(LOCAL_ACTION_STATUS); intent.putExtra(EXTRA_STATUS_CODE, statusCode); if (!TextUtils.isEmpty(message)) intent.putExtra(EXTRA_MESSAGE, message); - LocalBroadcastManager.getInstance(this).sendBroadcast(intent); + LocalBroadcastManager.getInstance(context).sendBroadcast(intent); } protected void sendRepoErrorStatus(int statusCode, ArrayList repoErrors) { @@ -219,7 +197,7 @@ public class UpdateService extends IntentService implements ProgressListener { String totalSizeFriendly = Utils.getFriendlySize(totalSize); message = getString(R.string.status_download, repoAddress, downloadedSizeFriendly, totalSizeFriendly, percent); } - sendStatus(STATUS_INFO, message); + sendStatus(context, STATUS_INFO, message); } }; @@ -354,8 +332,8 @@ public class UpdateService extends IntentService implements ProgressListener { List repos = RepoProvider.Helper.all(this); // Process each repo... - Map appsToUpdate = new HashMap<>(); - List apksToUpdate = new ArrayList<>(); + RepoPersister appSaver = new RepoPersister(this); + //List swapRepos = new ArrayList<>(); List unchangedRepos = new ArrayList<>(); List updatedRepos = new ArrayList<>(); @@ -380,16 +358,13 @@ public class UpdateService extends IntentService implements ProgressListener { continue; } - sendStatus(STATUS_INFO, getString(R.string.status_connecting_to_repo, repo.address)); + sendStatus(this, STATUS_INFO, getString(R.string.status_connecting_to_repo, repo.address)); RepoUpdater updater = new RepoUpdater(getBaseContext(), repo); updater.setProgressListener(this); try { updater.update(); if (updater.hasChanged()) { - for (final App app : updater.getApps()) { - appsToUpdate.put(app.id, app); - } - apksToUpdate.addAll(updater.getApks()); + appSaver.queueUpdater(updater); updatedRepos.add(repo); changes = true; repoUpdateRememberers.add(updater.getRememberer()); @@ -406,29 +381,9 @@ public class UpdateService extends IntentService implements ProgressListener { if (!changes) { Utils.debugLog(TAG, "Not checking app details or compatibility, because all repos were up to date."); } else { - sendStatus(STATUS_INFO, getString(R.string.status_checking_compatibility)); + sendStatus(this, STATUS_INFO, getString(R.string.status_checking_compatibility)); - List listOfAppsToUpdate = new ArrayList<>(); - listOfAppsToUpdate.addAll(appsToUpdate.values()); - - calcApkCompatibilityFlags(this, apksToUpdate); - - // Need to do this BEFORE updating the apks, otherwise when it continually - // calls "get existing apks for repo X" then it will be getting the newly - // created apks, rather than those from the fresh, juicy index we just processed. - removeApksNoLongerInRepo(apksToUpdate, updatedRepos); - - int totalInsertsUpdates = listOfAppsToUpdate.size() + apksToUpdate.size(); - updateOrInsertApps(listOfAppsToUpdate, totalInsertsUpdates, 0); - updateOrInsertApks(apksToUpdate, totalInsertsUpdates, listOfAppsToUpdate.size()); - removeApksFromRepos(disabledRepos); - removeAppsWithoutApks(); - - // This will sort out the icon urls, compatibility flags. and suggested version - // for each app. It used to happen here in Java code, but was moved to SQL when - // it became apparant we don't always have enough info (depending on which repos - // were updated). - AppProvider.Helper.calcDetailsFromIndex(this); + appSaver.save(disabledRepos); notifyContentProviders(); @@ -448,9 +403,9 @@ public class UpdateService extends IntentService implements ProgressListener { if (errorRepos.isEmpty()) { if (changes) { - sendStatus(STATUS_COMPLETE_WITH_CHANGES); + sendStatus(this, STATUS_COMPLETE_WITH_CHANGES); } else { - sendStatus(STATUS_COMPLETE_AND_SAME); + sendStatus(this, STATUS_COMPLETE_AND_SAME); } } else { if (updatedRepos.size() + unchangedRepos.size() == 0) { @@ -461,7 +416,7 @@ public class UpdateService extends IntentService implements ProgressListener { } } catch (Exception e) { Log.e(TAG, "Exception during update processing", e); - sendStatus(STATUS_ERROR_GLOBAL, e.getMessage()); + sendStatus(this, STATUS_ERROR_GLOBAL, e.getMessage()); } } @@ -470,26 +425,6 @@ public class UpdateService extends IntentService implements ProgressListener { getContentResolver().notifyChange(ApkProvider.getContentUri(), null); } - /** - * This cannot be offloaded to the database (as we did with the query which - * updates apps, depending on whether their apks are compatible or not). - * The reason is that we need to interact with the CompatibilityChecker - * in order to see if, and why an apk is not compatible. - */ - private static void calcApkCompatibilityFlags(Context context, List apks) { - final CompatibilityChecker checker = new CompatibilityChecker(context); - for (final Apk apk : apks) { - final List reasons = checker.getIncompatibleReasons(apk); - if (reasons.size() > 0) { - apk.compatible = false; - apk.incompatibleReasons = Utils.CommaSeparatedList.make(reasons); - } else { - apk.compatible = true; - apk.incompatibleReasons = null; - } - } - } - private void performUpdateNotification() { Cursor cursor = getContentResolver().query( AppProvider.getCanUpdateUri(), @@ -557,214 +492,6 @@ public class UpdateService extends IntentService implements ProgressListener { notificationManager.notify(NOTIFY_ID_UPDATES_AVAILABLE, builder.build()); } - private List getKnownAppIds(List apps) { - List knownAppIds = new ArrayList<>(); - if (apps.isEmpty()) { - return knownAppIds; - } - if (apps.size() > AppProvider.MAX_APPS_TO_QUERY) { - int middle = apps.size() / 2; - List apps1 = apps.subList(0, middle); - List apps2 = apps.subList(middle, apps.size()); - knownAppIds.addAll(getKnownAppIds(apps1)); - knownAppIds.addAll(getKnownAppIds(apps2)); - } else { - knownAppIds.addAll(getKnownAppIdsFromProvider(apps)); - } - return knownAppIds; - } - - /** - * Looks in the database to see which apps we already know about. Only - * returns ids of apps that are in the database if they are in the "apps" - * array. - */ - private List getKnownAppIdsFromProvider(List apps) { - - final Uri uri = AppProvider.getContentUri(apps); - final String[] fields = {AppProvider.DataColumns.APP_ID}; - Cursor cursor = getContentResolver().query(uri, fields, null, null, null); - - int knownIdCount = cursor != null ? cursor.getCount() : 0; - List knownIds = new ArrayList<>(knownIdCount); - if (cursor != null) { - if (knownIdCount > 0) { - cursor.moveToFirst(); - while (!cursor.isAfterLast()) { - knownIds.add(cursor.getString(0)); - cursor.moveToNext(); - } - } - cursor.close(); - } - - return knownIds; - } - - private void updateOrInsertApps(List appsToUpdate, int totalUpdateCount, int currentCount) { - - List operations = new ArrayList<>(); - List knownAppIds = getKnownAppIds(appsToUpdate); - for (final App app : appsToUpdate) { - if (knownAppIds.contains(app.id)) { - operations.add(updateExistingApp(app)); - } else { - operations.add(insertNewApp(app)); - } - } - - Utils.debugLog(TAG, "Updating/inserting " + operations.size() + " apps."); - try { - executeBatchWithStatus(AppProvider.getAuthority(), operations, currentCount, totalUpdateCount); - } catch (RemoteException | OperationApplicationException e) { - Log.e(TAG, "Could not update or insert apps", e); - } - } - - private void executeBatchWithStatus(String providerAuthority, - List operations, - int currentCount, - int totalUpdateCount) - throws RemoteException, OperationApplicationException { - int i = 0; - while (i < operations.size()) { - int count = Math.min(operations.size() - i, 100); - ArrayList o = new ArrayList<>(operations.subList(i, i + count)); - sendStatus(STATUS_INFO, getString( - R.string.status_inserting, - (int) ((double) (currentCount + i) / totalUpdateCount * 100))); - getContentResolver().applyBatch(providerAuthority, o); - i += 100; - } - } - - /** - * Return list of apps from the "apks" argument which are already in the database. - */ - private List getKnownApks(List apks) { - final String[] fields = { - ApkProvider.DataColumns.APK_ID, - ApkProvider.DataColumns.VERSION, - ApkProvider.DataColumns.VERSION_CODE, - }; - return ApkProvider.Helper.knownApks(this, apks, fields); - } - - private void updateOrInsertApks(List apksToUpdate, int totalApksAppsCount, int currentCount) { - - List operations = new ArrayList<>(); - - List knownApks = getKnownApks(apksToUpdate); - for (final Apk apk : apksToUpdate) { - boolean known = false; - for (final Apk knownApk : knownApks) { - if (knownApk.id.equals(apk.id) && knownApk.vercode == apk.vercode) { - known = true; - break; - } - } - - if (known) { - operations.add(updateExistingApk(apk)); - } else { - operations.add(insertNewApk(apk)); - knownApks.add(apk); // In case another repo has the same version/id combo for this apk. - } - } - - Utils.debugLog(TAG, "Updating/inserting " + operations.size() + " apks."); - try { - executeBatchWithStatus(ApkProvider.getAuthority(), operations, currentCount, totalApksAppsCount); - } catch (RemoteException | OperationApplicationException e) { - Log.e(TAG, "Could not update/insert apps", e); - } - } - - private ContentProviderOperation updateExistingApk(final Apk apk) { - Uri uri = ApkProvider.getContentUri(apk); - ContentValues values = apk.toContentValues(); - return ContentProviderOperation.newUpdate(uri).withValues(values).build(); - } - - private ContentProviderOperation insertNewApk(final Apk apk) { - ContentValues values = apk.toContentValues(); - Uri uri = ApkProvider.getContentUri(); - return ContentProviderOperation.newInsert(uri).withValues(values).build(); - } - - private ContentProviderOperation updateExistingApp(App app) { - Uri uri = AppProvider.getContentUri(app); - ContentValues values = app.toContentValues(); - for (final String toIgnore : APP_FIELDS_TO_IGNORE) { - if (values.containsKey(toIgnore)) { - values.remove(toIgnore); - } - } - return ContentProviderOperation.newUpdate(uri).withValues(values).build(); - } - - private ContentProviderOperation insertNewApp(App app) { - ContentValues values = app.toContentValues(); - Uri uri = AppProvider.getContentUri(); - return ContentProviderOperation.newInsert(uri).withValues(values).build(); - } - - /** - * If a repo was updated (i.e. it is in use, and the index has changed - * since last time we did an update), then we want to remove any apks that - * belong to the repo which are not in the current list of apks that were - * retrieved. - */ - private void removeApksNoLongerInRepo(List apksToUpdate, List updatedRepos) { - - long startTime = System.currentTimeMillis(); - List toRemove = new ArrayList<>(); - - final String[] fields = { - ApkProvider.DataColumns.APK_ID, - ApkProvider.DataColumns.VERSION_CODE, - ApkProvider.DataColumns.VERSION, - }; - - for (final Repo repo : updatedRepos) { - final List existingApks = ApkProvider.Helper.findByRepo(this, repo, fields); - for (final Apk existingApk : existingApks) { - if (!isApkToBeUpdated(existingApk, apksToUpdate)) { - toRemove.add(existingApk); - } - } - } - - long duration = System.currentTimeMillis() - startTime; - Utils.debugLog(TAG, "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 (final Apk apkToUpdate : apksToUpdate) { - if (apkToUpdate.vercode == existingApk.vercode && apkToUpdate.id.equals(existingApk.id)) { - return true; - } - } - return false; - } - - private void removeApksFromRepos(List repos) { - for (final Repo repo : repos) { - Uri uri = ApkProvider.getRepoUri(repo.getId()); - int numDeleted = getContentResolver().delete(uri, null, null); - Utils.debugLog(TAG, "Removing " + numDeleted + " apks from repo " + repo.address); - } - } - - private void removeAppsWithoutApks() { - int numDeleted = getContentResolver().delete(AppProvider.getNoApksUri(), null, null); - Utils.debugLog(TAG, "Removing " + numDeleted + " apks that don't have any apks"); - } - /** * Received progress event from the RepoXMLHandler. It could be progress * downloading from the repo, or perhaps processing the info from the repo. @@ -783,6 +510,6 @@ public class UpdateService extends IntentService implements ProgressListener { message = getString(R.string.status_processing_xml_percent, repoAddress, downloadedSize, totalSize, percent); break; } - sendStatus(STATUS_INFO, message); + sendStatus(this, STATUS_INFO, message); } }