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