Chromium Code Reviews| Index: content/browser/android/download_controller.cc |
| diff --git a/content/browser/android/download_controller.cc b/content/browser/android/download_controller.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..bd3883ca4d9839799e5287e934348609103dfbbf |
| --- /dev/null |
| +++ b/content/browser/android/download_controller.cc |
| @@ -0,0 +1,272 @@ |
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "content/browser/android/download_controller.h" |
| + |
| +#include "base/android/jni_android.h" |
| +#include "base/android/jni_string.h" |
| +#include "base/bind.h" |
| +#include "base/logging.h" |
| +#include "base/memory/scoped_ptr.h" |
| +#include "content/browser/renderer_host/render_view_host_delegate.h" |
| +#include "content/browser/renderer_host/resource_dispatcher_host_impl.h" |
| +#include "content/public/browser/browser_thread.h" |
| +#include "content/public/browser/download_item.h" |
| +#include "content/public/browser/global_request_id.h" |
| +#include "content/public/browser/render_process_host.h" |
| +#include "content/public/browser/render_view_host.h" |
| +#include "content/public/browser/web_contents.h" |
| +#include "jni/download_controller_jni.h" |
| +#include "net/cookies/cookie_options.h" |
| +#include "net/cookies/cookie_store.h" |
| +#include "net/http/http_request_headers.h" |
| +#include "net/url_request/url_request.h" |
| +#include "net/url_request/url_request_context.h" |
| + |
| +using base::android::AttachCurrentThread; |
| +using base::android::CheckException; |
| +using base::android::ConvertUTF8ToJavaString; |
| +using base::android::GetClass; |
| +using base::android::ScopedJavaLocalRef; |
| +using content::BrowserThread; |
| +using content::DownloadItem; |
| +using content::RenderViewHost; |
| +using content::WebContents; |
| + |
| +// JNI methods |
| +static void Init(JNIEnv* env, jobject obj) { |
|
jochen (gone - plz use gerrit)
2012/05/26 10:12:44
if it's invoked within this compilation unit, you
nilesh
2012/05/29 18:21:22
The method is declared in jni/download_controller_
|
| + content::DownloadController::GetInstance()->Init(env, obj); |
| +} |
| + |
| +namespace { |
| +const char* kDownloadControllerClassPathName = |
| + "org/chromium/content/browser/DownloadController"; |
| +} // namespace |
| + |
| +namespace content { |
| + |
| +struct DownloadController::JavaObject { |
| + ScopedJavaLocalRef<jobject> Controller(JNIEnv* env) { |
| + return GetRealObject(env, obj); |
| + } |
| + jweak obj; |
| +}; |
| + |
| +// static |
| +bool DownloadController::RegisterDownloadController(JNIEnv* env) { |
| + return RegisterNativesImpl(env); |
| +} |
| + |
| +DownloadController* DownloadController::GetInstance() { |
| + return Singleton<DownloadController>::get(); |
| +} |
| + |
| +DownloadController::DownloadController() |
| + : java_object_(NULL) { |
| +} |
| + |
| +DownloadController::~DownloadController() { |
| + if (java_object_) { |
| + JNIEnv* env = AttachCurrentThread(); |
| + env->DeleteWeakGlobalRef(java_object_->obj); |
| + delete java_object_; |
| + CheckException(env); |
| + } |
| +} |
| + |
| +// Initialize references to Java object. |
| +void DownloadController::Init(JNIEnv* env, jobject obj) { |
| + java_object_ = new JavaObject; |
| + java_object_->obj = env->NewWeakGlobalRef(obj); |
| +} |
| + |
| +void DownloadController::NewGetDownload( |
| + content::RenderViewHost* render_view_host, |
| + int request_id) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + int render_process_id = render_view_host->GetProcess()->GetID(); |
| + content::GlobalRequestID global_id(render_process_id, request_id); |
| + |
| + // We are yielding the UI thread and render_view_host may go away by |
| + // the time we come back. Pass along render_process_id and render_view_id |
| + // to retrieve it later (if it still exists). |
| + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| + base::Bind(&DownloadController::PrepareDownloadInfo, |
| + base::Unretained(this), global_id, |
| + render_process_id, |
| + render_view_host->GetRoutingID())); |
| +} |
| + |
| +void DownloadController::PrepareDownloadInfo( |
| + const content::GlobalRequestID& global_id, |
| + int render_process_id, int render_view_id) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + |
| + net::URLRequest* request = |
| + content::ResourceDispatcherHostImpl::Get()->GetURLRequest(global_id); |
| + DCHECK(request) << "Request to download not found."; |
| + |
| + DownloadInfoAndroid info_android(request); |
| + net::CookieOptions options; |
| + options.set_include_httponly(); |
| + |
| + request->context()->cookie_store()->GetCookiesWithOptionsAsync( |
|
jochen (gone - plz use gerrit)
2012/05/26 10:12:44
see http://code.google.com/searchframe#OAMlx_jo-ck
nilesh
2012/05/29 18:21:22
Done. Thanks for the pointer.
|
| + info_android.url, options, |
| + base::Bind(&DownloadController::OnCookieResponse, |
| + base::Unretained(this), info_android, render_process_id, |
| + render_view_id)); |
| +} |
| + |
| +void DownloadController::OnCookieResponse(DownloadInfoAndroid download_info, |
| + int render_process_id, |
| + int render_view_id, |
| + const std::string& cookie) { |
| + download_info.cookie = cookie; |
| + |
| + // We have everything we need, start Android download on the UI thread. |
| + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| + base::Bind(&DownloadController::StartAndroidDownload, |
| + base::Unretained(this), download_info, render_process_id, |
| + render_view_id)); |
| +} |
| + |
| +void DownloadController::StartAndroidDownload( |
| + const DownloadInfoAndroid& info, |
| + int render_process_id, |
| + int render_view_id) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + JNIEnv* env = AttachCurrentThread(); |
| + |
| + // Call newHttpGetDownload |
| + jobject view = GetContentView(render_process_id, render_view_id); |
| + if (!view) { |
| + // The view went away. Can't proceed. |
| + LOG(ERROR) << "Download failed on URL:" << info.url.spec(); |
| + return; |
| + } |
| + |
| + ScopedJavaLocalRef<jstring> jurl = |
| + ConvertUTF8ToJavaString(env, info.url.spec()); |
| + ScopedJavaLocalRef<jstring> juser_agent = |
| + ConvertUTF8ToJavaString(env, info.user_agent); |
| + ScopedJavaLocalRef<jstring> jcontent_disposition = |
| + ConvertUTF8ToJavaString(env, info.content_disposition); |
| + ScopedJavaLocalRef<jstring> jmime_type = |
| + ConvertUTF8ToJavaString(env, info.original_mime_type); |
| + ScopedJavaLocalRef<jstring> jcookie = |
| + ConvertUTF8ToJavaString(env, info.cookie); |
| + |
| + Java_DownloadController_newHttpGetDownload( |
| + env, java_object()->Controller(env).obj(), view, jurl.obj(), |
| + juser_agent.obj(), jcontent_disposition.obj(), jmime_type.obj(), |
| + jcookie.obj(), info.total_bytes); |
| +} |
| + |
| +void DownloadController::OnPostDownloadStarted( |
| + WebContents* web_contents, |
| + DownloadItem* download_item) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + JNIEnv* env = AttachCurrentThread(); |
| + |
| + // Register for updates to the DownloadItem. |
| + download_item->AddObserver(this); |
| + |
| + jobject view = GetContentViewFromWebContents(web_contents); |
| + if(!view) { |
| + // The view went away. Can't proceed. |
| + return; |
| + } |
| + |
| + Java_DownloadController_onHttpPostDownloadStarted( |
| + env, java_object()->Controller(env).obj(), view); |
| +} |
| + |
| +void DownloadController::OnDownloadUpdated(DownloadItem* item) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + |
| + if (item->GetState() != DownloadItem::COMPLETE) |
| + return; |
| + |
| + // Call onHttpPostDownloadCompleted |
| + JNIEnv* env = AttachCurrentThread(); |
| + ScopedJavaLocalRef<jstring> jurl = |
| + ConvertUTF8ToJavaString(env, item->GetURL().spec()); |
| + ScopedJavaLocalRef<jstring> jcontent_disposition = |
| + ConvertUTF8ToJavaString(env, item->GetContentDisposition()); |
| + ScopedJavaLocalRef<jstring> jmime_type = |
| + ConvertUTF8ToJavaString(env, item->GetMimeType()); |
| + ScopedJavaLocalRef<jstring> jpath = |
| + ConvertUTF8ToJavaString(env, item->GetFullPath().value()); |
| + |
| + jobject view = GetContentViewFromWebContents(item->GetWebContents()); |
| + if(!view) { |
| + // We can get NULL WebContents from the DownloadItem. |
| + return; |
| + } |
| + |
| + Java_DownloadController_onHttpPostDownloadCompleted(env, |
| + java_object()->Controller(env).obj(), view, jurl.obj(), |
| + jcontent_disposition.obj(), jmime_type.obj(), jpath.obj(), |
| + item->GetReceivedBytes(), true); |
| +} |
| + |
| +void DownloadController::OnDownloadOpened(DownloadItem* item) { |
| +} |
| + |
| +jobject DownloadController::GetContentView(int render_process_id, |
| + int render_view_id) { |
| + RenderViewHost* render_view_host = |
| + RenderViewHost::FromID(render_process_id, render_view_id); |
| + |
| + if (!render_view_host) |
| + return NULL; |
| + |
| + WebContents* web_contents = |
| + render_view_host->GetDelegate()->GetAsWebContents(); |
| + |
| + if (!web_contents) |
| + return NULL; |
| + |
| + return GetContentViewFromWebContents(web_contents); |
| +} |
| + |
| +jobject DownloadController::GetContentViewFromWebContents( |
| + WebContents* web_contents) { |
| + NOTIMPLEMENTED(); |
| + return NULL; |
| +} |
| + |
| +DownloadController::JavaObject* DownloadController::java_object() { |
| + if (!java_object_) { |
| + // Initialize Java DownloadController by calling |
| + // DownloadController.getInstance(), which will call Init() |
| + // if Java DownloadController is not instantiated already. |
| + JNIEnv* env = AttachCurrentThread(); |
| + ScopedJavaLocalRef<jclass> clazz = |
| + GetClass(env, kDownloadControllerClassPathName); |
| + jmethodID get_instance = GetStaticMethodID(env, clazz, "getInstance", |
| + "()Lorg/chromium/content/browser/DownloadController;"); |
| + ScopedJavaLocalRef<jobject> jobj(env, |
| + env->CallStaticObjectMethod(clazz.obj(), get_instance)); |
| + CheckException(env); |
| + } |
| + |
| + DCHECK(java_object_); |
| + return java_object_; |
| +} |
| + |
| +DownloadController::DownloadInfoAndroid::DownloadInfoAndroid( |
| + net::URLRequest* request) { |
| + request->GetResponseHeaderByName("content-disposition", &content_disposition); |
| + request->GetResponseHeaderByName("mime-type", &original_mime_type); |
| + request->extra_request_headers().GetHeader( |
| + net::HttpRequestHeaders::kUserAgent, |
| + &user_agent); |
| + if (!request->url_chain().empty()) { |
| + original_url = request->url_chain().front(); |
| + url = request->url_chain().back(); |
| + } |
| +} |
| + |
| +} // namespace content |