Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/android/download/download_controller.h" | 5 #include "chrome/browser/android/download/download_controller.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/android/context_utils.h" | 10 #include "base/android/context_utils.h" |
| 11 #include "base/android/jni_android.h" | 11 #include "base/android/jni_android.h" |
| 12 #include "base/android/jni_string.h" | 12 #include "base/android/jni_string.h" |
| 13 #include "base/bind.h" | 13 #include "base/bind.h" |
| 14 #include "base/lazy_instance.h" | 14 #include "base/lazy_instance.h" |
| 15 #include "base/logging.h" | 15 #include "base/logging.h" |
| 16 #include "base/metrics/histogram_macros.h" | 16 #include "base/metrics/histogram_macros.h" |
| 17 #include "base/synchronization/lock.h" | 17 #include "base/synchronization/lock.h" |
| 18 #include "chrome/browser/android/download/chrome_download_delegate.h" | 18 #include "chrome/browser/android/download/chrome_download_delegate.h" |
| 19 #include "chrome/browser/android/download/dangerous_download_infobar_delegate.h" | 19 #include "chrome/browser/android/download/dangerous_download_infobar_delegate.h" |
| 20 #include "chrome/browser/android/download/download_manager_service.h" | 20 #include "chrome/browser/android/download/download_manager_service.h" |
| 21 #include "chrome/browser/infobars/infobar_service.h" | 21 #include "chrome/browser/infobars/infobar_service.h" |
| 22 #include "chrome/browser/permissions/permission_update_infobar_delegate_android. h" | |
| 22 #include "chrome/browser/ui/android/view_android_helper.h" | 23 #include "chrome/browser/ui/android/view_android_helper.h" |
| 24 #include "chrome/grit/chromium_strings.h" | |
| 23 #include "content/public/browser/browser_context.h" | 25 #include "content/public/browser/browser_context.h" |
| 24 #include "content/public/browser/browser_thread.h" | 26 #include "content/public/browser/browser_thread.h" |
| 25 #include "content/public/browser/download_manager.h" | 27 #include "content/public/browser/download_manager.h" |
| 26 #include "content/public/browser/download_url_parameters.h" | 28 #include "content/public/browser/download_url_parameters.h" |
| 27 #include "content/public/browser/render_process_host.h" | 29 #include "content/public/browser/render_process_host.h" |
| 28 #include "content/public/browser/render_view_host.h" | 30 #include "content/public/browser/render_view_host.h" |
| 29 #include "content/public/common/referrer.h" | 31 #include "content/public/common/referrer.h" |
| 30 #include "jni/DownloadController_jni.h" | 32 #include "jni/DownloadController_jni.h" |
| 31 #include "net/base/filename_util.h" | 33 #include "net/base/filename_util.h" |
| 32 #include "ui/android/view_android.h" | 34 #include "ui/android/view_android.h" |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 50 WebContents* GetWebContents(int render_process_id, int render_view_id) { | 52 WebContents* GetWebContents(int render_process_id, int render_view_id) { |
| 51 content::RenderViewHost* render_view_host = | 53 content::RenderViewHost* render_view_host = |
| 52 content::RenderViewHost::FromID(render_process_id, render_view_id); | 54 content::RenderViewHost::FromID(render_process_id, render_view_id); |
| 53 | 55 |
| 54 if (!render_view_host) | 56 if (!render_view_host) |
| 55 return nullptr; | 57 return nullptr; |
| 56 | 58 |
| 57 return WebContents::FromRenderViewHost(render_view_host); | 59 return WebContents::FromRenderViewHost(render_view_host); |
| 58 } | 60 } |
| 59 | 61 |
| 60 void CreateContextMenuDownload(int render_process_id, | 62 void CreateContextMenuDownload( |
| 61 int render_view_id, | 63 const content::ResourceRequestInfo::WebContentsGetter& wc_getter, |
| 62 const content::ContextMenuParams& params, | 64 const content::ContextMenuParams& params, |
| 63 bool is_link, | 65 bool is_link, |
| 64 const std::string& extra_headers, | 66 const std::string& extra_headers, |
| 65 bool granted) { | 67 bool granted) { |
| 66 if (!granted) | 68 content::WebContents* web_contents = wc_getter.Run(); |
| 67 return; | |
| 68 | 69 |
| 69 content::WebContents* web_contents = | |
| 70 GetWebContents(render_process_id, render_view_id); | |
| 71 if (!web_contents) | 70 if (!web_contents) |
| 72 return; | 71 return; |
| 73 | 72 |
| 74 const GURL& url = is_link ? params.link_url : params.src_url; | 73 const GURL& url = is_link ? params.link_url : params.src_url; |
| 75 const GURL& referring_url = | 74 const GURL& referring_url = |
| 76 params.frame_url.is_empty() ? params.page_url : params.frame_url; | 75 params.frame_url.is_empty() ? params.page_url : params.frame_url; |
| 77 content::DownloadManager* dlm = | 76 content::DownloadManager* dlm = |
| 78 content::BrowserContext::GetDownloadManager( | 77 content::BrowserContext::GetDownloadManager( |
| 79 web_contents->GetBrowserContext()); | 78 web_contents->GetBrowserContext()); |
| 80 std::unique_ptr<content::DownloadUrlParameters> dl_params( | 79 std::unique_ptr<content::DownloadUrlParameters> dl_params( |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 107 content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED; | 106 content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED; |
| 108 } | 107 } |
| 109 | 108 |
| 110 } // namespace | 109 } // namespace |
| 111 | 110 |
| 112 // JNI methods | 111 // JNI methods |
| 113 static void Init(JNIEnv* env, const JavaParamRef<jobject>& obj) { | 112 static void Init(JNIEnv* env, const JavaParamRef<jobject>& obj) { |
| 114 DownloadController::GetInstance()->Init(env, obj); | 113 DownloadController::GetInstance()->Init(env, obj); |
| 115 } | 114 } |
| 116 | 115 |
| 117 static void OnRequestFileAccessResult(JNIEnv* env, | 116 static void OnAcquirePermissionResult( |
| 118 const JavaParamRef<jobject>& obj, | 117 JNIEnv* env, |
| 119 jlong callback_id, | 118 const JavaParamRef<jobject>& obj, |
| 120 jboolean granted) { | 119 jlong callback_id, |
| 120 jboolean granted, | |
| 121 const JavaParamRef<jstring>& jpermission_to_update) { | |
| 121 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 122 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 122 DCHECK(callback_id); | 123 DCHECK(callback_id); |
| 123 | 124 |
| 125 std::string permission_to_update = | |
| 126 base::android::ConvertJavaStringToUTF8(env, jpermission_to_update); | |
| 124 // Convert java long long int to c++ pointer, take ownership. | 127 // Convert java long long int to c++ pointer, take ownership. |
| 125 std::unique_ptr< | 128 std::unique_ptr<DownloadController::AcquirePermissionCallback> cb( |
| 126 DownloadControllerBase::AcquireFileAccessPermissionCallback> | 129 reinterpret_cast<DownloadController::AcquirePermissionCallback*>( |
| 127 cb(reinterpret_cast< | 130 callback_id)); |
| 128 DownloadControllerBase::AcquireFileAccessPermissionCallback*>( | 131 cb->Run(granted, permission_to_update); |
| 129 callback_id)); | 132 } |
| 133 | |
| 134 static void OnRequestFileAccessResult( | |
| 135 const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter, | |
| 136 const DownloadControllerBase::AcquireFileAccessPermissionCallback& cb, | |
| 137 bool granted, | |
| 138 const std::string& permission_to_update) { | |
| 139 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 140 | |
| 141 if (!granted && !permission_to_update.empty() && web_contents_getter.Run()) { | |
|
David Trainor- moved to gerrit
2017/05/03 20:43:47
Will this show a dialog and then, if the user says
qinmin
2017/05/04 17:36:16
If we show the dialog, there will be no infobar.
S
| |
| 142 WebContents* web_contents = web_contents_getter.Run(); | |
| 143 std::vector<std::string> permissions; | |
| 144 permissions.push_back(permission_to_update); | |
| 145 | |
| 146 PermissionUpdateInfoBarDelegate::Create( | |
| 147 web_contents, permissions, | |
| 148 IDS_MISSING_STORAGE_PERMISSION_DOWNLOAD_EDUCATION_TEXT, cb); | |
| 149 return; | |
| 150 } | |
| 151 | |
| 130 if (!granted) { | 152 if (!granted) { |
| 131 DownloadController::RecordDownloadCancelReason( | 153 DownloadController::RecordDownloadCancelReason( |
| 132 DownloadController::CANCEL_REASON_NO_STORAGE_PERMISSION); | 154 DownloadController::CANCEL_REASON_NO_STORAGE_PERMISSION); |
| 133 } | 155 } |
| 134 cb->Run(granted); | 156 cb.Run(granted); |
| 135 } | 157 } |
| 136 | 158 |
| 137 struct DownloadController::JavaObject { | 159 struct DownloadController::JavaObject { |
| 138 ScopedJavaLocalRef<jobject> Controller(JNIEnv* env) { | 160 ScopedJavaLocalRef<jobject> Controller(JNIEnv* env) { |
| 139 return GetRealObject(env, obj_); | 161 return GetRealObject(env, obj_); |
| 140 } | 162 } |
| 141 jweak obj_; | 163 jweak obj_; |
| 142 }; | 164 }; |
| 143 | 165 |
| 144 // static | 166 // static |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 186 } | 208 } |
| 187 } | 209 } |
| 188 | 210 |
| 189 // Initialize references to Java object. | 211 // Initialize references to Java object. |
| 190 void DownloadController::Init(JNIEnv* env, jobject obj) { | 212 void DownloadController::Init(JNIEnv* env, jobject obj) { |
| 191 java_object_ = new JavaObject; | 213 java_object_ = new JavaObject; |
| 192 java_object_->obj_ = env->NewWeakGlobalRef(obj); | 214 java_object_->obj_ = env->NewWeakGlobalRef(obj); |
| 193 } | 215 } |
| 194 | 216 |
| 195 void DownloadController::AcquireFileAccessPermission( | 217 void DownloadController::AcquireFileAccessPermission( |
| 196 WebContents* web_contents, | 218 const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter, |
| 197 const DownloadControllerBase::AcquireFileAccessPermissionCallback& cb) { | 219 const DownloadControllerBase::AcquireFileAccessPermissionCallback& cb) { |
| 198 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 220 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 199 DCHECK(web_contents); | |
| 200 | 221 |
| 201 ViewAndroidHelper* view_helper = | 222 if (HasFileAccessPermission()) { |
| 202 ViewAndroidHelper::FromWebContents(web_contents); | |
| 203 if (!view_helper) | |
| 204 return; | |
| 205 | |
| 206 ui::ViewAndroid* view_android = view_helper->GetViewAndroid(); | |
| 207 if (!view_android) { | |
| 208 // ViewAndroid may have been gone away. | |
| 209 BrowserThread::PostTask( | |
| 210 BrowserThread::UI, FROM_HERE, base::Bind(cb, false)); | |
| 211 return; | |
| 212 } | |
| 213 ui::WindowAndroid* window_android = view_android->GetWindowAndroid(); | |
| 214 if (window_android && HasFileAccessPermission(window_android)) { | |
| 215 BrowserThread::PostTask( | 223 BrowserThread::PostTask( |
| 216 BrowserThread::UI, FROM_HERE, base::Bind(cb, true)); | 224 BrowserThread::UI, FROM_HERE, base::Bind(cb, true)); |
| 217 return; | 225 return; |
| 218 } | 226 } |
| 227 | |
| 228 AcquirePermissionCallback callback( | |
| 229 base::Bind(&OnRequestFileAccessResult, web_contents_getter, cb)); | |
| 219 // Make copy on the heap so we can pass the pointer through JNI. | 230 // Make copy on the heap so we can pass the pointer through JNI. |
| 220 intptr_t callback_id = reinterpret_cast<intptr_t>( | 231 intptr_t callback_id = |
| 221 new DownloadControllerBase::AcquireFileAccessPermissionCallback(cb)); | 232 reinterpret_cast<intptr_t>(new AcquirePermissionCallback(callback)); |
| 222 ChromeDownloadDelegate::FromWebContents(web_contents)-> | 233 JNIEnv* env = base::android::AttachCurrentThread(); |
| 223 RequestFileAccess(callback_id); | 234 Java_DownloadController_requestFileAccess( |
| 235 env, GetJavaObject()->Controller(env), callback_id); | |
| 224 } | 236 } |
| 225 | 237 |
| 226 void DownloadController::CreateAndroidDownload( | 238 void DownloadController::CreateAndroidDownload( |
| 227 const content::ResourceRequestInfo::WebContentsGetter& wc_getter, | 239 const content::ResourceRequestInfo::WebContentsGetter& wc_getter, |
| 228 const DownloadInfo& info) { | 240 const DownloadInfo& info) { |
| 229 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 241 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 230 | 242 |
| 231 BrowserThread::PostTask( | 243 BrowserThread::PostTask( |
| 232 BrowserThread::UI, FROM_HERE, | 244 BrowserThread::UI, FROM_HERE, |
| 233 base::Bind(&DownloadController::StartAndroidDownload, | 245 base::Bind(&DownloadController::StartAndroidDownload, |
| 234 base::Unretained(this), | 246 base::Unretained(this), |
| 235 wc_getter, info)); | 247 wc_getter, info)); |
| 236 } | 248 } |
| 237 | 249 |
| 238 void DownloadController::StartAndroidDownload( | 250 void DownloadController::StartAndroidDownload( |
| 239 const content::ResourceRequestInfo::WebContentsGetter& wc_getter, | 251 const content::ResourceRequestInfo::WebContentsGetter& wc_getter, |
| 240 const DownloadInfo& info) { | 252 const DownloadInfo& info) { |
| 241 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 253 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 242 | 254 |
| 243 WebContents* web_contents = wc_getter.Run(); | |
| 244 if (!web_contents) { | |
| 245 // The view went away. Can't proceed. | |
| 246 LOG(ERROR) << "Tab closed, download failed on URL:" << info.url.spec(); | |
| 247 return; | |
| 248 } | |
| 249 | |
| 250 AcquireFileAccessPermission( | 255 AcquireFileAccessPermission( |
| 251 web_contents, | 256 wc_getter, base::Bind(&DownloadController::StartAndroidDownloadInternal, |
| 252 base::Bind(&DownloadController::StartAndroidDownloadInternal, | 257 base::Unretained(this), wc_getter, info)); |
| 253 base::Unretained(this), wc_getter, info)); | |
| 254 } | 258 } |
| 255 | 259 |
| 256 void DownloadController::StartAndroidDownloadInternal( | 260 void DownloadController::StartAndroidDownloadInternal( |
| 257 const content::ResourceRequestInfo::WebContentsGetter& wc_getter, | 261 const content::ResourceRequestInfo::WebContentsGetter& wc_getter, |
| 258 const DownloadInfo& info, bool allowed) { | 262 const DownloadInfo& info, bool allowed) { |
| 259 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 263 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 260 if (!allowed) | 264 if (!allowed) |
| 261 return; | 265 return; |
| 262 | 266 |
| 263 WebContents* web_contents = wc_getter.Run(); | 267 WebContents* web_contents = wc_getter.Run(); |
| 264 if (!web_contents) { | 268 if (!web_contents) { |
| 265 // The view went away. Can't proceed. | 269 // The view went away. Can't proceed. |
| 266 LOG(ERROR) << "Tab closed, download failed on URL:" << info.url.spec(); | 270 LOG(ERROR) << "Tab closed, download failed on URL:" << info.url.spec(); |
| 267 return; | 271 return; |
| 268 } | 272 } |
| 269 | 273 |
| 270 base::string16 filename = | 274 base::string16 filename = |
| 271 net::GetSuggestedFilename(info.url, info.content_disposition, | 275 net::GetSuggestedFilename(info.url, info.content_disposition, |
| 272 std::string(), // referrer_charset | 276 std::string(), // referrer_charset |
| 273 std::string(), // suggested_name | 277 std::string(), // suggested_name |
| 274 info.original_mime_type, default_file_name_); | 278 info.original_mime_type, default_file_name_); |
| 275 ChromeDownloadDelegate::FromWebContents(web_contents) | 279 ChromeDownloadDelegate::FromWebContents(web_contents) |
| 276 ->EnqueueDownloadManagerRequest(info.url.spec(), info.user_agent, | 280 ->EnqueueDownloadManagerRequest(info.url.spec(), info.user_agent, |
| 277 filename, info.original_mime_type, | 281 filename, info.original_mime_type, |
| 278 info.cookie, info.referer); | 282 info.cookie, info.referer); |
| 279 } | 283 } |
| 280 | 284 |
| 281 bool DownloadController::HasFileAccessPermission( | 285 bool DownloadController::HasFileAccessPermission() { |
| 282 ui::WindowAndroid* window_android) { | |
| 283 ScopedJavaLocalRef<jobject> jwindow_android = window_android->GetJavaObject(); | |
| 284 | |
| 285 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 286 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 286 DCHECK(!jwindow_android.is_null()); | |
| 287 | 287 |
| 288 JNIEnv* env = base::android::AttachCurrentThread(); | 288 JNIEnv* env = base::android::AttachCurrentThread(); |
| 289 return Java_DownloadController_hasFileAccess( | 289 return Java_DownloadController_hasFileAccess( |
| 290 env, GetJavaObject()->Controller(env), jwindow_android); | 290 env, GetJavaObject()->Controller(env)); |
| 291 } | 291 } |
| 292 | 292 |
| 293 void DownloadController::OnDownloadStarted( | 293 void DownloadController::OnDownloadStarted( |
| 294 DownloadItem* download_item) { | 294 DownloadItem* download_item) { |
| 295 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 295 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 296 WebContents* web_contents = download_item->GetWebContents(); | 296 WebContents* web_contents = download_item->GetWebContents(); |
| 297 if (!web_contents) | 297 if (!web_contents) |
| 298 return; | 298 return; |
| 299 | 299 |
| 300 // Register for updates to the DownloadItem. | 300 // Register for updates to the DownloadItem. |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 383 | 383 |
| 384 DCHECK(java_object_); | 384 DCHECK(java_object_); |
| 385 return java_object_; | 385 return java_object_; |
| 386 } | 386 } |
| 387 | 387 |
| 388 void DownloadController::StartContextMenuDownload( | 388 void DownloadController::StartContextMenuDownload( |
| 389 const ContextMenuParams& params, WebContents* web_contents, bool is_link, | 389 const ContextMenuParams& params, WebContents* web_contents, bool is_link, |
| 390 const std::string& extra_headers) { | 390 const std::string& extra_headers) { |
| 391 int process_id = web_contents->GetRenderProcessHost()->GetID(); | 391 int process_id = web_contents->GetRenderProcessHost()->GetID(); |
| 392 int routing_id = web_contents->GetRenderViewHost()->GetRoutingID(); | 392 int routing_id = web_contents->GetRenderViewHost()->GetRoutingID(); |
| 393 | |
| 394 const content::ResourceRequestInfo::WebContentsGetter& wc_getter( | |
| 395 base::Bind(&GetWebContents, process_id, routing_id)); | |
| 396 | |
| 393 AcquireFileAccessPermission( | 397 AcquireFileAccessPermission( |
| 394 web_contents, base::Bind(&CreateContextMenuDownload, process_id, | 398 wc_getter, base::Bind(&CreateContextMenuDownload, wc_getter, params, |
| 395 routing_id, params, is_link, extra_headers)); | 399 is_link, extra_headers)); |
| 396 } | 400 } |
| 397 | 401 |
| OLD | NEW |