Details
-
Type: Improvement
-
Status: Closed (View Workflow)
-
Priority: Major
-
Resolution: Fixed
-
Affects Version/s: 1.6
-
Fix Version/s: 1.6.1
-
Component/s: o.c.common.util, o.c.jsword.book.install
-
Labels:None
-
Environment:
Android
Description
Downloads to a mobile are slower and more variable than to a pc and there can be quite a large difference between predicted download time and actual download time. Also, the first download does not have a predicted download time and so the first progress bar And Bible showed to users had no percentage complete (maybe this second problem could have been avoided by pre-loading a guesstimate) .
There is code in JSword to get the download file size (WebResource.getSize()) but the actual download loop does not have access to the Progress object in order to update the percentage so I changed the code to pass the Progress object to the download method. And Bible has been using this for a few weeks now to allow actual download percent to be displayed with no known problems.
There were a few changes in different classes:
AbstractSwordInstaller.run() determines if the download times are predicted. I had to set the last parameter to false to turn predictions off:
//change final parameter to false to prevent guessing progress of file download because now actual file size is used
Progress job = JobManager.createJob(UserMsg.gettext("Installing book:
", sbmd.getName()), predictURI, this, false);
In HttpSwordInstaller.copy(..) pass the Progress object through to WebResource which actually does the download:
private void copy(Progress job, URI uri, URI dest) throws LucidException {
if (job != null)
//MJD START - modified following line - pass job thro to WebResource to allow actual progress indicator
WebResource wr = new WebResource(uri, proxyHost, proxyPort, job);
wr.copy(dest);
}
The above implies a new constructor was also needed and created for WebResource.
The WebResource.copy method is where the percent complete is updated currently in And Bible. It could be argued that this creates inefficiency in a tight loop but the loop isn't that tight because it deals in blocks rather than bytes. Inefficiency of updating Progress too often was the reason I added progressUpdateCounter so the calls do not happen after every block is fetched, but in reality it did not really save much as anything more than every other time leads to a very jumpy progress bar so I think the progressUpdateCounter part of below could be removed so that the progress is updated every time.
95.0% was used below, as in other places to allow 5% for post download operations but I think users expect a delay after download so it could be 100.0%.
My first attempt involved calling getSize() somewhere after GetMethod and it just hung, hence the comment below.
public void copy(URI dest) throws LucidException {
InputStream in = null;
OutputStream out = null;
//MJD START calculate progress as percent of total file size
//must call getSize before opening the connection or it hangs
int size = getSize();
HttpMethod method = new GetMethod(uri.getPath());
try {
// Execute the method.
int status = client.executeMethod(method);
if (status == HttpStatus.SC_OK) {
in = method.getResponseBodyAsStream();
// Download the index file
out = NetUtil.getOutputStream(dest);
int progressUpdateCounter = 0;
long totalRead = 0;
byte[] buf = new byte[4096];
int count = in.read(buf);
while (-1 != count) {
out.write(buf, 0, count);
count = in.read(buf);
totalRead += count;
//update progress occasionally - every other time
if (job!=null && size>0 && progressUpdateCounter++ % 2 == 0)
}
} else {
// rest is unchanged
My only reservation is that getSize() may sometimes not work but I have not found any cases where it failed although And Bible only currently downloads from the CrossWire repository.