summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authoravi@chromium.org <avi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-12 02:25:13 +0000
committeravi@chromium.org <avi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-12 02:25:13 +0000
commit27ee16ff2b9370d70fb93233b73ec01856f08017 (patch)
tree0ee062b116b1b7ab29d9546b37a2ec3cc461e3b5 /chrome
parentd2a0e1ab98ab2e01fdb2cb77387e917c1d57b4c8 (diff)
downloadchromium_src-27ee16ff2b9370d70fb93233b73ec01856f08017.zip
chromium_src-27ee16ff2b9370d70fb93233b73ec01856f08017.tar.gz
chromium_src-27ee16ff2b9370d70fb93233b73ec01856f08017.tar.bz2
Unify and clean up system download notifications, add Mountain Lion support.
BUG=138962 TEST=as in bug Review URL: https://chromiumcodereview.appspot.com/10827207 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@151195 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/download/chrome_download_manager_delegate.cc9
-rw-r--r--chrome/browser/download/download_completion_observer_win.cc111
-rw-r--r--chrome/browser/download/download_completion_observer_win.h42
-rw-r--r--chrome/browser/download/download_status_updater.cc33
-rw-r--r--chrome/browser/download/download_status_updater.h12
-rw-r--r--chrome/browser/download/download_status_updater_gtk.cc16
-rw-r--r--chrome/browser/download/download_status_updater_mac.mm287
-rw-r--r--chrome/browser/download/download_status_updater_unittest.cc85
-rw-r--r--chrome/browser/download/download_status_updater_win.cc123
-rw-r--r--chrome/browser/download/download_util.cc58
-rw-r--r--chrome/browser/download/download_util.h9
-rw-r--r--chrome/browser/ui/cocoa/download/download_item_mac.mm2
-rw-r--r--chrome/browser/ui/cocoa/download/download_util_mac.h4
-rw-r--r--chrome/browser/ui/cocoa/download/download_util_mac.mm24
-rw-r--r--chrome/chrome_browser.gypi5
15 files changed, 526 insertions, 294 deletions
diff --git a/chrome/browser/download/chrome_download_manager_delegate.cc b/chrome/browser/download/chrome_download_manager_delegate.cc
index 27e5988..3a909c7 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.cc
+++ b/chrome/browser/download/chrome_download_manager_delegate.cc
@@ -60,10 +60,6 @@
#include "chrome/browser/download/save_package_file_picker_chromeos.h"
#endif
-#if defined(OS_WIN)
-#include "chrome/browser/download/download_completion_observer_win.h"
-#endif // OS_WIN
-
using content::BrowserContext;
using content::BrowserThread;
using content::DownloadId;
@@ -143,11 +139,6 @@ void ChromeDownloadManagerDelegate::SetDownloadManager(DownloadManager* dm) {
extension_event_router_.reset(new ExtensionDownloadsEventRouter(
profile_, download_manager_));
#endif
-
-#if defined(OS_WIN)
- DownloadCompletionObserver* download_completion =
- new DownloadCompletionObserver(dm);
-#endif // OS_WIN
}
void ChromeDownloadManagerDelegate::Shutdown() {
diff --git a/chrome/browser/download/download_completion_observer_win.cc b/chrome/browser/download/download_completion_observer_win.cc
deleted file mode 100644
index 809e896..0000000
--- a/chrome/browser/download/download_completion_observer_win.cc
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/download/download_completion_observer_win.h"
-
-#include <string>
-
-#include "base/logging.h"
-#include "base/stl_util.h"
-#include "base/string_number_conversions.h"
-#include "base/win/metro.h"
-#include "googleurl/src/gurl.h"
-#include "grit/generated_resources.h"
-#include "ui/base/l10n/l10n_util.h"
-
-using content::DownloadItem;
-using content::DownloadManager;
-
-static const char kDownloadNotificationPrefix[] = "DownloadNotification";
-int g_next_notification_id = 0;
-
-DownloadCompletionObserver::DownloadCompletionObserver(
- DownloadManager* manager) {
- manager->AddObserver(this);
-}
-
-DownloadCompletionObserver::~DownloadCompletionObserver() {
- DCHECK(download_items_.empty());
-}
-
-void DownloadCompletionObserver::OnDownloadCreated(DownloadManager* manager,
- DownloadItem* download) {
- if (download->IsInProgress()) {
- download_items_.insert(download);
- download->AddObserver(this);
- }
-}
-
-void DownloadCompletionObserver::ManagerGoingDown(DownloadManager* manager) {
- ClearDownloadItems();
- manager->RemoveObserver(this);
- delete this;
-}
-
-void DownloadCompletionObserver::OnDownloadUpdated(DownloadItem* download) {
- switch (download->GetState()) {
- case DownloadItem::COMPLETE: {
- if (base::win::IsMetroProcess() &&
- !download->GetOpenWhenComplete() &&
- !download->ShouldOpenFileBasedOnExtension() &&
- !download->IsTemporary() &&
- !download->GetAutoOpened()) {
- // In Windows 8 metro mode display a metro style notification which
- // informs the user that the download is complete.
- HMODULE metro = base::win::GetMetroModule();
- base::win::MetroNotification display_notification =
- reinterpret_cast< base::win::MetroNotification>(
- ::GetProcAddress(metro, "DisplayNotification"));
- DCHECK(display_notification);
- if (display_notification) {
- string16 title = l10n_util::GetStringUTF16(
- IDS_METRO_DOWNLOAD_COMPLETE_NOTIFICATION_TITLE);
- string16 body = l10n_util::GetStringUTF16(
- IDS_METRO_DOWNLOAD_COMPLETE_NOTIFICATION);
-
- // Dummy notification id. Every metro style notification needs a
- // unique notification id.
- std::string notification_id = kDownloadNotificationPrefix;
- notification_id += base::IntToString(g_next_notification_id++);
-
- display_notification(download->GetURL().spec().c_str(),
- "",
- title.c_str(),
- body.c_str(),
- L"",
- notification_id.c_str());
- }
- }
- DCHECK(ContainsKey(download_items_, download));
- download_items_.erase(download);
- download->RemoveObserver(this);
- break;
- }
-
- case DownloadItem::INTERRUPTED:
- case DownloadItem::CANCELLED: {
- DCHECK(ContainsKey(download_items_, download));
- download_items_.erase(download);
- download->RemoveObserver(this);
- break;
- }
-
- default:
- break;
- }
-}
-
-void DownloadCompletionObserver::OnDownloadDestroyed(DownloadItem* download) {
- DCHECK(ContainsKey(download_items_, download));
- download_items_.erase(download);
- download->RemoveObserver(this);
-}
-
-void DownloadCompletionObserver::ClearDownloadItems() {
- for (std::set<DownloadItem*>::iterator it = download_items_.begin();
- it != download_items_.end(); ++it) {
- (*it)->RemoveObserver(this);
- }
- download_items_.clear();
-}
diff --git a/chrome/browser/download/download_completion_observer_win.h b/chrome/browser/download/download_completion_observer_win.h
deleted file mode 100644
index ceca491..0000000
--- a/chrome/browser/download/download_completion_observer_win.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_COMPLETION_OBSERVER_WIN_H_
-#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_COMPLETION_OBSERVER_WIN_H_
-
-#include <set>
-
-#include "base/basictypes.h"
-#include "content/public/browser/download_item.h"
-#include "content/public/browser/download_manager.h"
-
-// Tracks download item completions and notifies any interested parties
-// (Windows 8 metro) about the same. On Windows 8 we display metro style
-// notifications when a download completes.
-class DownloadCompletionObserver
- : public content::DownloadManager::Observer,
- public content::DownloadItem::Observer {
- public:
- explicit DownloadCompletionObserver(content::DownloadManager* manager);
- ~DownloadCompletionObserver();
-
- // Methods inherited from content::DownloadManager::Observer.
- virtual void OnDownloadCreated(
- content::DownloadManager* manager, content::DownloadItem* download)
- OVERRIDE;
- virtual void ManagerGoingDown(content::DownloadManager* manager) OVERRIDE;
-
- // Methods inherited from content::DownloadItem::Observer.
- virtual void OnDownloadUpdated(content::DownloadItem* download) OVERRIDE;
- virtual void OnDownloadDestroyed(content::DownloadItem* download) OVERRIDE;
-
- private:
- void ClearDownloadItems();
-
- std::set<content::DownloadItem*> download_items_;
-
- DISALLOW_COPY_AND_ASSIGN(DownloadCompletionObserver);
-};
-
-#endif // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_COMPLETION_OBSERVER_WIN_H_
diff --git a/chrome/browser/download/download_status_updater.cc b/chrome/browser/download/download_status_updater.cc
index a8dde9b..489d3be 100644
--- a/chrome/browser/download/download_status_updater.cc
+++ b/chrome/browser/download/download_status_updater.cc
@@ -55,12 +55,19 @@ void DownloadStatusUpdater::ModelChanged(content::DownloadManager* manager) {
std::vector<content::DownloadItem*> downloads;
manager->SearchDownloads(string16(), &downloads);
+ std::vector<content::DownloadItem*> added_downloads;
for (std::vector<content::DownloadItem*>::iterator it = downloads.begin();
it != downloads.end(); ++it) {
- UpdateItem(*it);
+ if (UpdateItem(*it))
+ added_downloads.push_back(*it);
}
- UpdateAppIconDownloadProgress();
+ for (std::vector<content::DownloadItem*>::iterator it =
+ added_downloads.begin();
+ it != added_downloads.end();
+ ++it) {
+ UpdateAppIconDownloadProgress(*it);
+ }
}
void DownloadStatusUpdater::ManagerGoingDown(
@@ -74,7 +81,7 @@ void DownloadStatusUpdater::ManagerGoingDown(
void DownloadStatusUpdater::OnDownloadUpdated(
content::DownloadItem* download) {
UpdateItem(download);
- UpdateAppIconDownloadProgress();
+ UpdateAppIconDownloadProgress(download);
}
void DownloadStatusUpdater::OnDownloadDestroyed(
@@ -83,30 +90,30 @@ void DownloadStatusUpdater::OnDownloadDestroyed(
items_.erase(download);
download->RemoveObserver(this);
}
- UpdateAppIconDownloadProgress();
+ UpdateAppIconDownloadProgress(download);
}
void DownloadStatusUpdater::OnDownloadOpened(content::DownloadItem* download) {
}
-void DownloadStatusUpdater::UpdateAppIconDownloadProgress() {
- float progress = 0;
- int download_count = 0;
- bool progress_known = GetProgress(&progress, &download_count);
- download_util::UpdateAppIconDownloadProgress(download_count,
- progress_known,
- progress);
+#if defined(USE_AURA) || defined(OS_ANDROID)
+void DownloadStatusUpdater::UpdateAppIconDownloadProgress(
+ content::DownloadItem* download) {
+ // TODO(davemoore): Implement once UX for aura download is decided <104742>
+ // TODO(avi): Implement for Android?
}
+#endif
// React to a transition that a download associated with one of our
// download managers has made. Our goal is to have only IN_PROGRESS
// items on our set list, as they're the only ones that have relevance
// to GetProgress() return values.
-void DownloadStatusUpdater::UpdateItem(content::DownloadItem* download) {
+bool DownloadStatusUpdater::UpdateItem(content::DownloadItem* download) {
if (download->GetState() == content::DownloadItem::IN_PROGRESS) {
if (!ContainsKey(items_, download)) {
items_.insert(download);
download->AddObserver(this);
+ return true;
}
} else {
if (ContainsKey(items_, download)) {
@@ -114,4 +121,6 @@ void DownloadStatusUpdater::UpdateItem(content::DownloadItem* download) {
download->RemoveObserver(this);
}
}
+
+ return false;
}
diff --git a/chrome/browser/download/download_status_updater.h b/chrome/browser/download/download_status_updater.h
index 252be03..75218c5 100644
--- a/chrome/browser/download/download_status_updater.h
+++ b/chrome/browser/download/download_status_updater.h
@@ -42,12 +42,16 @@ class DownloadStatusUpdater
virtual void OnDownloadDestroyed(content::DownloadItem* download) OVERRIDE;
protected:
- // Update the app icon. Virtual to be overridable for testing.
- virtual void UpdateAppIconDownloadProgress();
+ // Platform-specific function to update the platform UI for download progress.
+ // |download| is the download item that changed. Implementations should not
+ // hold the value of |download| as it is not guaranteed to remain valid.
+ // Virtual to be overridable for testing.
+ virtual void UpdateAppIconDownloadProgress(content::DownloadItem* download);
private:
- // Update the internal state tracking an item.
- void UpdateItem(content::DownloadItem* download);
+ // Update the internal state tracking an item. Returns true if the item was
+ // added to the set of tracked items.
+ bool UpdateItem(content::DownloadItem* download);
std::set<content::DownloadManager*> managers_;
std::set<content::DownloadItem*> items_;
diff --git a/chrome/browser/download/download_status_updater_gtk.cc b/chrome/browser/download/download_status_updater_gtk.cc
new file mode 100644
index 0000000..6f045fff76
--- /dev/null
+++ b/chrome/browser/download/download_status_updater_gtk.cc
@@ -0,0 +1,16 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/download/download_status_updater.h"
+
+#include "chrome/browser/ui/gtk/unity_service.h"
+
+void DownloadStatusUpdater::UpdateAppIconDownloadProgress(
+ content::DownloadItem* download) {
+ float progress = 0;
+ int download_count = 0;
+ GetProgress(&progress, &download_count);
+ unity::SetDownloadCount(download_count);
+ unity::SetProgressFraction(progress);
+}
diff --git a/chrome/browser/download/download_status_updater_mac.mm b/chrome/browser/download/download_status_updater_mac.mm
new file mode 100644
index 0000000..240f7eb
--- /dev/null
+++ b/chrome/browser/download/download_status_updater_mac.mm
@@ -0,0 +1,287 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/download/download_status_updater.h"
+
+#include "base/mac/foundation_util.h"
+#include "base/memory/scoped_nsobject.h"
+#include "base/supports_user_data.h"
+#include "base/sys_string_conversions.h"
+#include "content/public/browser/download_item.h"
+#import "chrome/browser/ui/cocoa/dock_icon.h"
+#include "googleurl/src/gurl.h"
+
+// --- Private 10.8 API for showing progress ---
+// rdar://12058866 http://www.openradar.me/12058866
+
+namespace {
+
+NSString* const kNSProgressAppBundleIdentifierKey =
+ @"NSProgressAppBundleIdentifierKey";
+NSString* const kNSProgressEstimatedTimeKey =
+ @"NSProgressEstimatedTimeKey";
+NSString* const kNSProgressFileCompletedCountKey =
+ @"NSProgressFileCompletedCountKey";
+NSString* const kNSProgressFileContainerURLKey =
+ @"NSProgressFileContainerURLKey";
+NSString* const kNSProgressFileDownloadingSourceURLKey =
+ @"NSProgressFileDownloadingSourceURLKey";
+NSString* const kNSProgressFileIconKey =
+ @"NSProgressFileIconKey";
+NSString* const kNSProgressFileIconOriginalRectKey =
+ @"NSProgressFileIconOriginalRectKey";
+NSString* const kNSProgressFileLocationCanChangeKey =
+ @"NSProgressFileLocationCanChangeKey";
+NSString* const kNSProgressFileOperationKindAirDropping =
+ @"NSProgressFileOperationKindAirDropping";
+NSString* const kNSProgressFileOperationKindCopying =
+ @"NSProgressFileOperationKindCopying";
+NSString* const kNSProgressFileOperationKindDecompressingAfterDownloading =
+ @"NSProgressFileOperationKindDecompressingAfterDownloading";
+NSString* const kNSProgressFileOperationKindDownloading =
+ @"NSProgressFileOperationKindDownloading";
+NSString* const kNSProgressFileOperationKindEncrypting =
+ @"NSProgressFileOperationKindEncrypting";
+NSString* const kNSProgressFileOperationKindKey =
+ @"NSProgressFileOperationKindKey";
+NSString* const kNSProgressFileTotalCountKey =
+ @"NSProgressFileTotalCountKey";
+NSString* const kNSProgressFileURLKey =
+ @"NSProgressFileURLKey";
+NSString* const kNSProgressIsWaitingKey =
+ @"NSProgressIsWaitingKey";
+NSString* const kNSProgressKindFile =
+ @"NSProgressKindFile";
+NSString* const kNSProgressThroughputKey =
+ @"NSProgressThroughputKey";
+
+NSString* ProgressString(NSString* string) {
+ static NSMutableDictionary* cache;
+ static CFBundleRef foundation;
+ if (!cache) {
+ cache = [[NSMutableDictionary alloc] init];
+ foundation = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.Foundation"));
+ }
+
+ NSString* result = [cache objectForKey:string];
+ if (!result) {
+ NSString** ref = static_cast<NSString**>(
+ CFBundleGetDataPointerForName(foundation,
+ base::mac::NSToCFCast(string)));
+ if (ref) {
+ result = *ref;
+ [cache setObject:result forKey:string];
+ }
+ }
+
+ return result;
+}
+
+} // namespace
+
+@interface NSProgress : NSObject
+
+- (id)initWithParent:(id)parent userInfo:(NSDictionary*)info;
+@property(copy) NSString* kind;
+
+- (void)unpublish;
+- (void)publish;
+
+- (void)setUserInfoObject:(id)object forKey:(NSString*)key;
+- (NSDictionary*)userInfo;
+
+@property(readonly) double fractionCompleted;
+// Set the totalUnitCount to -1 to indicate an indeterminate download. The dock
+// shows a non-filling progress bar; the Finder is lame and draws its progress
+// bar off the right side.
+@property(readonly, getter=isIndeterminate) BOOL indeterminate;
+@property long long completedUnitCount;
+@property long long totalUnitCount;
+
+// Pausing appears to be unimplemented in 10.8.0.
+- (void)pause;
+@property(readonly, getter=isPaused) BOOL paused;
+@property(getter=isPausable) BOOL pausable;
+- (void)setPausingHandler:(id)blockOfUnknownSignature;
+
+- (void)cancel;
+@property(readonly, getter=isCancelled) BOOL cancelled;
+@property(getter=isCancellable) BOOL cancellable;
+// Note that the cancellation handler block will be called on a random thread.
+- (void)setCancellationHandler:(void (^)())block;
+
+// Allows other applications to provide feedback as to whether the progress is
+// visible in that app. Note that the acknowledgement handler block will be
+// called on a random thread.
+// com.apple.dock => BOOL indicating whether the download target folder was
+// successfully "flown to" at the beginning of the download.
+// This primarily depends on whether the download target
+// folder is in the dock. Note that if the download target
+// folder is added or removed from the dock during the
+// duration of the download, it will not trigger a callback.
+// Note that if the "fly to the dock" keys were not set, the
+// callback's parameter will always be NO.
+// com.apple.Finder => always YES, no matter whether the download target
+// folder's window is open.
+- (void)handleAcknowledgementByAppWithBundleIdentifier:(NSString*)bundle
+ usingBlock:(void (^)(BOOL success))block;
+
+@end
+
+// --- Private 10.8 API for showing progress ---
+
+namespace {
+
+bool NSProgressSupported() {
+ static bool supported;
+ static bool valid;
+ if (!valid) {
+ supported = NSClassFromString(@"NSProgress");
+ valid = true;
+ }
+
+ return supported;
+}
+
+const char kCrNSProgressUserDataKey[] = "CrNSProgressUserData";
+
+class CrNSProgressUserData : public base::SupportsUserData::Data {
+ public:
+ CrNSProgressUserData(NSProgress* progress, const FilePath& target)
+ : target_(target) {
+ progress_.reset(progress);
+ }
+ virtual ~CrNSProgressUserData() {}
+
+ NSProgress* progress() const { return progress_.get(); }
+ FilePath target() const { return target_; }
+ void setTarget(const FilePath& target) { target_ = target; }
+
+ private:
+ scoped_nsobject<NSProgress> progress_;
+ FilePath target_;
+};
+
+void UpdateAppIcon(int download_count,
+ bool progress_known,
+ float progress) {
+ DockIcon* dock_icon = [DockIcon sharedDockIcon];
+ [dock_icon setDownloads:download_count];
+ [dock_icon setIndeterminate:!progress_known];
+ [dock_icon setProgress:progress];
+ [dock_icon updateIcon];
+}
+
+void CreateNSProgress(content::DownloadItem* download) {
+ NSURL* source_url = [NSURL URLWithString:
+ base::SysUTF8ToNSString(download->GetURL().spec())];
+ FilePath destination_path = download->GetFullPath();
+ NSURL* destination_url = [NSURL fileURLWithPath:
+ base::mac::FilePathToNSString(destination_path)];
+
+ // If there were an image to fly to the download folder in the dock, then
+ // the keys in the userInfo to set would be:
+ // - @"NSProgressFlyToImageKey" : NSImage
+ // - kNSProgressFileIconOriginalRectKey : NSValue of NSRect in global coords
+
+ NSDictionary* user_info = @{
+ ProgressString(kNSProgressFileDownloadingSourceURLKey) : source_url,
+ ProgressString(kNSProgressFileLocationCanChangeKey) : @true,
+ ProgressString(kNSProgressFileOperationKindKey) :
+ ProgressString(kNSProgressFileOperationKindDownloading),
+ ProgressString(kNSProgressFileURLKey) : destination_url
+ };
+ Class progress_class = NSClassFromString(@"NSProgress");
+ NSProgress* progress = [progress_class performSelector:@selector(alloc)];
+ progress = [progress performSelector:@selector(initWithParent:userInfo:)
+ withObject:nil
+ withObject:user_info];
+ progress.kind = ProgressString(kNSProgressKindFile);
+
+ progress.pausable = NO;
+ progress.cancellable = YES;
+ [progress setCancellationHandler:^{
+ dispatch_async(dispatch_get_main_queue(), ^{
+ download->Cancel(true);
+ });
+ }];
+
+ progress.totalUnitCount = download->GetTotalBytes();
+ progress.completedUnitCount = download->GetReceivedBytes();
+
+ [progress publish];
+
+ download->SetUserData(&kCrNSProgressUserDataKey,
+ new CrNSProgressUserData(progress, destination_path));
+}
+
+void UpdateNSProgress(content::DownloadItem* download,
+ CrNSProgressUserData* progress_data) {
+ NSProgress* progress = progress_data->progress();
+ progress.totalUnitCount = download->GetTotalBytes();
+ progress.completedUnitCount = download->GetReceivedBytes();
+
+ FilePath download_path = download->GetFullPath();
+ if (progress_data->target() != download_path) {
+ progress_data->setTarget(download_path);
+ NSURL* download_url = [NSURL fileURLWithPath:
+ base::mac::FilePathToNSString(download_path)];
+ [progress setUserInfoObject:download_url
+ forKey:ProgressString(kNSProgressFileURLKey)];
+ }
+}
+
+void DestroyNSProgress(content::DownloadItem* download,
+ CrNSProgressUserData* progress_data) {
+ NSProgress* progress = progress_data->progress();
+ [progress unpublish];
+
+ download->RemoveUserData(&kCrNSProgressUserDataKey);
+}
+
+} // namespace
+
+void DownloadStatusUpdater::UpdateAppIconDownloadProgress(
+ content::DownloadItem* download) {
+
+ // Always update overall progress.
+
+ float progress = 0;
+ int download_count = 0;
+ bool progress_known = GetProgress(&progress, &download_count);
+ UpdateAppIcon(download_count, progress_known, progress);
+
+ // Update NSProgress-based indicators.
+
+ if (NSProgressSupported()) {
+ CrNSProgressUserData* progress_data = static_cast<CrNSProgressUserData*>(
+ download->GetUserData(&kCrNSProgressUserDataKey));
+ if (!progress_data)
+ CreateNSProgress(download);
+ else
+ UpdateNSProgress(download, progress_data);
+
+ if (download->GetState() != content::DownloadItem::IN_PROGRESS)
+ DestroyNSProgress(download, progress_data);
+ }
+
+ // Handle downloads that ended.
+ if (download->GetState() != content::DownloadItem::IN_PROGRESS) {
+ NSString* download_path =
+ base::mac::FilePathToNSString(download->GetFullPath());
+ if (download->GetState() == content::DownloadItem::COMPLETE) {
+ // Bounce the dock icon.
+ [[NSDistributedNotificationCenter defaultCenter]
+ postNotificationName:@"com.apple.DownloadFileFinished"
+ object:download_path];
+ }
+
+ // Notify the Finder.
+ NSString* parent_path = [download_path stringByDeletingLastPathComponent];
+ FNNotifyByPath(
+ reinterpret_cast<const UInt8*>([parent_path fileSystemRepresentation]),
+ kFNDirectoryModifiedMessage,
+ kNilOptions);
+ }
+}
diff --git a/chrome/browser/download/download_status_updater_unittest.cc b/chrome/browser/download/download_status_updater_unittest.cc
index 6cc7ec03..7a36124 100644
--- a/chrome/browser/download/download_status_updater_unittest.cc
+++ b/chrome/browser/download/download_status_updater_unittest.cc
@@ -13,7 +13,6 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-
using ::testing::AtLeast;
using ::testing::Mock;
using ::testing::Return;
@@ -22,10 +21,26 @@ using ::testing::StrictMock;
using ::testing::_;
class TestDownloadStatusUpdater : public DownloadStatusUpdater {
+ public:
+ TestDownloadStatusUpdater() : notification_count_(0),
+ acceptable_notification_item_(NULL) {
+ }
+ void SetAcceptableNotificationItem(content::DownloadItem* item) {
+ acceptable_notification_item_ = item;
+ }
+ size_t NotificationCount() {
+ return notification_count_;
+ }
protected:
- virtual void UpdateAppIconDownloadProgress() OVERRIDE {
- return;
+ virtual void UpdateAppIconDownloadProgress(
+ content::DownloadItem* download) OVERRIDE {
+ ++notification_count_;
+ if (acceptable_notification_item_)
+ EXPECT_EQ(acceptable_notification_item_, download);
}
+ private:
+ size_t notification_count_;
+ content::DownloadItem* acceptable_notification_item_;
};
class DownloadStatusUpdaterTest : public testing::Test {
@@ -120,13 +135,16 @@ class DownloadStatusUpdaterTest : public testing::Test {
}
// Set return values relevant to |DownloadStatusUpdater::GetProgress()|
- // for the specified item
+ // for the specified item.
void SetItemValues(int manager_index, int item_index,
- int received_bytes, int total_bytes) {
- EXPECT_CALL(*Item(manager_index, item_index), GetReceivedBytes())
+ int received_bytes, int total_bytes, bool notify) {
+ content::MockDownloadItem* item(Item(manager_index, item_index));
+ EXPECT_CALL(*item, GetReceivedBytes())
.WillRepeatedly(Return(received_bytes));
- EXPECT_CALL(*Item(manager_index, item_index), GetTotalBytes())
+ EXPECT_CALL(*item, GetTotalBytes())
.WillRepeatedly(Return(total_bytes));
+ if (notify)
+ updater_->OnDownloadUpdated(item);
}
// Transition specified item to completed.
@@ -157,7 +175,7 @@ class DownloadStatusUpdaterTest : public testing::Test {
// Pointer so we can verify that destruction triggers appropriate
// changes.
- DownloadStatusUpdater *updater_;
+ TestDownloadStatusUpdater *updater_;
// Thread so that the DownloadManager (which is a DeleteOnUIThread
// object) can be deleted.
@@ -198,9 +216,9 @@ TEST_F(DownloadStatusUpdaterTest, OneManagerManyItems) {
LinkManager(0);
// Prime items
- SetItemValues(0, 0, 10, 20);
- SetItemValues(0, 1, 50, 60);
- SetItemValues(0, 2, 90, 90);
+ SetItemValues(0, 0, 10, 20, false);
+ SetItemValues(0, 1, 50, 60, false);
+ SetItemValues(0, 2, 90, 90, false);
float progress = -1;
int download_count = -1;
@@ -218,13 +236,46 @@ TEST_F(DownloadStatusUpdaterTest, OneManagerManyItems) {
// Add a new item to manager and confirm progress is updated properly.
AddItems(0, 1, 1);
updater_->ModelChanged(Manager(0));
- SetItemValues(0, 3, 150, 200);
+ SetItemValues(0, 3, 150, 200, false);
EXPECT_TRUE(updater_->GetProgress(&progress, &download_count));
EXPECT_FLOAT_EQ((50+150)/(60+200.0f), progress);
EXPECT_EQ(2, download_count);
}
+// Test to ensure that the download progress notification is called correctly.
+TEST_F(DownloadStatusUpdaterTest, ProgressNotification) {
+ size_t expected_notifications = updater_->NotificationCount();
+ SetupManagers(1);
+ AddItems(0, 2, 2);
+ LinkManager(0);
+
+ // Expect two notifications, one for each item; which item will come first
+ // isn't defined so it cannot be tested.
+ expected_notifications += 2;
+ ASSERT_EQ(expected_notifications, updater_->NotificationCount());
+
+ // Make progress on the first item.
+ updater_->SetAcceptableNotificationItem(Item(0, 0));
+ SetItemValues(0, 0, 10, 20, true);
+ ++expected_notifications;
+ ASSERT_EQ(expected_notifications, updater_->NotificationCount());
+
+ // Second item completes!
+ updater_->SetAcceptableNotificationItem(Item(0, 1));
+ CompleteItem(0, 1);
+ ++expected_notifications;
+ ASSERT_EQ(expected_notifications, updater_->NotificationCount());
+
+ // First item completes.
+ updater_->SetAcceptableNotificationItem(Item(0, 0));
+ CompleteItem(0, 0);
+ ++expected_notifications;
+ ASSERT_EQ(expected_notifications, updater_->NotificationCount());
+
+ updater_->SetAcceptableNotificationItem(NULL);
+}
+
// Confirm we recognize the situation where we have an unknown size.
TEST_F(DownloadStatusUpdaterTest, UnknownSize) {
SetupManagers(1);
@@ -232,8 +283,8 @@ TEST_F(DownloadStatusUpdaterTest, UnknownSize) {
LinkManager(0);
// Prime items
- SetItemValues(0, 0, 10, 20);
- SetItemValues(0, 1, 50, -1);
+ SetItemValues(0, 0, 10, 20, false);
+ SetItemValues(0, 1, 50, -1, false);
float progress = -1;
int download_count = -1;
@@ -276,9 +327,9 @@ TEST_F(DownloadStatusUpdaterTest, ManyManagersMixedItems) {
AddItems(1, 3, 1);
LinkManager(1);
- SetItemValues(0, 0, 10, 20);
- SetItemValues(0, 1, 50, 60);
- SetItemValues(1, 0, 80, 90);
+ SetItemValues(0, 0, 10, 20, false);
+ SetItemValues(0, 1, 50, 60, false);
+ SetItemValues(1, 0, 80, 90, false);
float progress = -1;
int download_count = -1;
diff --git a/chrome/browser/download/download_status_updater_win.cc b/chrome/browser/download/download_status_updater_win.cc
new file mode 100644
index 0000000..3e28d6f
--- /dev/null
+++ b/chrome/browser/download/download_status_updater_win.cc
@@ -0,0 +1,123 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/download/download_status_updater.h"
+
+#include <string>
+#include <shobjidl.h>
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "base/string_number_conversions.h"
+#include "base/win/metro.h"
+#include "base/win/scoped_comptr.h"
+#include "base/win/windows_version.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "googleurl/src/gurl.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+
+// This code doesn't compile with Aura on. TODO(avi): hook it up so that
+// win_aura can do platform integration.
+#if !defined(USE_AURA)
+
+namespace {
+
+const char kDownloadNotificationPrefix[] = "DownloadNotification";
+int g_next_notification_id = 0;
+
+void UpdateTaskbarProgressBar(int download_count,
+ bool progress_known,
+ float progress) {
+ // Taskbar progress bar is only supported on Win7.
+ if (base::win::GetVersion() < base::win::VERSION_WIN7)
+ return;
+
+ base::win::ScopedComPtr<ITaskbarList3> taskbar;
+ HRESULT result = taskbar.CreateInstance(CLSID_TaskbarList, NULL,
+ CLSCTX_INPROC_SERVER);
+ if (FAILED(result)) {
+ VLOG(1) << "Failed creating a TaskbarList object: " << result;
+ return;
+ }
+
+ result = taskbar->HrInit();
+ if (FAILED(result)) {
+ LOG(ERROR) << "Failed initializing an ITaskbarList3 interface.";
+ return;
+ }
+
+ // Iterate through all the browser windows, and draw the progress bar.
+ for (BrowserList::const_iterator browser_iterator = BrowserList::begin();
+ browser_iterator != BrowserList::end(); browser_iterator++) {
+ Browser* browser = *browser_iterator;
+ BrowserWindow* window = browser->window();
+ if (!window)
+ continue;
+ HWND frame = window->GetNativeWindow();
+ if (download_count == 0 || progress == 1.0f)
+ taskbar->SetProgressState(frame, TBPF_NOPROGRESS);
+ else if (!progress_known)
+ taskbar->SetProgressState(frame, TBPF_INDETERMINATE);
+ else
+ taskbar->SetProgressValue(frame, static_cast<int>(progress * 100), 100);
+ }
+}
+
+} // namespace
+
+void DownloadStatusUpdater::UpdateAppIconDownloadProgress(
+ content::DownloadItem* download) {
+
+ // Always update overall progress.
+
+ float progress = 0;
+ int download_count = 0;
+ bool progress_known = GetProgress(&progress, &download_count);
+ UpdateTaskbarProgressBar(download_count, progress_known, progress);
+
+ // Fire notifications when downloads complete.
+
+ if (!base::win::IsMetroProcess())
+ return;
+
+ if (download->GetState() != content::DownloadItem::COMPLETE)
+ return;
+
+ if (download->GetOpenWhenComplete() ||
+ download->ShouldOpenFileBasedOnExtension() ||
+ download->IsTemporary() ||
+ download->GetAutoOpened())
+ return;
+
+ // In Windows 8 metro mode display a metro style notification which
+ // informs the user that the download is complete.
+ HMODULE metro = base::win::GetMetroModule();
+ base::win::MetroNotification display_notification =
+ reinterpret_cast<base::win::MetroNotification>(
+ ::GetProcAddress(metro, "DisplayNotification"));
+ DCHECK(display_notification);
+ if (display_notification) {
+ string16 title = l10n_util::GetStringUTF16(
+ IDS_METRO_DOWNLOAD_COMPLETE_NOTIFICATION_TITLE);
+ string16 body = l10n_util::GetStringUTF16(
+ IDS_METRO_DOWNLOAD_COMPLETE_NOTIFICATION);
+
+ // Dummy notification id. Every metro style notification needs a
+ // unique notification id.
+ std::string notification_id = kDownloadNotificationPrefix;
+ notification_id += base::IntToString(g_next_notification_id++);
+
+ display_notification(download->GetURL().spec().c_str(),
+ "",
+ title.c_str(),
+ body.c_str(),
+ L"",
+ notification_id.c_str());
+ }
+}
+
+#endif // !USE_AURA
diff --git a/chrome/browser/download/download_util.cc b/chrome/browser/download/download_util.cc
index b5a6a2e..7b940aa 100644
--- a/chrome/browser/download/download_util.cc
+++ b/chrome/browser/download/download_util.cc
@@ -27,8 +27,6 @@
#include "chrome/browser/download/download_extensions.h"
#include "chrome/browser/download/download_item_model.h"
#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_window.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/time_format.h"
@@ -52,12 +50,6 @@
#include "ui/gfx/image/image.h"
#include "ui/gfx/rect.h"
-#if defined(OS_WIN)
-#include <shobjidl.h>
-
-#include "base/win/windows_version.h"
-#endif
-
#if defined(TOOLKIT_VIEWS)
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/dragdrop/drag_utils.h"
@@ -68,12 +60,9 @@
#if defined(TOOLKIT_GTK)
#include "chrome/browser/ui/gtk/custom_drag.h"
-#include "chrome/browser/ui/gtk/unity_service.h"
#endif // defined(TOOLKIT_GTK)
#if defined(OS_WIN) && !defined(USE_AURA)
-#include "base/win/scoped_comptr.h"
-#include "chrome/browser/ui/browser_list.h"
#include "ui/base/dragdrop/drag_source.h"
#include "ui/base/dragdrop/os_exchange_data_provider_win.h"
#endif
@@ -554,53 +543,6 @@ string16 GetProgressStatusText(DownloadItem* download) {
speed_text, amount, time_remaining);
}
-#if !defined(OS_MACOSX)
-void UpdateAppIconDownloadProgress(int download_count,
- bool progress_known,
- float progress) {
-#if defined(USE_AURA)
- // TODO(davemoore) Implement once UX for download is decided <104742>
-#elif defined(OS_WIN)
- // Taskbar progress bar is only supported on Win7.
- if (base::win::GetVersion() < base::win::VERSION_WIN7)
- return;
-
- base::win::ScopedComPtr<ITaskbarList3> taskbar;
- HRESULT result = taskbar.CreateInstance(CLSID_TaskbarList, NULL,
- CLSCTX_INPROC_SERVER);
- if (FAILED(result)) {
- VLOG(1) << "Failed creating a TaskbarList object: " << result;
- return;
- }
-
- result = taskbar->HrInit();
- if (FAILED(result)) {
- LOG(ERROR) << "Failed initializing an ITaskbarList3 interface.";
- return;
- }
-
- // Iterate through all the browser windows, and draw the progress bar.
- for (BrowserList::const_iterator browser_iterator = BrowserList::begin();
- browser_iterator != BrowserList::end(); browser_iterator++) {
- Browser* browser = *browser_iterator;
- BrowserWindow* window = browser->window();
- if (!window)
- continue;
- HWND frame = window->GetNativeWindow();
- if (download_count == 0 || progress == 1.0f)
- taskbar->SetProgressState(frame, TBPF_NOPROGRESS);
- else if (!progress_known)
- taskbar->SetProgressState(frame, TBPF_INDETERMINATE);
- else
- taskbar->SetProgressValue(frame, static_cast<int>(progress * 100), 100);
- }
-#elif defined(TOOLKIT_GTK)
- unity::SetDownloadCount(download_count);
- unity::SetProgressFraction(progress);
-#endif
-}
-#endif
-
FilePath GetCrDownloadPath(const FilePath& suggested_path) {
return FilePath(suggested_path.value() + FILE_PATH_LITERAL(".crdownload"));
}
diff --git a/chrome/browser/download/download_util.h b/chrome/browser/download/download_util.h
index cb1bdac..ddbfba8 100644
--- a/chrome/browser/download/download_util.h
+++ b/chrome/browser/download/download_util.h
@@ -138,15 +138,6 @@ base::DictionaryValue* CreateDownloadItemValue(content::DownloadItem* download,
// Get the localized status text for an in-progress download.
string16 GetProgressStatusText(content::DownloadItem* download);
-// Update the application icon to indicate overall download progress.
-// |download_count| is the number of downloads currently in progress. If
-// |progress_known| is false, then at least one download is of indeterminate
-// size and |progress| is invalid, otherwise |progress| indicates the overall
-// download progress (float value from 0..1).
-void UpdateAppIconDownloadProgress(int download_count,
- bool progress_known,
- float progress);
-
// Returns a .crdownload intermediate path for the |suggested_path|.
FilePath GetCrDownloadPath(const FilePath& suggested_path);
diff --git a/chrome/browser/ui/cocoa/download/download_item_mac.mm b/chrome/browser/ui/cocoa/download/download_item_mac.mm
index 3a622b4..741575b 100644
--- a/chrome/browser/ui/cocoa/download/download_item_mac.mm
+++ b/chrome/browser/ui/cocoa/download/download_item_mac.mm
@@ -8,7 +8,6 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/download/download_item_model.h"
#import "chrome/browser/ui/cocoa/download/download_item_controller.h"
-#include "chrome/browser/ui/cocoa/download/download_util_mac.h"
#include "content/public/browser/download_item.h"
#include "ui/gfx/image/image.h"
@@ -51,7 +50,6 @@ void DownloadItemMac::OnDownloadUpdated(content::DownloadItem* download) {
[item_controller_ remove]; // We're deleted now!
return;
}
- download_util::NotifySystemOfDownloadComplete(download->GetFullPath());
// fall through
case DownloadItem::IN_PROGRESS:
case DownloadItem::CANCELLED:
diff --git a/chrome/browser/ui/cocoa/download/download_util_mac.h b/chrome/browser/ui/cocoa/download/download_util_mac.h
index 5fe53d4..968f1a1c 100644
--- a/chrome/browser/ui/cocoa/download/download_util_mac.h
+++ b/chrome/browser/ui/cocoa/download/download_util_mac.h
@@ -15,10 +15,6 @@ namespace download_util {
void AddFileToPasteboard(NSPasteboard* pasteboard, const FilePath& path);
-// Notify the system that a download completed. This will cause the download
-// folder in the dock to bounce.
-void NotifySystemOfDownloadComplete(const FilePath& path);
-
} // namespace download_util
#endif // CHROME_BROWSER_UI_COCOA_DOWNLOAD_DOWNLOAD_UTIL_MAC_H_
diff --git a/chrome/browser/ui/cocoa/download/download_util_mac.mm b/chrome/browser/ui/cocoa/download/download_util_mac.mm
index 17e4826b..fe56ebd 100644
--- a/chrome/browser/ui/cocoa/download/download_util_mac.mm
+++ b/chrome/browser/ui/cocoa/download/download_util_mac.mm
@@ -7,7 +7,6 @@
#include "chrome/browser/ui/cocoa/download/download_util_mac.h"
#include "base/sys_string_conversions.h"
-#import "chrome/browser/ui/cocoa/dock_icon.h"
#include "content/public/browser/download_item.h"
#include "content/public/browser/download_manager.h"
#include "ui/gfx/image/image.h"
@@ -26,19 +25,6 @@ void AddFileToPasteboard(NSPasteboard* pasteboard, const FilePath& path) {
[pasteboard setPropertyList:fileList forType:NSFilenamesPboardType];
}
-void NotifySystemOfDownloadComplete(const FilePath& path) {
- NSString* filePath = base::SysUTF8ToNSString(path.value());
- [[NSDistributedNotificationCenter defaultCenter]
- postNotificationName:@"com.apple.DownloadFileFinished"
- object:filePath];
-
- NSString* parentPath = [filePath stringByDeletingLastPathComponent];
- FNNotifyByPath(
- reinterpret_cast<const UInt8*>([parentPath fileSystemRepresentation]),
- kFNDirectoryModifiedMessage,
- kNilOptions);
-}
-
void DragDownload(const DownloadItem* download,
gfx::Image* icon,
gfx::NativeView view) {
@@ -69,14 +55,4 @@ void DragDownload(const DownloadItem* download,
slideBack:YES];
}
-void UpdateAppIconDownloadProgress(int download_count,
- bool progress_known,
- float progress) {
- DockIcon* dock_icon = [DockIcon sharedDockIcon];
- [dock_icon setDownloads:download_count];
- [dock_icon setIndeterminate:!progress_known];
- [dock_icon setProgress:progress];
- [dock_icon updateIcon];
-}
-
} // namespace download_util
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index dbff421..630befd 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -1027,8 +1027,6 @@
'browser/download/chrome_download_manager_delegate.h',
'browser/download/download_completion_blocker.cc',
'browser/download/download_completion_blocker.h',
- 'browser/download/download_completion_observer_win.cc',
- 'browser/download/download_completion_observer_win.h',
'browser/download/download_crx_util.cc',
'browser/download/download_crx_util.h',
'browser/download/download_crx_util_android.cc',
@@ -1067,6 +1065,9 @@
'browser/download/download_resource_throttle.h',
'browser/download/download_status_updater.cc',
'browser/download/download_status_updater.h',
+ 'browser/download/download_status_updater_gtk.cc',
+ 'browser/download/download_status_updater_mac.mm',
+ 'browser/download/download_status_updater_win.cc',
'browser/download/download_util.cc',
'browser/download/download_util.h',
'browser/download/save_package_file_picker.cc',