diff options
author | shashishekhar@chromium.org <shashishekhar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-22 01:03:06 +0000 |
---|---|---|
committer | shashishekhar@chromium.org <shashishekhar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-22 01:03:06 +0000 |
commit | d219519e9f9d831d607fcd0cec836c957939313d (patch) | |
tree | de2fd3d0440a1637bb5513643c30ad8182963982 /content | |
parent | 13b0f88e6b3309e69aa38ce5a2c9be3151b0b921 (diff) | |
download | chromium_src-d219519e9f9d831d607fcd0cec836c957939313d.zip chromium_src-d219519e9f9d831d607fcd0cec836c957939313d.tar.gz chromium_src-d219519e9f9d831d607fcd0cec836c957939313d.tar.bz2 |
[Android] Expose download progress updates to Java.
Android currently does not show any progress indication for Downloads
that use the Chrome network stack. Expose this information to the
Java DownloadNotificationService interface.
Download progress notification needs percent complete and time remaining
to display the progress.
BUG=314164
Review URL: https://codereview.chromium.org/78603004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@236653 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
4 files changed, 127 insertions, 24 deletions
diff --git a/content/browser/android/download_controller_android_impl.cc b/content/browser/android/download_controller_android_impl.cc index 7d27e64..f3a274a 100644 --- a/content/browser/android/download_controller_android_impl.cc +++ b/content/browser/android/download_controller_android_impl.cc @@ -9,6 +9,7 @@ #include "base/bind.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" +#include "base/time/time.h" #include "content/browser/android/content_view_core_impl.h" #include "content/browser/download/download_item_impl.h" #include "content/browser/download/download_manager_impl.h" @@ -254,18 +255,9 @@ void DownloadControllerAndroidImpl::OnDownloadStarted( void DownloadControllerAndroidImpl::OnDownloadUpdated(DownloadItem* item) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (item->IsDangerous() && - (item->GetState() != DownloadItem::CANCELLED)) + if (item->IsDangerous() && (item->GetState() != DownloadItem::CANCELLED)) OnDangerousDownload(item); - if (item->GetState() != DownloadItem::COMPLETE) - return; - - // Multiple OnDownloadUpdated() notifications may be issued while the download - // is in the COMPLETE state. Only handle one. - item->RemoveObserver(this); - - // Call onDownloadCompleted JNIEnv* env = base::android::AttachCurrentThread(); ScopedJavaLocalRef<jstring> jurl = ConvertUTF8ToJavaString(env, item->GetURL().spec()); @@ -276,10 +268,44 @@ void DownloadControllerAndroidImpl::OnDownloadUpdated(DownloadItem* item) { ScopedJavaLocalRef<jstring> jfilename = ConvertUTF8ToJavaString( env, item->GetTargetFilePath().BaseName().value()); - Java_DownloadController_onDownloadCompleted( - env, GetJavaObject()->Controller(env).obj(), - base::android::GetApplicationContext(), jurl.obj(), jmime_type.obj(), - jfilename.obj(), jpath.obj(), item->GetReceivedBytes(), true); + switch (item->GetState()) { + case DownloadItem::IN_PROGRESS: { + base::TimeDelta time_delta; + item->TimeRemaining(&time_delta); + Java_DownloadController_onDownloadUpdated( + env, GetJavaObject()->Controller(env).obj(), + base::android::GetApplicationContext(), jurl.obj(), jmime_type.obj(), + jfilename.obj(), jpath.obj(), item->GetReceivedBytes(), true, + item->GetId(), item->PercentComplete(), time_delta.InMilliseconds()); + break; + } + case DownloadItem::COMPLETE: + // Multiple OnDownloadUpdated() notifications may be issued while the + // download is in the COMPLETE state. Only handle one. + item->RemoveObserver(this); + + // Call onDownloadCompleted + Java_DownloadController_onDownloadCompleted( + env, GetJavaObject()->Controller(env).obj(), + base::android::GetApplicationContext(), jurl.obj(), jmime_type.obj(), + jfilename.obj(), jpath.obj(), item->GetReceivedBytes(), true, + item->GetId()); + break; + case DownloadItem::CANCELLED: + // TODO(shashishekhar): An interrupted download can be resumed. Android + // currently does not support resumable downloads. Add handling for + // interrupted case based on item->CanResume(). + case DownloadItem::INTERRUPTED: + // Call onDownloadCompleted with success = false. + Java_DownloadController_onDownloadCompleted( + env, GetJavaObject()->Controller(env).obj(), + base::android::GetApplicationContext(), jurl.obj(), jmime_type.obj(), + jfilename.obj(), jpath.obj(), item->GetReceivedBytes(), false, + item->GetId()); + break; + case DownloadItem::MAX_DOWNLOAD_STATE: + NOTREACHED(); + } } void DownloadControllerAndroidImpl::OnDangerousDownload(DownloadItem* item) { diff --git a/content/public/android/java/src/org/chromium/content/browser/DownloadController.java b/content/public/android/java/src/org/chromium/content/browser/DownloadController.java index 0efcfeb..5f7ffeb 100644 --- a/content/public/android/java/src/org/chromium/content/browser/DownloadController.java +++ b/content/public/android/java/src/org/chromium/content/browser/DownloadController.java @@ -25,10 +25,15 @@ public class DownloadController { public interface DownloadNotificationService { /** * Notify the host application that a download is finished. - * @param context Application context. * @param downloadInfo Information about the completed download. */ - void onDownloadCompleted(Context context, DownloadInfo downloadInfo); + void onDownloadCompleted(final DownloadInfo downloadInfo); + + /** + * Notify the host application that a download is in progress. + * @param downloadInfo Information about the in-progress download. + */ + void onDownloadUpdated(final DownloadInfo downloadInfo); } private static DownloadNotificationService sDownloadNotificationService; @@ -89,10 +94,10 @@ public class DownloadController { */ @CalledByNative public void onDownloadStarted(ContentViewCore view, String filename, String mimeType) { - ContentViewDownloadDelegate downloadDelagate = downloadDelegateFromView(view); + ContentViewDownloadDelegate downloadDelegate = downloadDelegateFromView(view); - if (downloadDelagate != null) { - downloadDelagate.onDownloadStarted(filename, mimeType); + if (downloadDelegate != null) { + downloadDelegate.onDownloadStarted(filename, mimeType); } } @@ -102,7 +107,7 @@ public class DownloadController { */ @CalledByNative public void onDownloadCompleted(Context context, String url, String mimeType, - String filename, String path, long contentLength, boolean successful) { + String filename, String path, long contentLength, boolean successful, int downloadId) { if (sDownloadNotificationService != null) { DownloadInfo downloadInfo = new DownloadInfo.Builder() .setUrl(url) @@ -112,8 +117,36 @@ public class DownloadController { .setContentLength(contentLength) .setIsSuccessful(successful) .setDescription(filename) + .setDownloadId(downloadId) + .setHasDownloadId(true) .build(); - sDownloadNotificationService.onDownloadCompleted(context, downloadInfo); + sDownloadNotificationService.onDownloadCompleted(downloadInfo); + } + } + + /** + * Notifies the download delegate about progress of a download. Downloads that use Chrome + * network stack use custom notification to display the progress of downloads. + */ + @CalledByNative + public void onDownloadUpdated(Context context, String url, String mimeType, + String filename, String path, long contentLength, boolean successful, int downloadId, + int percentCompleted, long timeRemainingInMs) { + if(sDownloadNotificationService != null) { + DownloadInfo downloadInfo = new DownloadInfo.Builder() + .setUrl(url) + .setMimeType(mimeType) + .setFileName(filename) + .setFilePath(path) + .setContentLength(contentLength) + .setIsSuccessful(successful) + .setDescription(filename) + .setDownloadId(downloadId) + .setHasDownloadId(true) + .setPercentCompleted(percentCompleted) + .setTimeRemainingInMillis(timeRemainingInMs) + .build(); + sDownloadNotificationService.onDownloadUpdated(downloadInfo); } } diff --git a/content/public/android/java/src/org/chromium/content/browser/DownloadInfo.java b/content/public/android/java/src/org/chromium/content/browser/DownloadInfo.java index cd18724..cae4fff 100644 --- a/content/public/android/java/src/org/chromium/content/browser/DownloadInfo.java +++ b/content/public/android/java/src/org/chromium/content/browser/DownloadInfo.java @@ -22,6 +22,8 @@ public final class DownloadInfo { private final String mContentDisposition; private final boolean mIsGETRequest; private final boolean mIsSuccessful; + private final int mPercentCompleted; + private final long mTimeRemainingInMillis; private DownloadInfo(Builder builder) { mUrl = builder.mUrl; @@ -38,6 +40,8 @@ public final class DownloadInfo { mIsSuccessful = builder.mIsSuccessful; mIsGETRequest = builder.mIsGETRequest; mContentDisposition = builder.mContentDisposition; + mPercentCompleted = builder.mPercentCompleted; + mTimeRemainingInMillis = builder.mTimeRemainingInMillis; } public String getUrl() { @@ -96,6 +100,17 @@ public final class DownloadInfo { return mContentDisposition; } + /** + * @return percent completed as an integer, -1 if there is no download progress. + */ + public int getPercentCompleted() { + return mPercentCompleted; + } + + public long getTimeRemainingInMillis() { + return mTimeRemainingInMillis; + } + public static class Builder { private String mUrl; private String mUserAgent; @@ -111,6 +126,8 @@ public final class DownloadInfo { private int mDownloadId; private boolean mIsSuccessful; private String mContentDisposition; + private int mPercentCompleted = -1; + private long mTimeRemainingInMillis; public Builder setUrl(String url) { mUrl = url; @@ -182,6 +199,17 @@ public final class DownloadInfo { return this; } + public Builder setPercentCompleted(int percentCompleted) { + assert percentCompleted <= 100; + mPercentCompleted = percentCompleted; + return this; + } + + public Builder setTimeRemainingInMillis(long timeRemainingInMillis) { + mTimeRemainingInMillis = timeRemainingInMillis; + return this; + } + public DownloadInfo build() { return new DownloadInfo(this); } @@ -207,7 +235,9 @@ public final class DownloadInfo { .setDownloadId(downloadInfo.getDownloadId()) .setContentDisposition(downloadInfo.getContentDisposition()) .setIsGETRequest(downloadInfo.isGETRequest()) - .setIsSuccessful(downloadInfo.isSuccessful()); + .setIsSuccessful(downloadInfo.isSuccessful()) + .setPercentCompleted(downloadInfo.getPercentCompleted()) + .setTimeRemainingInMillis(downloadInfo.getTimeRemainingInMillis()); return builder; } diff --git a/content/public/android/javatests/src/org/chromium/content/browser/DownloadInfoTest.java b/content/public/android/javatests/src/org/chromium/content/browser/DownloadInfoTest.java index b3eb186..a76a1f3 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/DownloadInfoTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/DownloadInfoTest.java @@ -172,7 +172,7 @@ public class DownloadInfoTest extends InstrumentationTestCase { valuesForBuilder.put(signature, Boolean.TRUE); } else { // This is a primitive type that is not boolean, probably an integer. - valuesForBuilder.put(signature, Integer.valueOf(random.nextInt())); + valuesForBuilder.put(signature, Integer.valueOf(random.nextInt(100))); } } @@ -184,7 +184,7 @@ public class DownloadInfoTest extends InstrumentationTestCase { invokeMethod(setter, builder, valuesForBuilder.get(signature)); } catch (Exception e) { fail("Exception while setting value in the setter. Signature: " + signature - + " value:" + valuesForBuilder.get(signature)); + + " value:" + valuesForBuilder.get(signature) + ":" + e); } } DownloadInfo downloadInfo = builder.build(); @@ -199,5 +199,19 @@ public class DownloadInfoTest extends InstrumentationTestCase { + " value:" + valuesForBuilder.get(signature)); } } + + // Test DownloadInfo.fromDownloadInfo copies all fields. + DownloadInfo newDownloadInfo = Builder.fromDownloadInfo(downloadInfo).build(); + for (AccessorSignature signature : downloadInfoGetters.keySet()) { + Method getter = downloadInfoGetters.get(signature); + try { + Object returnValue1 = invokeMethod(getter, downloadInfo); + Object returnValue2 = invokeMethod(getter, newDownloadInfo); + assertEquals(signature.toString(), returnValue1, returnValue2); + } catch (Exception e) { + fail("Exception while getting value from getter. Signature: " + signature + + " value:" + valuesForBuilder.get(signature) + ":" + e); + } + } } } |