From 10106bf6ddc1dc8d5e2e101f01277b94a2e5bcda Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 21 Jan 2014 20:54:59 -0500 Subject: [PATCH] reorganize update process to set up updating individual repos This keeps the same logic as was in place before, but splits out code from onHandleIntent() so that it can be used to update specific repos, rather than always updating all repos. This is needed for transient repos, like p2p repos connected via bluetooth or local wifi. --- src/org/fdroid/fdroid/UpdateService.java | 340 ++++++++++++----------- 1 file changed, 174 insertions(+), 166 deletions(-) diff --git a/src/org/fdroid/fdroid/UpdateService.java b/src/org/fdroid/fdroid/UpdateService.java index d81b2fddd..f1c2544ce 100644 --- a/src/org/fdroid/fdroid/UpdateService.java +++ b/src/org/fdroid/fdroid/UpdateService.java @@ -21,22 +21,32 @@ package org.fdroid.fdroid; import java.util.ArrayList; import java.util.List; -import android.app.*; +import android.app.AlarmManager; +import android.app.IntentService; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.ProgressDialog; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.net.ConnectivityManager; import android.net.NetworkInfo; -import android.os.*; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.os.Parcelable; +import android.os.ResultReceiver; +import android.os.SystemClock; import android.preference.PreferenceManager; -import android.util.Log; -import org.fdroid.fdroid.updater.RepoUpdater; - import android.support.v4.app.NotificationCompat; import android.support.v4.app.TaskStackBuilder; +import android.text.TextUtils; +import android.util.Log; import android.widget.Toast; +import org.fdroid.fdroid.updater.RepoUpdater; + public class UpdateService extends IntentService implements ProgressListener { public static final String RESULT_MESSAGE = "msg"; @@ -232,177 +242,20 @@ public class UpdateService extends IntentService implements ProgressListener { } else { Log.d("FDroid", "Unscheduled (manually requested) update"); } - - boolean notify = prefs.getBoolean(Preferences.PREF_UPD_NOTIFY, false); - - // Grab some preliminary information, then we can release the - // database while we do all the downloading, etc... - int updates = 0; - List repos; - List apps; - try { - DB db = DB.getDB(); - repos = db.getRepos(); - apps = db.getApps(false); - } finally { - DB.releaseDB(); - } - - // Process each repo... - List updatingApps = new ArrayList(); - List keeprepos = new ArrayList(); - boolean success = true; - boolean changes = false; - for (DB.Repo repo : repos) { - if (!repo.inuse) { - continue; - } - sendStatus(STATUS_INFO, getString(R.string.status_connecting_to_repo, repo.address)); - RepoUpdater updater = RepoUpdater.createUpdaterFor(getBaseContext(), repo); - updater.setProgressListener(this); - try { - updater.update(); - if (updater.hasChanged()) { - updatingApps.addAll(updater.getApps()); - changes = true; - } else { - keeprepos.add(repo.id); - } - } catch (RepoUpdater.UpdateException e) { - errmsg += (errmsg.length() == 0 ? "" : "\n") + e.getMessage(); - Log.e("FDroid", "Error updating repository " + repo.address + ": " + e.getMessage()); - Log.e("FDroid", Log.getStackTraceString(e)); - } - } - - if (!changes && success) { - Log.d("FDroid", - "Not checking app details or compatibility, " + - "because all repos were up to date."); - } else if (changes && success) { - - sendStatus(STATUS_INFO, - getString(R.string.status_checking_compatibility)); - - DB db = DB.getDB(); - try { - - // Need to flag things we're keeping despite having received - // no data about during the update. (i.e. stuff from a repo - // that we know is unchanged due to the etag) - for (int keep : keeprepos) { - for (DB.App app : apps) { - boolean keepapp = false; - for (DB.Apk apk : app.apks) { - if (apk.repo == keep) { - keepapp = true; - break; - } - } - if (keepapp) { - DB.App app_k = null; - for (DB.App app2 : apps) { - if (app2.id.equals(app.id)) { - app_k = app2; - break; - } - } - if (app_k == null) { - updatingApps.add(app); - app_k = app; - } - app_k.updated = true; - db.populateDetails(app_k, keep); - for (DB.Apk apk : app.apks) - if (apk.repo == keep) - apk.updated = true; - } - } - } - - db.beginUpdate(apps); - for (DB.App app : updatingApps) { - db.updateApplication(app); - } - db.endUpdate(); - for (DB.Repo repo : repos) - db.writeLastEtag(repo); - } catch (Exception ex) { - db.cancelUpdate(); - Log.e("FDroid", "Exception during update processing:\n" - + Log.getStackTraceString(ex)); - errmsg = "Exception during processing - " + ex.getMessage(); - success = false; - } finally { - DB.releaseDB(); - } - - } - - if (success && changes) { - ((FDroidApp) getApplication()).invalidateAllApps(); - if (notify) { - apps = ((FDroidApp) getApplication()).getApps(); - updates = getNumUpdates(apps); - } - } - - if (success && changes && notify && updates > 0) { - Log.d("FDroid", "Notifying "+updates+" updates."); - NotificationCompat.Builder mBuilder = - new NotificationCompat.Builder( - this) - .setAutoCancel(true) - .setContentTitle( - getString(R.string.fdroid_updates_available)); - if (Build.VERSION.SDK_INT >= 11) { - mBuilder.setSmallIcon(R.drawable.ic_stat_notify_updates); - } else { - mBuilder.setSmallIcon(R.drawable.ic_launcher); - } - Intent notifyIntent = new Intent(this, FDroid.class) - .putExtra(FDroid.EXTRA_TAB_UPDATE, true); - if (updates > 1) { - mBuilder.setContentText(getString( - R.string.many_updates_available, updates)); - - } else { - mBuilder.setContentText(getString(R.string.one_update_available)); - } - TaskStackBuilder stackBuilder = TaskStackBuilder - .create(this).addParentStack(FDroid.class) - .addNextIntent(notifyIntent); - PendingIntent pendingIntent = stackBuilder - .getPendingIntent(0, - PendingIntent.FLAG_UPDATE_CURRENT); - mBuilder.setContentIntent(pendingIntent); - NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - mNotificationManager.notify(1, mBuilder.build()); - } - - if (!success) { - if (errmsg.length() == 0) - errmsg = "Unknown error"; - sendStatus(STATUS_ERROR, errmsg); - } else { + errmsg = updateRepos(); + if (TextUtils.isEmpty(errmsg)) { Editor e = prefs.edit(); e.putLong(Preferences.PREF_UPD_LAST, System.currentTimeMillis()); e.commit(); - if (changes) { - sendStatus(STATUS_COMPLETE_WITH_CHANGES); - } else { - sendStatus(STATUS_COMPLETE_AND_SAME); - } } - } catch (Exception e) { Log.e("FDroid", "Exception during update processing:\n" + Log.getStackTraceString(e)); - if (errmsg.length() == 0) + if (TextUtils.isEmpty(errmsg)) errmsg = "Unknown error"; sendStatus(STATUS_ERROR, errmsg); - } finally { + } finally { Log.d("FDroid", "Update took " + ((System.currentTimeMillis() - startTime) / 1000) + " seconds."); @@ -410,6 +263,161 @@ public class UpdateService extends IntentService implements ProgressListener { } } + protected String updateRepos() throws Exception { + SharedPreferences prefs = PreferenceManager + .getDefaultSharedPreferences(getBaseContext()); + boolean notify = prefs.getBoolean(Preferences.PREF_UPD_NOTIFY, false); + String errmsg = ""; + // Grab some preliminary information, then we can release the + // database while we do all the downloading, etc... + int updates = 0; + List repos; + List apps; + try { + DB db = DB.getDB(); + repos = db.getRepos(); + apps = db.getApps(false); + } finally { + DB.releaseDB(); + } + + // Process each repo... + List updatingApps = new ArrayList(); + List keeprepos = new ArrayList(); + boolean changes = false; + for (DB.Repo repo : repos) { + if (!repo.inuse) + continue; + sendStatus(STATUS_INFO, getString(R.string.status_connecting_to_repo, repo.address)); + RepoUpdater updater = RepoUpdater.createUpdaterFor(getBaseContext(), repo); + updater.setProgressListener(this); + try { + updater.update(); + if (updater.hasChanged()) { + updatingApps.addAll(updater.getApps()); + changes = true; + } else { + keeprepos.add(repo.id); + } + } catch (RepoUpdater.UpdateException e) { + errmsg += (errmsg.length() == 0 ? "" : "\n") + e.getMessage(); + Log.e("FDroid", "Error updating repository " + repo.address + ": " + e.getMessage()); + Log.e("FDroid", Log.getStackTraceString(e)); + } + } + + boolean success = true; + if (!changes) { + Log.d("FDroid", "Not checking app details or compatibility, " + + "because all repos were up to date."); + } else { + sendStatus(STATUS_INFO, getString(R.string.status_checking_compatibility)); + + DB db = DB.getDB(); + try { + + // Need to flag things we're keeping despite having received + // no data about during the update. (i.e. stuff from a repo + // that we know is unchanged due to the etag) + for (int keep : keeprepos) { + for (DB.App app : apps) { + boolean keepapp = false; + for (DB.Apk apk : app.apks) { + if (apk.repo == keep) { + keepapp = true; + break; + } + } + if (keepapp) { + DB.App app_k = null; + for (DB.App app2 : apps) { + if (app2.id.equals(app.id)) { + app_k = app2; + break; + } + } + if (app_k == null) { + updatingApps.add(app); + app_k = app; + } + app_k.updated = true; + db.populateDetails(app_k, keep); + for (DB.Apk apk : app.apks) + if (apk.repo == keep) + apk.updated = true; + } + } + } + + db.beginUpdate(apps); + for (DB.App app : updatingApps) { + db.updateApplication(app); + } + db.endUpdate(); + for (DB.Repo repo : repos) + db.writeLastEtag(repo); + } catch (Exception ex) { + db.cancelUpdate(); + Log.e("FDroid", "Exception during update processing:\n" + + Log.getStackTraceString(ex)); + errmsg = "Exception during processing - " + ex.getMessage(); + success = false; + } finally { + DB.releaseDB(); + } + } + + if (success && changes) { + ((FDroidApp) getApplication()).invalidateAllApps(); + if (notify) { + apps = ((FDroidApp) getApplication()).getApps(); + updates = getNumUpdates(apps); + } + if (notify && updates > 0) + showAppUpdatesNotification(updates); + } + + if (success) { + if (changes) { + sendStatus(STATUS_COMPLETE_WITH_CHANGES); + } else { + sendStatus(STATUS_COMPLETE_AND_SAME); + } + } else { + if (TextUtils.isEmpty(errmsg)) + errmsg = "Unknown error"; + sendStatus(STATUS_ERROR, errmsg); + } + + return errmsg; + } + + private void showAppUpdatesNotification(int updates) throws Exception { + Log.d("FDroid", "Notifying " + updates + " updates."); + NotificationCompat.Builder builder = + new NotificationCompat.Builder(this) + .setAutoCancel(true) + .setContentTitle(getString(R.string.fdroid_updates_available)); + if (Build.VERSION.SDK_INT >= 11) { + builder.setSmallIcon(R.drawable.ic_stat_notify_updates); + } else { + builder.setSmallIcon(R.drawable.ic_launcher); + } + Intent notifyIntent = new Intent(this, FDroid.class) + .putExtra(FDroid.EXTRA_TAB_UPDATE, true); + if (updates > 1) { + builder.setContentText(getString(R.string.many_updates_available, updates)); + } else { + builder.setContentText(getString(R.string.one_update_available)); + } + TaskStackBuilder stackBuilder = TaskStackBuilder + .create(this).addParentStack(FDroid.class) + .addNextIntent(notifyIntent); + PendingIntent pi = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT); + builder.setContentIntent(pi); + NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + nm.notify(1, builder.build()); + } /** * Received progress event from the RepoXMLHandler. It could be progress