diff options
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); + } + } } } |