From 4bcf4bf60de955f397b3e30583a47e1b7a062957 Mon Sep 17 00:00:00 2001 From: Peter Serwylo Date: Tue, 9 Apr 2013 18:31:33 +1000 Subject: [PATCH 1/2] Progress information during repo update. Polls the download server before download to see how big the file is so that we can figur eout our progress during download. Its a bit of a hit (about 1.5 seconds on my connection), but I think most people would be willing to take a small hit to get accurate percentage measurements. I also spend a small amount of time (~1.5 seconds) asking how big the file is before we download it, so that we can give an accurate progress measurement. The same can be said for peeking into the XML file before we pass it to the SAX parser, by just iterating over every line looking for "What\'s New Recently Updated + + Downloading %1$s / %2$s (%3$d%%) + Processing application %1$d of %2$d + Connecting to repository:\n%1$s + Checking apps compatibility with your device… + diff --git a/src/org/fdroid/fdroid/AppDetails.java b/src/org/fdroid/fdroid/AppDetails.java index 5e4f75917..e3d86a440 100644 --- a/src/org/fdroid/fdroid/AppDetails.java +++ b/src/org/fdroid/fdroid/AppDetails.java @@ -127,7 +127,7 @@ public class AppDetails extends ListActivity { if (apk.detail_size == 0) { size.setText(""); } else { - size.setText(getFriendlySize(apk.detail_size)); + size.setText(Utils.getFriendlySize(apk.detail_size)); } TextView buildtype = (TextView) v.findViewById(R.id.buildtype); if (apk.srcname != null) { @@ -153,19 +153,6 @@ public class AppDetails extends ListActivity { } } - private static final String[] FRIENDLY_SIZE_FORMAT = { - "%.0f B", "%.0f KiB", "%.1f MiB", "%.2f GiB" }; - - private static String getFriendlySize(int size) { - double s = size; - int i = 0; - while (i < FRIENDLY_SIZE_FORMAT.length - 1 && s >= 1024) { - s = (100 * s / 1024) / 100.0; - i++; - } - return String.format(FRIENDLY_SIZE_FORMAT[i], s); - } - private static final int INSTALL = Menu.FIRST; private static final int UNINSTALL = Menu.FIRST + 1; private static final int WEBSITE = Menu.FIRST + 2; diff --git a/src/org/fdroid/fdroid/FDroid.java b/src/org/fdroid/fdroid/FDroid.java index c14703eb5..ac73b9c76 100644 --- a/src/org/fdroid/fdroid/FDroid.java +++ b/src/org/fdroid/fdroid/FDroid.java @@ -384,13 +384,19 @@ public class FDroid extends FragmentActivity { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { - if (resultCode == 1) { - Toast.makeText(FDroid.this, resultData.getString("errmsg"), - Toast.LENGTH_LONG).show(); - } else { + String message = resultData.getString(UpdateService.RESULT_MESSAGE); + boolean finished = false; + if (resultCode == UpdateService.STATUS_ERROR) { + Toast.makeText(FDroid.this, message, Toast.LENGTH_LONG).show(); + finished = true; + } else if (resultCode == UpdateService.STATUS_COMPLETE) { repopulateViews(); + finished = true; + } else if (resultCode == UpdateService.STATUS_INFO) { + pd.setMessage(message); } - if (pd.isShowing()) + + if (finished && pd.isShowing()) pd.dismiss(); } } diff --git a/src/org/fdroid/fdroid/ProgressListener.java b/src/org/fdroid/fdroid/ProgressListener.java new file mode 100644 index 000000000..2ec97ed92 --- /dev/null +++ b/src/org/fdroid/fdroid/ProgressListener.java @@ -0,0 +1,7 @@ +package org.fdroid.fdroid; + +public interface ProgressListener { + + public void onProgress(int type, int progress, int total); + +} diff --git a/src/org/fdroid/fdroid/RepoXMLHandler.java b/src/org/fdroid/fdroid/RepoXMLHandler.java index 2ab7360a5..f8844dc9b 100644 --- a/src/org/fdroid/fdroid/RepoXMLHandler.java +++ b/src/org/fdroid/fdroid/RepoXMLHandler.java @@ -30,6 +30,7 @@ import java.io.Reader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; +import java.net.URLConnection; import java.security.cert.Certificate; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -66,13 +67,21 @@ public class RepoXMLHandler extends DefaultHandler { private String pubkey; private String hashType; + private int progressCounter = 0; + private ProgressListener progressListener; + + public static final int PROGRESS_TYPE_DOWNLOAD = 1; + public static final int PROGRESS_TYPE_PROCESS_XML = 2; + // The date format used in the repo XML file. private SimpleDateFormat mXMLDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + private int totalAppCount; - public RepoXMLHandler(int repo, Vector apps) { + public RepoXMLHandler(int repo, Vector apps, ProgressListener listener) { this.repo = repo; this.apps = apps; pubkey = null; + progressListener = listener; } @Override @@ -225,7 +234,6 @@ public class RepoXMLHandler extends DefaultHandler { @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { - super.startElement(uri, localName, qName, attributes); if (localName == "repo") { String pk = attributes.getValue("", "pubkey"); @@ -234,6 +242,8 @@ public class RepoXMLHandler extends DefaultHandler { } else if (localName == "application" && curapp == null) { curapp = new DB.App(); curapp.detail_Populated = true; + progressCounter ++; + progressListener.onProgress(RepoXMLHandler.PROGRESS_TYPE_PROCESS_XML, progressCounter, totalAppCount); } else if (localName == "package" && curapp != null && curapk == null) { curapk = new DB.Apk(); curapk.id = curapp.id; @@ -252,29 +262,38 @@ public class RepoXMLHandler extends DefaultHandler { // empty) may contain an etag value for the response, or it may be left // empty if none was available. private static int getRemoteFile(Context ctx, String url, String dest, - String etag, StringBuilder retag) throws MalformedURLException, + String etag, StringBuilder retag, + ProgressListener progressListener ) throws MalformedURLException, IOException { long startTime = System.currentTimeMillis(); URL u = new URL(url); - HttpURLConnection uc = (HttpURLConnection) u.openConnection(); + HttpURLConnection connection = (HttpURLConnection) u.openConnection(); if (etag != null) - uc.setRequestProperty("If-None-Match", etag); + connection.setRequestProperty("If-None-Match", etag); int totalBytes = 0; - int code = uc.getResponseCode(); + int code = connection.getResponseCode(); if (code == 200) { + // Testing in the emulator for me, showed that figuring out the filesize took about 1 to 1.5 seconds. + // To put this in context, downloading a repo of: + // - 400k takes ~6 seconds + // - 5k takes ~3 seconds + // on my connection. I think the 1/1.5 seconds is worth it, because as the repo grows, the tradeoff will + // become more worth it. + int size = connection.getContentLength(); + Log.d("FDroid", "Downloading " + size + " bytes from " + url); InputStream input = null; OutputStream output = null; try { - input = new URL(url).openStream(); + input = connection.getInputStream(); output = ctx.openFileOutput(dest, Context.MODE_PRIVATE); - Utils.copy(input, output); + Utils.copy(input, output, size, progressListener, PROGRESS_TYPE_DOWNLOAD); } finally { Utils.closeQuietly(output); Utils.closeQuietly(input); } - String et = uc.getHeaderField("ETag"); + String et = connection.getHeaderField("ETag"); if (et != null) retag.append(et); } @@ -293,7 +312,8 @@ public class RepoXMLHandler extends DefaultHandler { // value for the index that was successfully processed, or it may contain // null if none was available. public static String doUpdate(Context ctx, DB.Repo repo, - Vector apps, StringBuilder newetag, Vector keeprepos) { + Vector apps, StringBuilder newetag, Vector keeprepos, + ProgressListener progressListener) { try { int code = 0; @@ -310,7 +330,7 @@ public class RepoXMLHandler extends DefaultHandler { } catch (Exception e) { } code = getRemoteFile(ctx, address, "tempindex.jar", - repo.lastetag, newetag); + repo.lastetag, newetag, progressListener); if (code == 200) { String jarpath = ctx.getFilesDir() + "/tempindex.jar"; JarFile jar = null; @@ -366,7 +386,7 @@ public class RepoXMLHandler extends DefaultHandler { // It's an old-fashioned unsigned repo... Log.d("FDroid", "Getting unsigned index from " + repo.address); code = getRemoteFile(ctx, repo.address + "/index.xml", - "tempindex.xml", repo.lastetag, newetag); + "tempindex.xml", repo.lastetag, newetag, progressListener); } if (code == 200) { @@ -374,11 +394,22 @@ public class RepoXMLHandler extends DefaultHandler { SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParser sp = spf.newSAXParser(); XMLReader xr = sp.getXMLReader(); - RepoXMLHandler handler = new RepoXMLHandler(repo.id, apps); + RepoXMLHandler handler = new RepoXMLHandler(repo.id, apps, progressListener); xr.setContentHandler(handler); - Reader r = new BufferedReader(new FileReader(new File( - ctx.getFilesDir() + "/tempindex.xml"))); + File tempIndex = new File(ctx.getFilesDir() + "/tempindex.xml"); + BufferedReader r = new BufferedReader(new FileReader(tempIndex)); + + // A bit of a hack, this might return false positives if an apps description + // or some other part of the XML file contains this, but it is a pretty good + // estimate and makes the progress counter more informative. + // As with asking the server about the size of the index before downloading, + // this also has a time tradeoff. It takes about three seconds to iterate + // through the file and count 600 apps on a slow emulator (v17), but if it is + // taking two minutes to update, the three second wait may be worth it. + final String APPLICATION = " 0) + resultData.putString(RESULT_MESSAGE, message); + receiver.send( statusCode, resultData ); + } + } + + /** + * We might be doing a scheduled run, or we might have been launched by + * the app in response to a user's request. If we have a receiver, it's + * the latter... + */ + private boolean isScheduledRun() { + return receiver == null; + } + protected void onHandleIntent(Intent intent) { - // We might be doing a scheduled run, or we might have been launched by - // the app in response to a user's request. If we get this receiver, - // it's - // the latter... - ResultReceiver receiver = intent.getParcelableExtra("receiver"); + receiver = intent.getParcelableExtra("receiver"); long startTime = System.currentTimeMillis(); String errmsg = ""; - try { SharedPreferences prefs = PreferenceManager .getDefaultSharedPreferences(getBaseContext()); // See if it's time to actually do anything yet... - if (receiver == null) { + if (isScheduledRun()) { long lastUpdate = prefs.getLong("lastUpdateCheck", 0); String sint = prefs.getString("updateInterval", "0"); int interval = Integer.parseInt(sint); @@ -124,9 +148,12 @@ public class UpdateService extends IntentService { boolean success = true; for (DB.Repo repo : repos) { if (repo.inuse) { + + sendStatus(STATUS_INFO, getString(R.string.status_connecting_to_repo, repo.address)); + StringBuilder newetag = new StringBuilder(); String err = RepoXMLHandler.doUpdate(getBaseContext(), - repo, apps, newetag, keeprepos); + repo, apps, newetag, keeprepos, this); if (err == null) { repo.lastetag = newetag.toString(); } else { @@ -142,6 +169,7 @@ public class UpdateService extends IntentService { } if (success) { + sendStatus(STATUS_INFO, getString(R.string.status_checking_compatibility)); Vector acceptedapps = new Vector(); Vector prevapps = ((FDroidApp) getApplication()) .getApps(); @@ -234,17 +262,12 @@ public class UpdateService extends IntentService { } } - if (receiver != null) { - Bundle resultData = new Bundle(); - if (!success) { - if (errmsg.length() == 0) - errmsg = "Unknown error"; - resultData.putString("errmsg", errmsg); - receiver.send(1, resultData); - } else { - receiver.send(0, resultData); - } - + if (!success) { + if (errmsg.length() == 0) + errmsg = "Unknown error"; + sendStatus(STATUS_ERROR, errmsg); + } else { + sendStatus(STATUS_COMPLETE); } if(success) { @@ -257,19 +280,15 @@ public class UpdateService extends IntentService { Log.e("FDroid", "Exception during update processing:\n" + Log.getStackTraceString(e)); - if (receiver != null) { - Bundle resultData = new Bundle(); - if (errmsg.length() == 0) - errmsg = "Unknown error"; - resultData.putString("errmsg", errmsg); - receiver.send(1, resultData); - } + if (errmsg.length() == 0) + errmsg = "Unknown error"; + sendStatus(STATUS_ERROR, errmsg); } finally { Log.d("FDroid", "Update took " + ((System.currentTimeMillis() - startTime) / 1000) + " seconds."); + receiver = null; } - } private void getIcon(DB.App app, Vector repos) { @@ -306,4 +325,23 @@ public class UpdateService extends IntentService { } } + /** + * Received progress event from the RepoXMLHandler. + * It could be progress downloading from the repo, or perhaps processing the info from the repo. + */ + @Override + public void onProgress(int type, int progress, int total) { + + String message = ""; + if (type == RepoXMLHandler.PROGRESS_TYPE_DOWNLOAD) { + String downloadedSize = Utils.getFriendlySize( progress ); + String totalSize = Utils.getFriendlySize( total ); + int percent = (int)((double)progress/total * 100); + message = getString(R.string.status_download, downloadedSize, totalSize, percent); + } else if (type == RepoXMLHandler.PROGRESS_TYPE_PROCESS_XML) { + message = getString(R.string.status_processing_xml, progress, total); + } + + sendStatus(STATUS_INFO, message); + } } diff --git a/src/org/fdroid/fdroid/Utils.java b/src/org/fdroid/fdroid/Utils.java index 14dad6be0..d0d5bfe2f 100644 --- a/src/org/fdroid/fdroid/Utils.java +++ b/src/org/fdroid/fdroid/Utils.java @@ -22,6 +22,10 @@ import java.io.Closeable; import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; public final class Utils { private Utils() { @@ -29,18 +33,32 @@ public final class Utils { public static final int BUFFER_SIZE = 4096; - public static void copy(InputStream input, OutputStream output) - throws IOException { - byte[] buffer = new byte[BUFFER_SIZE]; - while (true) { - int count = input.read(buffer); - if (count == -1) { - break; - } - output.write(buffer, 0, count); - } - output.flush(); - } + private static final String[] FRIENDLY_SIZE_FORMAT = { + "%.0f B", "%.0f KiB", "%.1f MiB", "%.2f GiB" }; + + + public static void copy(InputStream input, OutputStream output) + throws IOException { + copy(input, output, -1, null, -1); + } + + public static void copy(InputStream input, OutputStream output, int totalSize, ProgressListener progressListener, int progressType) + throws IOException { + byte[] buffer = new byte[BUFFER_SIZE]; + int bytesRead = 0; + while (true) { + int count = input.read(buffer); + if (count == -1) { + break; + } + if (progressListener != null) { + bytesRead += count; + progressListener.onProgress(progressType, bytesRead, totalSize); + } + output.write(buffer, 0, count); + } + output.flush(); + } public static void closeQuietly(Closeable closeable) { if (closeable == null) { @@ -52,4 +70,52 @@ public final class Utils { // ignore } } + + public static String getFriendlySize(int size) { + double s = size; + int i = 0; + while (i < FRIENDLY_SIZE_FORMAT.length - 1 && s >= 1024) { + s = (100 * s / 1024) / 100.0; + i++; + } + return String.format(FRIENDLY_SIZE_FORMAT[i], s); + } + + public static int countSubstringOccurrence(File file, String substring) throws IOException { + int count = 0; + BufferedReader reader = null; + try { + + reader = new BufferedReader(new FileReader(file)); + while(true) { + String line = reader.readLine(); + if (line == null) { + break; + } + count += countSubstringOccurrence(line, substring); + } + + } finally { + closeQuietly(reader); + } + return count; + } + + /** + * Thanks to http://stackoverflow.com/a/767910 + */ + public static int countSubstringOccurrence(String toSearch, String substring) { + int count = 0; + int index = 0; + while (true) { + index = toSearch.indexOf(substring, index); + if (index == -1){ + break; + } + count ++; + index += substring.length(); + } + return count; + } + } From 841ec9d2896c49c29cdbb57d65ef158d0a0e63b8 Mon Sep 17 00:00:00 2001 From: Peter Serwylo Date: Tue, 16 Apr 2013 12:45:51 +1000 Subject: [PATCH 2/2] Make progress more multi-repo aware. Changed strings.xml to reflect the multi-repo nature of updating. Also refactored progress events to make them more generic and easier to nest deeply down the call stack. The ProgressListener now just expects a ProgressListener.Event, which in addition to statically typed type and progress info, also has an associated Bundle which can store arbitrary data. --- res/values/strings.xml | 11 ++-- src/org/fdroid/fdroid/ProgressListener.java | 49 +++++++++++++++++- src/org/fdroid/fdroid/RepoXMLHandler.java | 54 +++++++++++++------- src/org/fdroid/fdroid/UpdateService.java | 18 ++++--- src/org/fdroid/fdroid/Utils.java | 56 +++++++++------------ 5 files changed, 126 insertions(+), 62 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 26f5c031f..3a064405c 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -153,14 +153,15 @@ Recently Updated - Downloading %1$s / %2$s (%3$d%%) - Processing application %1$d of %2$d - Connecting to repository:\n%1$s - Checking apps compatibility with your device… + Downloading\n%2$s / %3$s (%4$d%%) from\n%1$s + Processing application\n%2$d of %3$d from\n%1$s + Connecting to\n%1$s + Checking all apps compatibility with your device… diff --git a/src/org/fdroid/fdroid/ProgressListener.java b/src/org/fdroid/fdroid/ProgressListener.java index 2ec97ed92..d38e342cd 100644 --- a/src/org/fdroid/fdroid/ProgressListener.java +++ b/src/org/fdroid/fdroid/ProgressListener.java @@ -1,7 +1,54 @@ package org.fdroid.fdroid; +import android.os.Bundle; + public interface ProgressListener { - public void onProgress(int type, int progress, int total); + public void onProgress(Event event); + + // I went a bit overboard with the overloaded constructors, but they all + // seemed potentially useful and unambiguous, so I just put them in there + // while I'm here. + public static class Event { + + public static final int NO_VALUE = Integer.MIN_VALUE; + + public final int type; + public final Bundle data; + + // These two are not final, so that you can create a template Event, + // pass it into a function which performs something over time, and + // that function can initialize "total" and progressively + // update "progress" + public int progress; + public int total; + + public Event(int type) { + this(type, NO_VALUE, NO_VALUE, null); + } + + public Event(int type, Bundle data) { + this(type, NO_VALUE, NO_VALUE, data); + } + + public Event(int type, int progress) { + this(type, progress, NO_VALUE, null); + } + + public Event(int type, int progress, Bundle data) { + this(type, NO_VALUE, NO_VALUE, data); + } + + public Event(int type, int progress, int total) { + this(type, progress, total, null); + } + + public Event(int type, int progress, int total, Bundle data) { + this.type = type; + this.progress = progress; + this.total = total; + this.data = data == null ? new Bundle() : data; + } + } } diff --git a/src/org/fdroid/fdroid/RepoXMLHandler.java b/src/org/fdroid/fdroid/RepoXMLHandler.java index f8844dc9b..2c9ce8917 100644 --- a/src/org/fdroid/fdroid/RepoXMLHandler.java +++ b/src/org/fdroid/fdroid/RepoXMLHandler.java @@ -42,6 +42,7 @@ import javax.net.ssl.SSLHandshakeException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; +import android.os.Bundle; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; @@ -55,8 +56,8 @@ import android.util.Log; public class RepoXMLHandler extends DefaultHandler { - // The ID of the repo we're processing. - private int repo; + // The repo we're processing. + private DB.Repo repo; private Vector apps; @@ -73,11 +74,13 @@ public class RepoXMLHandler extends DefaultHandler { public static final int PROGRESS_TYPE_DOWNLOAD = 1; public static final int PROGRESS_TYPE_PROCESS_XML = 2; + public static final String PROGRESS_DATA_REPO = "repo"; + // The date format used in the repo XML file. private SimpleDateFormat mXMLDateFormat = new SimpleDateFormat("yyyy-MM-dd"); private int totalAppCount; - public RepoXMLHandler(int repo, Vector apps, ProgressListener listener) { + public RepoXMLHandler(DB.Repo repo, Vector apps, ProgressListener listener) { this.repo = repo; this.apps = apps; pubkey = null; @@ -228,28 +231,37 @@ public class RepoXMLHandler extends DefaultHandler { curapp.requirements = DB.CommaSeparatedList.make(str); } } - } + private static Bundle createProgressData(String repoAddress) { + Bundle data = new Bundle(); + data.putString(PROGRESS_DATA_REPO, repoAddress); + return data; + } + @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { super.startElement(uri, localName, qName, attributes); - if (localName == "repo") { + if (localName.equals("repo")) { String pk = attributes.getValue("", "pubkey"); if (pk != null) pubkey = pk; - } else if (localName == "application" && curapp == null) { + } else if (localName.equals("application") && curapp == null) { curapp = new DB.App(); curapp.detail_Populated = true; + Bundle progressData = createProgressData(repo.address); progressCounter ++; - progressListener.onProgress(RepoXMLHandler.PROGRESS_TYPE_PROCESS_XML, progressCounter, totalAppCount); - } else if (localName == "package" && curapp != null && curapk == null) { + progressListener.onProgress( + new ProgressListener.Event( + RepoXMLHandler.PROGRESS_TYPE_PROCESS_XML, progressCounter, + totalAppCount, progressData)); + } else if (localName.equals("package") && curapp != null && curapk == null) { curapk = new DB.Apk(); curapk.id = curapp.id; - curapk.repo = repo; + curapk.repo = repo.id; hashType = null; - } else if (localName == "hash" && curapk != null) { + } else if (localName.equals("hash") && curapk != null) { hashType = attributes.getValue("", "type"); } curchars.setLength(0); @@ -263,7 +275,8 @@ public class RepoXMLHandler extends DefaultHandler { // empty if none was available. private static int getRemoteFile(Context ctx, String url, String dest, String etag, StringBuilder retag, - ProgressListener progressListener ) throws MalformedURLException, + ProgressListener progressListener, + ProgressListener.Event progressEvent) throws MalformedURLException, IOException { long startTime = System.currentTimeMillis(); @@ -280,14 +293,14 @@ public class RepoXMLHandler extends DefaultHandler { // - 5k takes ~3 seconds // on my connection. I think the 1/1.5 seconds is worth it, because as the repo grows, the tradeoff will // become more worth it. - int size = connection.getContentLength(); - Log.d("FDroid", "Downloading " + size + " bytes from " + url); + progressEvent.total = connection.getContentLength(); + Log.d("FDroid", "Downloading " + progressEvent.total + " bytes from " + url); InputStream input = null; OutputStream output = null; try { input = connection.getInputStream(); output = ctx.openFileOutput(dest, Context.MODE_PRIVATE); - Utils.copy(input, output, size, progressListener, PROGRESS_TYPE_DOWNLOAD); + Utils.copy(input, output, progressListener, progressEvent); } finally { Utils.closeQuietly(output); Utils.closeQuietly(input); @@ -329,8 +342,11 @@ public class RepoXMLHandler extends DefaultHandler { address += "?" + pi.versionName; } catch (Exception e) { } + Bundle progressData = createProgressData(repo.address); + ProgressListener.Event event = new ProgressListener.Event( + RepoXMLHandler.PROGRESS_TYPE_DOWNLOAD, progressData); code = getRemoteFile(ctx, address, "tempindex.jar", - repo.lastetag, newetag, progressListener); + repo.lastetag, newetag, progressListener, event ); if (code == 200) { String jarpath = ctx.getFilesDir() + "/tempindex.jar"; JarFile jar = null; @@ -385,8 +401,12 @@ public class RepoXMLHandler extends DefaultHandler { // It's an old-fashioned unsigned repo... Log.d("FDroid", "Getting unsigned index from " + repo.address); + Bundle eventData = createProgressData(repo.address); + ProgressListener.Event event = new ProgressListener.Event( + RepoXMLHandler.PROGRESS_TYPE_DOWNLOAD, eventData); code = getRemoteFile(ctx, repo.address + "/index.xml", - "tempindex.xml", repo.lastetag, newetag, progressListener); + "tempindex.xml", repo.lastetag, newetag, + progressListener, event); } if (code == 200) { @@ -394,7 +414,7 @@ public class RepoXMLHandler extends DefaultHandler { SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParser sp = spf.newSAXParser(); XMLReader xr = sp.getXMLReader(); - RepoXMLHandler handler = new RepoXMLHandler(repo.id, apps, progressListener); + RepoXMLHandler handler = new RepoXMLHandler(repo, apps, progressListener); xr.setContentHandler(handler); File tempIndex = new File(ctx.getFilesDir() + "/tempindex.xml"); diff --git a/src/org/fdroid/fdroid/UpdateService.java b/src/org/fdroid/fdroid/UpdateService.java index 667e5ab4e..084af18c0 100644 --- a/src/org/fdroid/fdroid/UpdateService.java +++ b/src/org/fdroid/fdroid/UpdateService.java @@ -330,16 +330,18 @@ public class UpdateService extends IntentService implements ProgressListener { * It could be progress downloading from the repo, or perhaps processing the info from the repo. */ @Override - public void onProgress(int type, int progress, int total) { + public void onProgress(ProgressListener.Event event) { String message = ""; - if (type == RepoXMLHandler.PROGRESS_TYPE_DOWNLOAD) { - String downloadedSize = Utils.getFriendlySize( progress ); - String totalSize = Utils.getFriendlySize( total ); - int percent = (int)((double)progress/total * 100); - message = getString(R.string.status_download, downloadedSize, totalSize, percent); - } else if (type == RepoXMLHandler.PROGRESS_TYPE_PROCESS_XML) { - message = getString(R.string.status_processing_xml, progress, total); + if (event.type == RepoXMLHandler.PROGRESS_TYPE_DOWNLOAD) { + String repoAddress = event.data.getString(RepoXMLHandler.PROGRESS_DATA_REPO); + String downloadedSize = Utils.getFriendlySize( event.progress ); + String totalSize = Utils.getFriendlySize( event.total ); + int percent = (int)((double)event.progress/event.total * 100); + message = getString(R.string.status_download, repoAddress, downloadedSize, totalSize, percent); + } else if (event.type == RepoXMLHandler.PROGRESS_TYPE_PROCESS_XML) { + String repoAddress = event.data.getString(RepoXMLHandler.PROGRESS_DATA_REPO); + message = getString(R.string.status_processing_xml, repoAddress, event.progress, event.total); } sendStatus(STATUS_INFO, message); diff --git a/src/org/fdroid/fdroid/Utils.java b/src/org/fdroid/fdroid/Utils.java index d0d5bfe2f..4d73e5d2c 100644 --- a/src/org/fdroid/fdroid/Utils.java +++ b/src/org/fdroid/fdroid/Utils.java @@ -18,18 +18,9 @@ package org.fdroid.fdroid; -import java.io.Closeable; -import java.io.InputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; +import java.io.*; public final class Utils { - private Utils() { - } public static final int BUFFER_SIZE = 4096; @@ -37,28 +28,31 @@ public final class Utils { "%.0f B", "%.0f KiB", "%.1f MiB", "%.2f GiB" }; - public static void copy(InputStream input, OutputStream output) - throws IOException { - copy(input, output, -1, null, -1); - } + public static void copy(InputStream input, OutputStream output) + throws IOException { + copy(input, output, null, null); + } - public static void copy(InputStream input, OutputStream output, int totalSize, ProgressListener progressListener, int progressType) - throws IOException { - byte[] buffer = new byte[BUFFER_SIZE]; - int bytesRead = 0; - while (true) { - int count = input.read(buffer); - if (count == -1) { - break; - } - if (progressListener != null) { - bytesRead += count; - progressListener.onProgress(progressType, bytesRead, totalSize); - } - output.write(buffer, 0, count); - } - output.flush(); - } + public static void copy(InputStream input, OutputStream output, + ProgressListener progressListener, + ProgressListener.Event templateProgressEvent) + throws IOException { + byte[] buffer = new byte[BUFFER_SIZE]; + int bytesRead = 0; + while (true) { + int count = input.read(buffer); + if (count == -1) { + break; + } + if (progressListener != null) { + bytesRead += count; + templateProgressEvent.progress = bytesRead; + progressListener.onProgress(templateProgressEvent); + } + output.write(buffer, 0, count); + } + output.flush(); + } public static void closeQuietly(Closeable closeable) { if (closeable == null) {