Merge commit 'refs/merge-requests/27' of git://gitorious.org/f-droid/fdroidclient into merge-requests/27
Conflicts: src/org/fdroid/fdroid/RepoXMLHandler.java src/org/fdroid/fdroid/UpdateService.java src/org/fdroid/fdroid/Utils.java
This commit is contained in:
commit
bbd9223ced
@ -152,4 +152,16 @@
|
|||||||
<string name="category_whatsnew">What\'s New</string>
|
<string name="category_whatsnew">What\'s New</string>
|
||||||
<string name="category_recentlyupdated">Recently Updated</string>
|
<string name="category_recentlyupdated">Recently Updated</string>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
status_download takes four parameters:
|
||||||
|
- Repository (url)
|
||||||
|
- Downloaded size (human readable)
|
||||||
|
- Total size (human readable)
|
||||||
|
- Percentage complete (int between 0-100)
|
||||||
|
-->
|
||||||
|
<string name="status_download">Downloading\n%2$s / %3$s (%4$d%%) from\n%1$s</string>
|
||||||
|
<string name="status_processing_xml">Processing application\n%2$d of %3$d from\n%1$s</string>
|
||||||
|
<string name="status_connecting_to_repo">Connecting to\n%1$s</string>
|
||||||
|
<string name="status_checking_compatibility">Checking all apps compatibility with your device…</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -127,7 +127,7 @@ public class AppDetails extends ListActivity {
|
|||||||
if (apk.detail_size == 0) {
|
if (apk.detail_size == 0) {
|
||||||
size.setText("");
|
size.setText("");
|
||||||
} else {
|
} else {
|
||||||
size.setText(getFriendlySize(apk.detail_size));
|
size.setText(Utils.getFriendlySize(apk.detail_size));
|
||||||
}
|
}
|
||||||
TextView buildtype = (TextView) v.findViewById(R.id.buildtype);
|
TextView buildtype = (TextView) v.findViewById(R.id.buildtype);
|
||||||
if (apk.srcname != null) {
|
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 INSTALL = Menu.FIRST;
|
||||||
private static final int UNINSTALL = Menu.FIRST + 1;
|
private static final int UNINSTALL = Menu.FIRST + 1;
|
||||||
private static final int WEBSITE = Menu.FIRST + 2;
|
private static final int WEBSITE = Menu.FIRST + 2;
|
||||||
|
@ -263,13 +263,19 @@ public class FDroid extends FragmentActivity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onReceiveResult(int resultCode, Bundle resultData) {
|
protected void onReceiveResult(int resultCode, Bundle resultData) {
|
||||||
if (resultCode == 1) {
|
String message = resultData.getString(UpdateService.RESULT_MESSAGE);
|
||||||
Toast.makeText(FDroid.this, resultData.getString("errmsg"),
|
boolean finished = false;
|
||||||
Toast.LENGTH_LONG).show();
|
if (resultCode == UpdateService.STATUS_ERROR) {
|
||||||
} else {
|
Toast.makeText(FDroid.this, message, Toast.LENGTH_LONG).show();
|
||||||
|
finished = true;
|
||||||
|
} else if (resultCode == UpdateService.STATUS_COMPLETE) {
|
||||||
repopulateViews();
|
repopulateViews();
|
||||||
|
finished = true;
|
||||||
|
} else if (resultCode == UpdateService.STATUS_INFO) {
|
||||||
|
pd.setMessage(message);
|
||||||
}
|
}
|
||||||
if (pd.isShowing())
|
|
||||||
|
if (finished && pd.isShowing())
|
||||||
pd.dismiss();
|
pd.dismiss();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
54
src/org/fdroid/fdroid/ProgressListener.java
Normal file
54
src/org/fdroid/fdroid/ProgressListener.java
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package org.fdroid.fdroid;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
public interface ProgressListener {
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -30,6 +30,7 @@ import java.io.Reader;
|
|||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
import java.security.cert.Certificate;
|
import java.security.cert.Certificate;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
@ -41,6 +42,7 @@ import javax.net.ssl.SSLHandshakeException;
|
|||||||
import javax.xml.parsers.SAXParser;
|
import javax.xml.parsers.SAXParser;
|
||||||
import javax.xml.parsers.SAXParserFactory;
|
import javax.xml.parsers.SAXParserFactory;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
import org.xml.sax.Attributes;
|
import org.xml.sax.Attributes;
|
||||||
import org.xml.sax.InputSource;
|
import org.xml.sax.InputSource;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
@ -54,8 +56,8 @@ import android.util.Log;
|
|||||||
|
|
||||||
public class RepoXMLHandler extends DefaultHandler {
|
public class RepoXMLHandler extends DefaultHandler {
|
||||||
|
|
||||||
// The ID of the repo we're processing.
|
// The repo we're processing.
|
||||||
private int repo;
|
private DB.Repo repo;
|
||||||
|
|
||||||
private List<DB.App> apps;
|
private List<DB.App> apps;
|
||||||
|
|
||||||
@ -66,13 +68,23 @@ public class RepoXMLHandler extends DefaultHandler {
|
|||||||
private String pubkey;
|
private String pubkey;
|
||||||
private String hashType;
|
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;
|
||||||
|
|
||||||
|
public static final String PROGRESS_DATA_REPO = "repo";
|
||||||
|
|
||||||
// The date format used in the repo XML file.
|
// The date format used in the repo XML file.
|
||||||
private SimpleDateFormat mXMLDateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
private SimpleDateFormat mXMLDateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
||||||
|
private int totalAppCount;
|
||||||
|
|
||||||
public RepoXMLHandler(int repo, List<DB.App> apps) {
|
public RepoXMLHandler(DB.Repo repo, List<DB.App> apps, ProgressListener listener) {
|
||||||
this.repo = repo;
|
this.repo = repo;
|
||||||
this.apps = apps;
|
this.apps = apps;
|
||||||
pubkey = null;
|
pubkey = null;
|
||||||
|
progressListener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -219,27 +231,37 @@ public class RepoXMLHandler extends DefaultHandler {
|
|||||||
curapp.requirements = DB.CommaSeparatedList.make(str);
|
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
|
@Override
|
||||||
public void startElement(String uri, String localName, String qName,
|
public void startElement(String uri, String localName, String qName,
|
||||||
Attributes attributes) throws SAXException {
|
Attributes attributes) throws SAXException {
|
||||||
|
|
||||||
super.startElement(uri, localName, qName, attributes);
|
super.startElement(uri, localName, qName, attributes);
|
||||||
if (localName == "repo") {
|
if (localName.equals("repo")) {
|
||||||
String pk = attributes.getValue("", "pubkey");
|
String pk = attributes.getValue("", "pubkey");
|
||||||
if (pk != null)
|
if (pk != null)
|
||||||
pubkey = pk;
|
pubkey = pk;
|
||||||
} else if (localName == "application" && curapp == null) {
|
} else if (localName.equals("application") && curapp == null) {
|
||||||
curapp = new DB.App();
|
curapp = new DB.App();
|
||||||
curapp.detail_Populated = true;
|
curapp.detail_Populated = true;
|
||||||
} else if (localName == "package" && curapp != null && curapk == null) {
|
Bundle progressData = createProgressData(repo.address);
|
||||||
|
progressCounter ++;
|
||||||
|
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 = new DB.Apk();
|
||||||
curapk.id = curapp.id;
|
curapk.id = curapp.id;
|
||||||
curapk.repo = repo;
|
curapk.repo = repo.id;
|
||||||
hashType = null;
|
hashType = null;
|
||||||
} else if (localName == "hash" && curapk != null) {
|
} else if (localName.equals("hash") && curapk != null) {
|
||||||
hashType = attributes.getValue("", "type");
|
hashType = attributes.getValue("", "type");
|
||||||
}
|
}
|
||||||
curchars.setLength(0);
|
curchars.setLength(0);
|
||||||
@ -252,29 +274,39 @@ public class RepoXMLHandler extends DefaultHandler {
|
|||||||
// empty) may contain an etag value for the response, or it may be left
|
// empty) may contain an etag value for the response, or it may be left
|
||||||
// empty if none was available.
|
// empty if none was available.
|
||||||
private static int getRemoteFile(Context ctx, String url, String dest,
|
private static int getRemoteFile(Context ctx, String url, String dest,
|
||||||
String etag, StringBuilder retag) throws MalformedURLException,
|
String etag, StringBuilder retag,
|
||||||
|
ProgressListener progressListener,
|
||||||
|
ProgressListener.Event progressEvent) throws MalformedURLException,
|
||||||
IOException {
|
IOException {
|
||||||
|
|
||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
URL u = new URL(url);
|
URL u = new URL(url);
|
||||||
HttpURLConnection uc = (HttpURLConnection) u.openConnection();
|
HttpURLConnection connection = (HttpURLConnection) u.openConnection();
|
||||||
if (etag != null)
|
if (etag != null)
|
||||||
uc.setRequestProperty("If-None-Match", etag);
|
connection.setRequestProperty("If-None-Match", etag);
|
||||||
int totalBytes = 0;
|
int totalBytes = 0;
|
||||||
int code = uc.getResponseCode();
|
int code = connection.getResponseCode();
|
||||||
if (code == 200) {
|
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.
|
||||||
|
progressEvent.total = connection.getContentLength();
|
||||||
|
Log.d("FDroid", "Downloading " + progressEvent.total + " bytes from " + url);
|
||||||
InputStream input = null;
|
InputStream input = null;
|
||||||
OutputStream output = null;
|
OutputStream output = null;
|
||||||
try {
|
try {
|
||||||
input = new URL(url).openStream();
|
input = connection.getInputStream();
|
||||||
output = ctx.openFileOutput(dest, Context.MODE_PRIVATE);
|
output = ctx.openFileOutput(dest, Context.MODE_PRIVATE);
|
||||||
Utils.copy(input, output);
|
Utils.copy(input, output, progressListener, progressEvent);
|
||||||
} finally {
|
} finally {
|
||||||
Utils.closeQuietly(output);
|
Utils.closeQuietly(output);
|
||||||
Utils.closeQuietly(input);
|
Utils.closeQuietly(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
String et = uc.getHeaderField("ETag");
|
String et = connection.getHeaderField("ETag");
|
||||||
if (et != null)
|
if (et != null)
|
||||||
retag.append(et);
|
retag.append(et);
|
||||||
}
|
}
|
||||||
@ -293,7 +325,8 @@ public class RepoXMLHandler extends DefaultHandler {
|
|||||||
// value for the index that was successfully processed, or it may contain
|
// value for the index that was successfully processed, or it may contain
|
||||||
// null if none was available.
|
// null if none was available.
|
||||||
public static String doUpdate(Context ctx, DB.Repo repo,
|
public static String doUpdate(Context ctx, DB.Repo repo,
|
||||||
List<DB.App> apps, StringBuilder newetag, List<Integer> keeprepos) {
|
List<DB.App> apps, StringBuilder newetag, List<Integer> keeprepos,
|
||||||
|
ProgressListener progressListener) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
int code = 0;
|
int code = 0;
|
||||||
@ -309,8 +342,11 @@ public class RepoXMLHandler extends DefaultHandler {
|
|||||||
address += "?" + pi.versionName;
|
address += "?" + pi.versionName;
|
||||||
} catch (Exception e) {
|
} 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",
|
code = getRemoteFile(ctx, address, "tempindex.jar",
|
||||||
repo.lastetag, newetag);
|
repo.lastetag, newetag, progressListener, event );
|
||||||
if (code == 200) {
|
if (code == 200) {
|
||||||
String jarpath = ctx.getFilesDir() + "/tempindex.jar";
|
String jarpath = ctx.getFilesDir() + "/tempindex.jar";
|
||||||
JarFile jar = null;
|
JarFile jar = null;
|
||||||
@ -365,8 +401,12 @@ public class RepoXMLHandler extends DefaultHandler {
|
|||||||
|
|
||||||
// It's an old-fashioned unsigned repo...
|
// It's an old-fashioned unsigned repo...
|
||||||
Log.d("FDroid", "Getting unsigned index from " + repo.address);
|
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",
|
code = getRemoteFile(ctx, repo.address + "/index.xml",
|
||||||
"tempindex.xml", repo.lastetag, newetag);
|
"tempindex.xml", repo.lastetag, newetag,
|
||||||
|
progressListener, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (code == 200) {
|
if (code == 200) {
|
||||||
@ -374,11 +414,22 @@ public class RepoXMLHandler extends DefaultHandler {
|
|||||||
SAXParserFactory spf = SAXParserFactory.newInstance();
|
SAXParserFactory spf = SAXParserFactory.newInstance();
|
||||||
SAXParser sp = spf.newSAXParser();
|
SAXParser sp = spf.newSAXParser();
|
||||||
XMLReader xr = sp.getXMLReader();
|
XMLReader xr = sp.getXMLReader();
|
||||||
RepoXMLHandler handler = new RepoXMLHandler(repo.id, apps);
|
RepoXMLHandler handler = new RepoXMLHandler(repo, apps, progressListener);
|
||||||
xr.setContentHandler(handler);
|
xr.setContentHandler(handler);
|
||||||
|
|
||||||
Reader r = new BufferedReader(new FileReader(new File(
|
File tempIndex = new File(ctx.getFilesDir() + "/tempindex.xml");
|
||||||
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 = "<application";
|
||||||
|
handler.setTotalAppCount(Utils.countSubstringOccurrence(tempIndex, APPLICATION));
|
||||||
|
|
||||||
InputSource is = new InputSource(r);
|
InputSource is = new InputSource(r);
|
||||||
xr.parse(is);
|
xr.parse(is);
|
||||||
|
|
||||||
@ -427,4 +478,7 @@ public class RepoXMLHandler extends DefaultHandler {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setTotalAppCount(int totalAppCount) {
|
||||||
|
this.totalAppCount = totalAppCount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,14 @@ import android.os.SystemClock;
|
|||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
public class UpdateService extends IntentService {
|
public class UpdateService extends IntentService implements ProgressListener {
|
||||||
|
|
||||||
|
public static final String RESULT_MESSAGE = "msg";
|
||||||
|
public static final int STATUS_COMPLETE = 0;
|
||||||
|
public static final int STATUS_ERROR = 1;
|
||||||
|
public static final int STATUS_INFO = 2;
|
||||||
|
|
||||||
|
private ResultReceiver receiver = null;
|
||||||
|
|
||||||
public UpdateService() {
|
public UpdateService() {
|
||||||
super("UpdateService");
|
super("UpdateService");
|
||||||
@ -72,24 +79,41 @@ public class UpdateService extends IntentService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void sendStatus(int statusCode ) {
|
||||||
|
sendStatus(statusCode, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void sendStatus(int statusCode, String message ) {
|
||||||
|
if (receiver != null) {
|
||||||
|
Bundle resultData = new Bundle();
|
||||||
|
if (message != null && message.length() > 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) {
|
protected void onHandleIntent(Intent intent) {
|
||||||
|
|
||||||
// We might be doing a scheduled run, or we might have been launched by
|
receiver = intent.getParcelableExtra("receiver");
|
||||||
// the app in response to a user's request. If we get this receiver,
|
|
||||||
// it's
|
|
||||||
// the latter...
|
|
||||||
ResultReceiver receiver = intent.getParcelableExtra("receiver");
|
|
||||||
|
|
||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
String errmsg = "";
|
String errmsg = "";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
SharedPreferences prefs = PreferenceManager
|
SharedPreferences prefs = PreferenceManager
|
||||||
.getDefaultSharedPreferences(getBaseContext());
|
.getDefaultSharedPreferences(getBaseContext());
|
||||||
|
|
||||||
// See if it's time to actually do anything yet...
|
// See if it's time to actually do anything yet...
|
||||||
if (receiver == null) {
|
if (isScheduledRun()) {
|
||||||
long lastUpdate = prefs.getLong("lastUpdateCheck", 0);
|
long lastUpdate = prefs.getLong("lastUpdateCheck", 0);
|
||||||
String sint = prefs.getString("updateInterval", "0");
|
String sint = prefs.getString("updateInterval", "0");
|
||||||
int interval = Integer.parseInt(sint);
|
int interval = Integer.parseInt(sint);
|
||||||
@ -125,9 +149,12 @@ public class UpdateService extends IntentService {
|
|||||||
boolean success = true;
|
boolean success = true;
|
||||||
for (DB.Repo repo : repos) {
|
for (DB.Repo repo : repos) {
|
||||||
if (repo.inuse) {
|
if (repo.inuse) {
|
||||||
|
|
||||||
|
sendStatus(STATUS_INFO, getString(R.string.status_connecting_to_repo, repo.address));
|
||||||
|
|
||||||
StringBuilder newetag = new StringBuilder();
|
StringBuilder newetag = new StringBuilder();
|
||||||
String err = RepoXMLHandler.doUpdate(getBaseContext(),
|
String err = RepoXMLHandler.doUpdate(getBaseContext(),
|
||||||
repo, apps, newetag, keeprepos);
|
repo, apps, newetag, keeprepos, this);
|
||||||
if (err == null) {
|
if (err == null) {
|
||||||
repo.lastetag = newetag.toString();
|
repo.lastetag = newetag.toString();
|
||||||
} else {
|
} else {
|
||||||
@ -143,9 +170,9 @@ public class UpdateService extends IntentService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
|
sendStatus(STATUS_INFO, getString(R.string.status_checking_compatibility));
|
||||||
List<DB.App> acceptedapps = new ArrayList<DB.App>();
|
List<DB.App> acceptedapps = new ArrayList<DB.App>();
|
||||||
List<DB.App> prevapps = ((FDroidApp) getApplication())
|
List<DB.App> prevapps = ((FDroidApp) getApplication()).getApps();
|
||||||
.getApps();
|
|
||||||
|
|
||||||
DB db = DB.getDB();
|
DB db = DB.getDB();
|
||||||
try {
|
try {
|
||||||
@ -235,17 +262,12 @@ public class UpdateService extends IntentService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (receiver != null) {
|
if (!success) {
|
||||||
Bundle resultData = new Bundle();
|
if (errmsg.length() == 0)
|
||||||
if (!success) {
|
errmsg = "Unknown error";
|
||||||
if (errmsg.length() == 0)
|
sendStatus(STATUS_ERROR, errmsg);
|
||||||
errmsg = "Unknown error";
|
} else {
|
||||||
resultData.putString("errmsg", errmsg);
|
sendStatus(STATUS_COMPLETE);
|
||||||
receiver.send(1, resultData);
|
|
||||||
} else {
|
|
||||||
receiver.send(0, resultData);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(success) {
|
if(success) {
|
||||||
@ -258,19 +280,15 @@ public class UpdateService extends IntentService {
|
|||||||
Log.e("FDroid",
|
Log.e("FDroid",
|
||||||
"Exception during update processing:\n"
|
"Exception during update processing:\n"
|
||||||
+ Log.getStackTraceString(e));
|
+ Log.getStackTraceString(e));
|
||||||
if (receiver != null) {
|
if (errmsg.length() == 0)
|
||||||
Bundle resultData = new Bundle();
|
errmsg = "Unknown error";
|
||||||
if (errmsg.length() == 0)
|
sendStatus(STATUS_ERROR, errmsg);
|
||||||
errmsg = "Unknown error";
|
|
||||||
resultData.putString("errmsg", errmsg);
|
|
||||||
receiver.send(1, resultData);
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
Log.d("FDroid", "Update took "
|
Log.d("FDroid", "Update took "
|
||||||
+ ((System.currentTimeMillis() - startTime) / 1000)
|
+ ((System.currentTimeMillis() - startTime) / 1000)
|
||||||
+ " seconds.");
|
+ " seconds.");
|
||||||
|
receiver = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getIcon(DB.App app, List<DB.Repo> repos) {
|
private void getIcon(DB.App app, List<DB.Repo> repos) {
|
||||||
@ -307,4 +325,25 @@ 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(ProgressListener.Event event) {
|
||||||
|
|
||||||
|
String message = "";
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,19 +26,34 @@ import java.io.IOException;
|
|||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
public final class Utils {
|
public final class Utils {
|
||||||
private Utils() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final int BUFFER_SIZE = 4096;
|
public static final int BUFFER_SIZE = 4096;
|
||||||
|
|
||||||
|
private static final String[] FRIENDLY_SIZE_FORMAT = {
|
||||||
|
"%.0f B", "%.0f KiB", "%.1f MiB", "%.2f GiB" };
|
||||||
|
|
||||||
|
|
||||||
public static void copy(InputStream input, OutputStream output)
|
public static void copy(InputStream input, OutputStream output)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
copy(input, output, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void copy(InputStream input, OutputStream output,
|
||||||
|
ProgressListener progressListener,
|
||||||
|
ProgressListener.Event templateProgressEvent)
|
||||||
|
throws IOException {
|
||||||
byte[] buffer = new byte[BUFFER_SIZE];
|
byte[] buffer = new byte[BUFFER_SIZE];
|
||||||
|
int bytesRead = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
int count = input.read(buffer);
|
int count = input.read(buffer);
|
||||||
if (count == -1) {
|
if (count == -1) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (progressListener != null) {
|
||||||
|
bytesRead += count;
|
||||||
|
templateProgressEvent.progress = bytesRead;
|
||||||
|
progressListener.onProgress(templateProgressEvent);
|
||||||
|
}
|
||||||
output.write(buffer, 0, count);
|
output.write(buffer, 0, count);
|
||||||
}
|
}
|
||||||
output.flush();
|
output.flush();
|
||||||
@ -62,4 +77,52 @@ public final class Utils {
|
|||||||
public static int getApi() {
|
public static int getApi() {
|
||||||
return Build.VERSION.SDK_INT;
|
return Build.VERSION.SDK_INT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user