Home | History | Annotate | Download | only in 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:
     30   DefaultUIControllerDelegateAndroid() {}
     31   virtual ~DefaultUIControllerDelegateAndroid() {}
     32 
     33  private:
     34   // DownloadUIController::Delegate
     35   virtual void NotifyDownloadStarting(content::DownloadItem* item) OVERRIDE;
     36 };
     37 
     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 
     83 DownloadUIController::Delegate::~Delegate() {
     84 }
     85 
     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 
    103 DownloadUIController::~DownloadUIController() {
    104 }
    105 
    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 
    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