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