Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(312)

Side by Side Diff: chrome/browser/android/download/download_controller.cc

Issue 2014803002: Move DownloadControllerAndroid from content/ to chrome/ (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: removed deprecated cookie apis Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/android/download/download_controller.h"
6
7 #include <memory>
8 #include <utility>
9
10 #include "base/android/context_utils.h"
11 #include "base/android/jni_android.h"
12 #include "base/android/jni_string.h"
13 #include "base/bind.h"
14 #include "base/lazy_instance.h"
15 #include "base/logging.h"
16 #include "base/synchronization/lock.h"
17 #include "base/time/time.h"
18 #include "chrome/browser/android/download/chrome_download_delegate.h"
19 #include "chrome/browser/ui/android/view_android_helper.h"
20 #include "content/public/browser/browser_context.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/download_manager.h"
23 #include "content/public/browser/download_url_parameters.h"
24 #include "content/public/browser/render_process_host.h"
25 #include "content/public/browser/render_view_host.h"
26 #include "content/public/common/referrer.h"
27 #include "jni/DownloadController_jni.h"
28 #include "net/base/filename_util.h"
29 #include "ui/android/view_android.h"
30 #include "ui/android/window_android.h"
31
32 using base::android::ConvertUTF8ToJavaString;
33 using base::android::ScopedJavaLocalRef;
34 using content::BrowserContext;
35 using content::BrowserThread;
36 using content::ContextMenuParams;
37 using content::DownloadItem;
38 using content::DownloadManager;
39 using content::WebContents;
40
41 namespace {
42 // Guards download_controller_
43 base::LazyInstance<base::Lock> g_download_controller_lock_;
44
45 WebContents* GetWebContents(int render_process_id, int render_view_id) {
46 content::RenderViewHost* render_view_host =
47 content::RenderViewHost::FromID(render_process_id, render_view_id);
48
49 if (!render_view_host)
50 return nullptr;
51
52 return WebContents::FromRenderViewHost(render_view_host);
53 }
54
55 void CreateContextMenuDownload(int render_process_id,
56 int render_view_id,
57 const content::ContextMenuParams& params,
58 bool is_link,
59 const std::string& extra_headers,
60 bool granted) {
61 if (!granted)
62 return;
63
64 content::WebContents* web_contents =
65 GetWebContents(render_process_id, render_view_id);
66 if (!web_contents)
67 return;
68
69 const GURL& url = is_link ? params.link_url : params.src_url;
70 const GURL& referring_url =
71 params.frame_url.is_empty() ? params.page_url : params.frame_url;
72 content::DownloadManager* dlm =
73 content::BrowserContext::GetDownloadManager(
74 web_contents->GetBrowserContext());
75 std::unique_ptr<content::DownloadUrlParameters> dl_params(
76 content::DownloadUrlParameters::CreateForWebContentsMainFrame(
77 web_contents, url));
78 content::Referrer referrer = content::Referrer::SanitizeForRequest(
79 url,
80 content::Referrer(referring_url.GetAsReferrer(), params.referrer_policy));
81 dl_params->set_referrer(referrer);
82 if (is_link)
83 dl_params->set_referrer_encoding(params.frame_charset);
84 net::HttpRequestHeaders headers;
85 headers.AddHeadersFromString(extra_headers);
86 for (net::HttpRequestHeaders::Iterator it(headers); it.GetNext();)
87 dl_params->add_request_header(it.name(), it.value());
88 if (!is_link && extra_headers.empty())
89 dl_params->set_prefer_cache(true);
90 dl_params->set_prompt(false);
91 dlm->DownloadUrl(std::move(dl_params));
92 }
93
94 // Check if an interrupted download item can be auto resumed.
95 bool IsInterruptedDownloadAutoResumable(content::DownloadItem* download_item) {
96 int interrupt_reason = download_item->GetLastReason();
97 DCHECK_NE(interrupt_reason, content::DOWNLOAD_INTERRUPT_REASON_NONE);
98 return
99 interrupt_reason == content::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT ||
100 interrupt_reason == content::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED ||
101 interrupt_reason ==
102 content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED;
103 }
104
105 } // namespace
106
107 // JNI methods
108 static void Init(JNIEnv* env, const JavaParamRef<jobject>& obj) {
109 DownloadController::GetInstance()->Init(env, obj);
110 }
111
112 static void OnRequestFileAccessResult(JNIEnv* env,
113 const JavaParamRef<jobject>& obj,
114 jlong callback_id,
115 jboolean granted) {
116 DCHECK_CURRENTLY_ON(BrowserThread::UI);
117 DCHECK(callback_id);
118
119 // Convert java long long int to c++ pointer, take ownership.
120 std::unique_ptr<
121 DownloadControllerBase::AcquireFileAccessPermissionCallback>
122 cb(reinterpret_cast<
123 DownloadControllerBase::AcquireFileAccessPermissionCallback*>(
124 callback_id));
125 cb->Run(granted);
126 }
127
128 struct DownloadController::JavaObject {
129 ScopedJavaLocalRef<jobject> Controller(JNIEnv* env) {
130 return GetRealObject(env, obj);
131 }
132 jweak obj;
qinmin 2016/06/13 18:31:44 nit: obj_
Jinsuk Kim 2016/06/14 00:55:58 Done.
133 };
134
135 // static
136 bool DownloadController::RegisterDownloadController(JNIEnv* env) {
137 return RegisterNativesImpl(env);
138 }
139
140 // static
141 DownloadControllerBase* DownloadControllerBase::Get() {
142 base::AutoLock lock(g_download_controller_lock_.Get());
143 if (!DownloadControllerBase::download_controller_)
144 download_controller_ = DownloadController::GetInstance();
145 return DownloadControllerBase::download_controller_;
146 }
147
148 // static
149 void DownloadControllerBase::SetDownloadControllerBase(
150 DownloadControllerBase* download_controller) {
151 base::AutoLock lock(g_download_controller_lock_.Get());
152 DownloadControllerBase::download_controller_ = download_controller;
153 }
154
155 // static
156 DownloadController* DownloadController::GetInstance() {
157 return base::Singleton<DownloadController>::get();
158 }
159
160 DownloadController::DownloadController()
161 : java_object_(NULL) {
162 }
163
164 DownloadController::~DownloadController() {
165 if (java_object_) {
166 JNIEnv* env = base::android::AttachCurrentThread();
167 env->DeleteWeakGlobalRef(java_object_->obj);
168 delete java_object_;
169 base::android::CheckException(env);
170 }
171 }
172
173 // Initialize references to Java object.
174 void DownloadController::Init(JNIEnv* env, jobject obj) {
175 java_object_ = new JavaObject;
176 java_object_->obj = env->NewWeakGlobalRef(obj);
177 }
178
179 void DownloadController::AcquireFileAccessPermission(
180 WebContents* web_contents,
181 const DownloadControllerBase::AcquireFileAccessPermissionCallback& cb) {
182 DCHECK_CURRENTLY_ON(BrowserThread::UI);
183 DCHECK(web_contents);
184
185 ui::WindowAndroid* window_android =
186 ViewAndroidHelper::FromWebContents(web_contents)->
187 GetViewAndroid()->GetWindowAndroid();
188 if (window_android && HasFileAccessPermission(window_android)) {
189 BrowserThread::PostTask(
190 BrowserThread::UI, FROM_HERE, base::Bind(cb, true));
191 return;
192 }
193 // Make copy on the heap so we can pass the pointer through JNI.
194 intptr_t callback_id = reinterpret_cast<intptr_t>(
195 new DownloadControllerBase::AcquireFileAccessPermissionCallback(cb));
196 ChromeDownloadDelegate::FromWebContents(web_contents)->
197 RequestFileAccess(callback_id);
198 }
199
200 void DownloadController::SetDefaultDownloadFileName(
201 const std::string& file_name) {
202 default_file_name_ = file_name;
203 }
204
205 bool DownloadController::HasFileAccessPermission(
206 ui::WindowAndroid* window_android) {
207 ScopedJavaLocalRef<jobject> jwindow_android = window_android->GetJavaObject();
208
209 DCHECK_CURRENTLY_ON(BrowserThread::UI);
210 DCHECK(!jwindow_android.is_null());
211
212 JNIEnv* env = base::android::AttachCurrentThread();
213 return Java_DownloadController_hasFileAccess(
214 env, GetJavaObject()->Controller(env).obj(), jwindow_android.obj());
215 }
216
217 void DownloadController::CreateGETDownload(
218 int render_process_id, int render_view_id, bool must_download,
219 const DownloadInfo& info) {
220 DCHECK_CURRENTLY_ON(BrowserThread::IO);
221
222 // We are yielding the UI thread and render_view_host may go away by
223 // the time we come back. Pass along render_process_id and render_view_id
224 // to retrieve it later (if it still exists).
225 BrowserThread::PostTask(
226 BrowserThread::UI, FROM_HERE,
227 base::Bind(&DownloadController::StartAndroidDownload,
228 base::Unretained(this),
229 render_process_id, render_view_id, must_download, info));
230 }
231
232 void DownloadController::StartAndroidDownload(
233 int render_process_id, int render_view_id, bool must_download,
234 const DownloadInfo& info) {
235 DCHECK_CURRENTLY_ON(BrowserThread::UI);
236
237 WebContents* web_contents = GetWebContents(render_process_id, render_view_id);
238 if (!web_contents) {
239 // The view went away. Can't proceed.
240 LOG(ERROR) << "Download failed on URL:" << info.url.spec();
241 return;
242 }
243
244 AcquireFileAccessPermission(
245 web_contents,
246 base::Bind(&DownloadController::StartAndroidDownloadInternal,
247 base::Unretained(this), render_process_id, render_view_id,
248 must_download, info));
249 }
250
251 void DownloadController::StartAndroidDownloadInternal(
252 int render_process_id, int render_view_id, bool must_download,
253 const DownloadInfo& info, bool allowed) {
254 DCHECK_CURRENTLY_ON(BrowserThread::UI);
255 if (!allowed)
256 return;
257
258 WebContents* web_contents = GetWebContents(render_process_id, render_view_id);
259 // The view went away. Can't proceed.
260 if (!web_contents)
261 return;
262
263 base::string16 filename = net::GetSuggestedFilename(
264 info.url, info.content_disposition,
265 std::string(), // referrer_charset
266 std::string(), // suggested_name
267 info.original_mime_type,
268 default_file_name_);
269 ChromeDownloadDelegate::FromWebContents(web_contents)->RequestHTTPGetDownload(
270 info.url.spec(), info.user_agent,
271 info.content_disposition, info.original_mime_type,
272 info.cookie, info.referer, filename,
273 info.total_bytes, info.has_user_gesture,
274 must_download);
275 }
276
277 void DownloadController::OnDownloadStarted(
278 DownloadItem* download_item) {
279 DCHECK_CURRENTLY_ON(BrowserThread::UI);
280 WebContents* web_contents = download_item->GetWebContents();
281 if (!web_contents)
282 return;
283
284 // Register for updates to the DownloadItem.
285 download_item->AddObserver(this);
286
287 ChromeDownloadDelegate::FromWebContents(web_contents)->OnDownloadStarted(
288 download_item->GetTargetFilePath().BaseName().value(),
289 download_item->GetMimeType());
290 }
291
292 void DownloadController::OnDownloadUpdated(DownloadItem* item) {
293 DCHECK_CURRENTLY_ON(BrowserThread::UI);
294 if (item->IsDangerous() && (item->GetState() != DownloadItem::CANCELLED))
295 OnDangerousDownload(item);
296
297 JNIEnv* env = base::android::AttachCurrentThread();
298 ScopedJavaLocalRef<jstring> jguid =
299 ConvertUTF8ToJavaString(env, item->GetGuid());
300 ScopedJavaLocalRef<jstring> jurl =
301 ConvertUTF8ToJavaString(env, item->GetURL().spec());
302 ScopedJavaLocalRef<jstring> jmime_type =
303 ConvertUTF8ToJavaString(env, item->GetMimeType());
304 ScopedJavaLocalRef<jstring> jpath =
305 ConvertUTF8ToJavaString(env, item->GetTargetFilePath().value());
306 ScopedJavaLocalRef<jstring> jfilename = ConvertUTF8ToJavaString(
307 env, item->GetTargetFilePath().BaseName().value());
308 ScopedJavaLocalRef<jstring> joriginal_url =
309 ConvertUTF8ToJavaString(env, item->GetOriginalUrl().spec());
310 ScopedJavaLocalRef<jstring> jreferrer_url =
311 ConvertUTF8ToJavaString(env, item->GetReferrerUrl().spec());
312
313 switch (item->GetState()) {
314 case DownloadItem::IN_PROGRESS: {
315 base::TimeDelta time_delta;
316 item->TimeRemaining(&time_delta);
317 Java_DownloadController_onDownloadUpdated(
318 env, GetJavaObject()->Controller(env).obj(), jurl.obj(),
319 jmime_type.obj(), jfilename.obj(), jpath.obj(),
320 item->GetReceivedBytes(), jguid.obj(),
321 item->PercentComplete(), time_delta.InMilliseconds(),
322 item->HasUserGesture(), item->IsPaused(),
323 item->GetBrowserContext()->IsOffTheRecord());
324 break;
325 }
326 case DownloadItem::COMPLETE:
327 // Multiple OnDownloadUpdated() notifications may be issued while the
328 // download is in the COMPLETE state. Only handle one.
329 item->RemoveObserver(this);
330
331 // Call onDownloadCompleted
332 Java_DownloadController_onDownloadCompleted(
333 env, GetJavaObject()->Controller(env).obj(), jurl.obj(),
334 jmime_type.obj(), jfilename.obj(), jpath.obj(),
335 item->GetReceivedBytes(), jguid.obj(),
336 joriginal_url.obj(), jreferrer_url.obj(), item->HasUserGesture());
337 break;
338 case DownloadItem::CANCELLED:
339 Java_DownloadController_onDownloadCancelled(
340 env, GetJavaObject()->Controller(env).obj(), jguid.obj());
341 break;
342 case DownloadItem::INTERRUPTED:
343 // When device loses/changes network, we get a NETWORK_TIMEOUT,
344 // NETWORK_FAILED or NETWORK_DISCONNECTED error. Download should auto
345 // resume in this case.
346 Java_DownloadController_onDownloadInterrupted(
347 env, GetJavaObject()->Controller(env).obj(), jurl.obj(),
348 jmime_type.obj(), jfilename.obj(), jpath.obj(),
349 item->GetReceivedBytes(), jguid.obj(),
350 item->CanResume(), IsInterruptedDownloadAutoResumable(item),
351 item->GetBrowserContext()->IsOffTheRecord());
352 item->RemoveObserver(this);
353 break;
354 case DownloadItem::MAX_DOWNLOAD_STATE:
355 NOTREACHED();
356 }
357 }
358
359 void DownloadController::OnDangerousDownload(DownloadItem* item) {
360 WebContents* web_contents = item->GetWebContents();
361 if (!web_contents)
362 return;
363 ChromeDownloadDelegate::FromWebContents(web_contents)->OnDangerousDownload(
364 item->GetTargetFilePath().BaseName().value(), item->GetGuid());
365 }
366
367 DownloadController::JavaObject*
368 DownloadController::GetJavaObject() {
369 if (!java_object_) {
370 // Initialize Java DownloadController by calling
371 // DownloadController.getInstance(), which will call Init()
372 // if Java DownloadController is not instantiated already.
373 JNIEnv* env = base::android::AttachCurrentThread();
374 Java_DownloadController_getInstance(env);
375 }
376
377 DCHECK(java_object_);
378 return java_object_;
379 }
380
381 void DownloadController::StartContextMenuDownload(
382 const ContextMenuParams& params, WebContents* web_contents, bool is_link,
383 const std::string& extra_headers) {
384 int process_id = web_contents->GetRenderProcessHost()->GetID();
385 int routing_id = web_contents->GetRoutingID();
386 AcquireFileAccessPermission(
387 web_contents, base::Bind(&CreateContextMenuDownload, process_id,
388 routing_id, params, is_link, extra_headers));
389 }
390
391 void DownloadController::DangerousDownloadValidated(
392 WebContents* web_contents,
393 const std::string& download_guid,
394 bool accept) {
395 if (!web_contents)
396 return;
397 DownloadManager* dlm =
398 BrowserContext::GetDownloadManager(web_contents->GetBrowserContext());
399 DownloadItem* item = dlm->GetDownloadByGuid(download_guid);
400 if (!item)
401 return;
402 if (accept)
403 item->ValidateDangerousDownload();
404 else
405 item->Remove();
406 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698