Home | History | Annotate | Download | only in download
      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/download/download_status_updater.h"
      6 
      7 #include <shobjidl.h>
      8 #include <string>
      9 
     10 #include "base/files/file_path.h"
     11 #include "base/logging.h"
     12 #include "base/stl_util.h"
     13 #include "base/strings/string_number_conversions.h"
     14 #include "base/win/metro.h"
     15 #include "base/win/scoped_comptr.h"
     16 #include "base/win/windows_version.h"
     17 #include "chrome/browser/platform_util.h"
     18 #include "chrome/browser/ui/browser.h"
     19 #include "chrome/browser/ui/browser_iterator.h"
     20 #include "chrome/browser/ui/browser_window.h"
     21 #include "content/public/browser/browser_context.h"
     22 #include "content/public/browser/browser_thread.h"
     23 #include "grit/generated_resources.h"
     24 #include "ui/base/l10n/l10n_util.h"
     25 #include "url/gurl.h"
     26 #include "win8/util/win8_util.h"
     27 
     28 // This code doesn't compile with Aura on. TODO(avi): hook it up so that
     29 // win_aura can do platform integration.
     30 #if !defined(USE_AURA)
     31 
     32 namespace {
     33 
     34 const char kDownloadNotificationPrefix[] = "DownloadNotification";
     35 int g_next_notification_id = 0;
     36 
     37 void UpdateTaskbarProgressBar(int download_count,
     38                               bool progress_known,
     39                               float progress) {
     40   // Taskbar progress bar is only supported on Win7.
     41   if (base::win::GetVersion() < base::win::VERSION_WIN7)
     42     return;
     43 
     44   base::win::ScopedComPtr<ITaskbarList3> taskbar;
     45   HRESULT result = taskbar.CreateInstance(CLSID_TaskbarList, NULL,
     46                                           CLSCTX_INPROC_SERVER);
     47   if (FAILED(result)) {
     48     VLOG(1) << "Failed creating a TaskbarList object: " << result;
     49     return;
     50   }
     51 
     52   result = taskbar->HrInit();
     53   if (FAILED(result)) {
     54     LOG(ERROR) << "Failed initializing an ITaskbarList3 interface.";
     55     return;
     56   }
     57 
     58   // Iterate through all the browser windows, and draw the progress bar.
     59   for (chrome::BrowserIterator it; !it.done(); it.Next()) {
     60     Browser* browser = *it;
     61     BrowserWindow* window = browser->window();
     62     if (!window)
     63       continue;
     64     HWND frame = window->GetNativeWindow();
     65     if (download_count == 0 || progress == 1.0f)
     66       taskbar->SetProgressState(frame, TBPF_NOPROGRESS);
     67     else if (!progress_known)
     68       taskbar->SetProgressState(frame, TBPF_INDETERMINATE);
     69     else
     70       taskbar->SetProgressValue(frame, static_cast<int>(progress * 100), 100);
     71   }
     72 }
     73 
     74 void MetroDownloadNotificationClickedHandler(const wchar_t* download_path) {
     75   // Metro chrome will invoke these handlers on the metro thread.
     76   DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
     77 
     78   // Ensure that we invoke the function to display the downloaded item on the
     79   // UI thread.
     80   content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
     81                                    base::Bind(platform_util::ShowItemInFolder,
     82                                               base::FilePath(download_path)));
     83 }
     84 
     85 }  // namespace
     86 
     87 void DownloadStatusUpdater::UpdateAppIconDownloadProgress(
     88     content::DownloadItem* download) {
     89 
     90   // Always update overall progress.
     91   float progress = 0;
     92   int download_count = 0;
     93   bool progress_known = GetProgress(&progress, &download_count);
     94   UpdateTaskbarProgressBar(download_count, progress_known, progress);
     95 
     96   // Fire notifications when downloads complete.
     97   if (!win8::IsSingleWindowMetroMode())
     98     return;
     99 
    100   if (download->GetState() != content::DownloadItem::COMPLETE)
    101     return;
    102 
    103   if (download->GetOpenWhenComplete() ||
    104       download->ShouldOpenFileBasedOnExtension() ||
    105       download->IsTemporary() ||
    106       download->GetAutoOpened())
    107     return;
    108 
    109   // Don't display the Windows8 metro notifications for an incognito download.
    110   if (download->GetBrowserContext() &&
    111       download->GetBrowserContext()->IsOffTheRecord())
    112     return;
    113 
    114   // Don't display the Windows 8 metro notifications if we are in the
    115   // foreground.
    116   HWND foreground_window = ::GetForegroundWindow();
    117   if (::IsWindow(foreground_window)) {
    118     DWORD process_id = 0;
    119     ::GetWindowThreadProcessId(foreground_window, &process_id);
    120     if (process_id == ::GetCurrentProcessId())
    121       return;
    122   }
    123 
    124   // In Windows 8 metro mode display a metro style notification which
    125   // informs the user that the download is complete.
    126   HMODULE metro = base::win::GetMetroModule();
    127   base::win::MetroNotification display_notification =
    128       reinterpret_cast<base::win::MetroNotification>(
    129           ::GetProcAddress(metro, "DisplayNotification"));
    130   DCHECK(display_notification);
    131   if (display_notification) {
    132     string16 title = l10n_util::GetStringUTF16(
    133         IDS_METRO_DOWNLOAD_COMPLETE_NOTIFICATION_TITLE);
    134     string16 body = l10n_util::GetStringUTF16(
    135         IDS_METRO_DOWNLOAD_COMPLETE_NOTIFICATION);
    136 
    137     // Dummy notification id. Every metro style notification needs a
    138     // unique notification id.
    139     std::string notification_id = kDownloadNotificationPrefix;
    140     notification_id += base::IntToString(g_next_notification_id++);
    141 
    142     display_notification(download->GetURL().spec().c_str(),
    143                          "",
    144                          title.c_str(),
    145                          body.c_str(),
    146                          L"",
    147                          notification_id.c_str(),
    148                          MetroDownloadNotificationClickedHandler,
    149                          download->GetTargetFilePath().value().c_str());
    150   }
    151 }
    152 
    153 #endif  // !USE_AURA
    154