• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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/download/download_ui_controller.h"
6 
7 #include "base/stl_util.h"
8 #include "chrome/browser/download/download_item_model.h"
9 #include "chrome/browser/ui/browser_finder.h"
10 #include "chrome/browser/ui/browser_tabstrip.h"
11 #include "content/public/browser/download_item.h"
12 #include "content/public/browser/web_contents.h"
13 #include "content/public/browser/web_contents_delegate.h"
14 
15 #if defined(OS_ANDROID)
16 #include "content/public/browser/android/download_controller_android.h"
17 #else
18 #include "chrome/browser/profiles/profile.h"
19 #endif
20 
21 namespace {
22 
23 // DefaultUIControllerDelegate{Android,} is used when a DownloadUIController is
24 // constructed without specifying an explicit Delegate.
25 #if defined(OS_ANDROID)
26 
27 class DefaultUIControllerDelegateAndroid
28     : public DownloadUIController::Delegate {
29  public:
DefaultUIControllerDelegateAndroid()30   DefaultUIControllerDelegateAndroid() {}
~DefaultUIControllerDelegateAndroid()31   virtual ~DefaultUIControllerDelegateAndroid() {}
32 
33  private:
34   // DownloadUIController::Delegate
35   virtual void NotifyDownloadStarting(content::DownloadItem* item) OVERRIDE;
36 };
37 
NotifyDownloadStarting(content::DownloadItem * item)38 void DefaultUIControllerDelegateAndroid::NotifyDownloadStarting(
39     content::DownloadItem* item) {
40   // GET downloads without authentication are delegated to the Android
41   // DownloadManager. Chrome is responsible for the rest.  See
42   // InterceptDownloadResourceThrottle::ProcessDownloadRequest().
43   content::DownloadControllerAndroid::Get()->OnDownloadStarted(item);
44 }
45 
46 #else  // OS_ANDROID
47 
48 class DefaultUIControllerDelegate : public DownloadUIController::Delegate {
49  public:
50   // |profile| is required to outlive DefaultUIControllerDelegate.
51   explicit DefaultUIControllerDelegate(Profile* profile)
52       : profile_(profile) {}
53   virtual ~DefaultUIControllerDelegate() {}
54 
55  private:
56   // DownloadUIController::Delegate
57   virtual void NotifyDownloadStarting(content::DownloadItem* item) OVERRIDE;
58 
59   Profile* profile_;
60 };
61 
62 void DefaultUIControllerDelegate::NotifyDownloadStarting(
63     content::DownloadItem* item) {
64   content::WebContents* web_contents = item->GetWebContents();
65   Browser* browser =
66       web_contents ? chrome::FindBrowserWithWebContents(web_contents) : NULL;
67 
68   // As a last resort, use the last active browser for this profile. Not ideal,
69   // but better than not showing the download at all.
70   if (browser == NULL) {
71     browser = chrome::FindLastActiveWithProfile(profile_,
72                                                 chrome::GetActiveDesktop());
73   }
74 
75   if (browser)
76     browser->ShowDownload(item);
77 }
78 
79 #endif  // !OS_ANDROID
80 
81 } // namespace
82 
~Delegate()83 DownloadUIController::Delegate::~Delegate() {
84 }
85 
DownloadUIController(content::DownloadManager * manager,scoped_ptr<Delegate> delegate)86 DownloadUIController::DownloadUIController(content::DownloadManager* manager,
87                                            scoped_ptr<Delegate> delegate)
88     : download_notifier_(manager, this),
89       delegate_(delegate.Pass()) {
90   if (!delegate_) {
91 #if defined(OS_ANDROID)
92     delegate_.reset(new DefaultUIControllerDelegateAndroid());
93 #else
94     // The delegate should not be invoked after the profile has gone away. This
95     // should be the case since DownloadUIController is owned by
96     // DownloadService, which in turn is a profile keyed service.
97     delegate_.reset(new DefaultUIControllerDelegate(
98         Profile::FromBrowserContext(manager->GetBrowserContext())));
99 #endif
100   }
101 }
102 
~DownloadUIController()103 DownloadUIController::~DownloadUIController() {
104 }
105 
OnDownloadCreated(content::DownloadManager * manager,content::DownloadItem * item)106 void DownloadUIController::OnDownloadCreated(content::DownloadManager* manager,
107                                              content::DownloadItem* item) {
108   // If this isn't a new download, there's nothing to do.
109   if (item->GetState() != content::DownloadItem::IN_PROGRESS)
110     return;
111 
112   DownloadItemModel(item).SetShouldNotifyUI(true);
113   // SavePackage downloads are created in a state where they can be shown in the
114   // browser. Call OnDownloadUpdated() once to notify the UI immediately.
115   OnDownloadUpdated(manager, item);
116 }
117 
OnDownloadUpdated(content::DownloadManager * manager,content::DownloadItem * item)118 void DownloadUIController::OnDownloadUpdated(content::DownloadManager* manager,
119                                              content::DownloadItem* item) {
120   // Ignore if we've already notified the UI about |item| or if it isn't a new
121   // download.
122   if (!DownloadItemModel(item).ShouldNotifyUI())
123     return;
124 
125   // Wait until the target path is determined.
126   if (item->GetTargetFilePath().empty())
127     return;
128 
129   // Can't be complete. That would imply that we didn't receive an
130   // OnDownloadUpdated() after the target was determined.
131   DCHECK_NE(content::DownloadItem::COMPLETE, item->GetState());
132 
133   DownloadItemModel(item).SetShouldNotifyUI(false);
134   delegate_->NotifyDownloadStarting(item);
135 }
136