Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(133)

Side by Side Diff: chrome/browser/download/download_status_updater_mac.mm

Issue 10827207: Mountain Lion: use the system download progress. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase only Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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 "base/mac/foundation_util.h"
8 #include "base/memory/scoped_nsobject.h"
9 #include "base/supports_user_data.h"
10 #include "base/sys_string_conversions.h"
11 #include "content/public/browser/download_item.h"
12 #include "googleurl/src/gurl.h"
13
14 // --- Private 10.8 API for showing progress ---
15 // rdar://12058866 http://www.openradar.me/12058866
16
17 namespace {
18
19 NSString* const kNSProgressAppBundleIdentifierKey =
20 @"NSProgressAppBundleIdentifierKey";
21 NSString* const kNSProgressEstimatedTimeKey =
22 @"NSProgressEstimatedTimeKey";
23 NSString* const kNSProgressFileCompletedCountKey =
24 @"NSProgressFileCompletedCountKey";
25 NSString* const kNSProgressFileContainerURLKey =
26 @"NSProgressFileContainerURLKey";
27 NSString* const kNSProgressFileDownloadingSourceURLKey =
28 @"NSProgressFileDownloadingSourceURLKey";
29 NSString* const kNSProgressFileIconKey =
30 @"NSProgressFileIconKey";
31 NSString* const kNSProgressFileIconOriginalRectKey =
32 @"NSProgressFileIconOriginalRectKey";
33 NSString* const kNSProgressFileLocationCanChangeKey =
34 @"NSProgressFileLocationCanChangeKey";
35 NSString* const kNSProgressFileOperationKindAirDropping =
36 @"NSProgressFileOperationKindAirDropping";
37 NSString* const kNSProgressFileOperationKindCopying =
38 @"NSProgressFileOperationKindCopying";
39 NSString* const kNSProgressFileOperationKindDecompressingAfterDownloading =
40 @"NSProgressFileOperationKindDecompressingAfterDownloading";
41 NSString* const kNSProgressFileOperationKindDownloading =
42 @"NSProgressFileOperationKindDownloading";
43 NSString* const kNSProgressFileOperationKindEncrypting =
44 @"NSProgressFileOperationKindEncrypting";
45 NSString* const kNSProgressFileOperationKindKey =
46 @"NSProgressFileOperationKindKey";
47 NSString* const kNSProgressFileTotalCountKey =
48 @"NSProgressFileTotalCountKey";
49 NSString* const kNSProgressFileURLKey =
50 @"NSProgressFileURLKey";
51 NSString* const kNSProgressIsWaitingKey =
52 @"NSProgressIsWaitingKey";
53 NSString* const kNSProgressKindFile =
54 @"NSProgressKindFile";
55 NSString* const kNSProgressThroughputKey =
56 @"NSProgressThroughputKey";
57
58 NSString* ProgressString(NSString* string) {
59 static NSMutableDictionary* cache;
60 static CFBundleRef foundation;
61 if (!cache) {
62 cache = [[NSMutableDictionary alloc] init];
63 foundation = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.Foundation"));
64 }
65
66 NSString* result = [cache objectForKey:string];
67 if (!result) {
68 NSString** ref = static_cast<NSString**>(
69 CFBundleGetDataPointerForName(foundation,
70 base::mac::NSToCFCast(string)));
71 if (ref) {
72 result = *ref;
73 [cache setObject:result forKey:string];
74 }
75 }
76
77 return result;
78 }
79
80 } // namespace
81
82 @interface NSProgress : NSObject
83
84 - (id)initWithParent:(id)parent userInfo:(NSDictionary*)info;
85 @property(copy) NSString* kind;
86
87 - (void)unpublish;
88 - (void)publish;
89
90 - (void)setUserInfoObject:(id)object forKey:(NSString*)key;
91 - (NSDictionary*)userInfo;
92
93 @property(readonly) double fractionCompleted;
94 // Set the totalUnitCount to -1 to indicate an indeterminate download. The dock
95 // shows a non-filling progress bar; the Finder is lame and draws its progress
96 // bar off the right side.
97 @property(readonly, getter=isIndeterminate) BOOL indeterminate;
98 @property long long completedUnitCount;
99 @property long long totalUnitCount;
100
101 // Pausing appears to be unimplemented in 10.8.0.
102 - (void)pause;
103 @property(readonly, getter=isPaused) BOOL paused;
104 @property(getter=isPausable) BOOL pausable;
105 - (void)setPausingHandler:(id)blockOfUnknownSignature;
106
107 - (void)cancel;
108 @property(readonly, getter=isCancelled) BOOL cancelled;
109 @property(getter=isCancellable) BOOL cancellable;
110 // Note that the cancellation handler block will be called on a random thread.
111 - (void)setCancellationHandler:(void (^)())block;
112
113 // Allows other applications to provide feedback as to whether the progress is
114 // visible in that app. Note that the acknowledgement handler block will be
115 // called on a random thread.
116 // com.apple.dock => BOOL indicating whether the download target folder was
117 // successfully "flown to" at the beginning of the download.
118 // This primarily depends on whether the download target
119 // folder is in the dock. Note that if the download target
120 // folder is added or removed from the dock during the
121 // duration of the download, it will not trigger a callback.
122 // Note that if the "fly to the dock" keys were not set, the
123 // callback's parameter will always be NO.
124 // com.apple.Finder => always YES, no matter whether the download target
125 // folder's window is open.
126 - (void)handleAcknowledgementByAppWithBundleIdentifier:(NSString*)bundle
127 usingBlock:(void (^)(BOOL success))block;
128
129 @end
130
131 // --- Private 10.8 API for showing progress ---
132
133 namespace {
134
135 bool NSProgressSupported() {
136 static bool supported;
137 static bool valid;
138 if (!valid) {
139 supported = NSClassFromString(@"NSProgress");
140 valid = true;
141 }
142
143 return supported;
144 }
145
146 const char kCrNSProgressUserDataKey[] = "CrNSProgressUserData";
147
148 class CrNSProgressUserData : public base::SupportsUserData::Data {
149 public:
150 CrNSProgressUserData(NSProgress* progress, const FilePath& target)
151 : target_(target) {
152 progress_.reset(progress);
153 }
154 virtual ~CrNSProgressUserData() {}
155
156 NSProgress* progress() const { return progress_.get(); }
157 FilePath target() const { return target_; }
158 void setTarget(const FilePath& target) { target_ = target; }
159
160 private:
161 scoped_nsobject<NSProgress> progress_;
162 FilePath target_;
163 };
164
165 } // namespace
166
167 void DownloadStatusUpdater::UpdateDownloadProgressForItemStarted(
168 content::DownloadItem* download) {
169 if (!NSProgressSupported())
170 return;
171
172 NSURL* source_url = [NSURL URLWithString:
173 base::SysUTF8ToNSString(download->GetURL().spec())];
174 FilePath destination_path = download->GetFullPath();
175 NSURL* destination_url = [NSURL fileURLWithPath:
176 base::mac::FilePathToNSString(destination_path)];
177
178 // If there were an image to fly to the download folder in the dock, then
179 // the keys in the userInfo to set would be:
180 // - @"NSProgressFlyToImageKey" : NSImage
181 // - kNSProgressFileIconOriginalRectKey : NSValue of NSRect in global coords
182
183 NSDictionary* user_info = @{
184 ProgressString(kNSProgressFileDownloadingSourceURLKey) : source_url,
185 ProgressString(kNSProgressFileLocationCanChangeKey) : @true,
186 ProgressString(kNSProgressFileOperationKindKey) :
187 ProgressString(kNSProgressFileOperationKindDownloading),
188 ProgressString(kNSProgressFileURLKey) : destination_url
189 };
190 Class progress_class = NSClassFromString(@"NSProgress");
191 NSProgress* progress = [progress_class performSelector:@selector(alloc)];
192 progress = [progress performSelector:@selector(initWithParent:userInfo:)
193 withObject:nil
194 withObject:user_info];
195 progress.kind = ProgressString(kNSProgressKindFile);
196
197 progress.pausable = NO;
198 progress.cancellable = YES;
199 [progress setCancellationHandler:^{
200 dispatch_async(dispatch_get_main_queue(), ^{
201 download->Cancel(true);
202 });
203 }];
204
205 progress.totalUnitCount = download->GetTotalBytes();
206 progress.completedUnitCount = download->GetReceivedBytes();
207
208 [progress publish];
209
210 download->SetUserData(&kCrNSProgressUserDataKey,
211 new CrNSProgressUserData(progress, destination_path));
212 }
213
214 void DownloadStatusUpdater::UpdateDownloadProgressForItemProgressed(
215 content::DownloadItem* download) {
216 if (!NSProgressSupported())
217 return;
218
219 CrNSProgressUserData* progress_data = static_cast<CrNSProgressUserData*>(
220 download->GetUserData(&kCrNSProgressUserDataKey));
221 if (!progress_data)
222 return;
223
224 NSProgress* progress = progress_data->progress();
225 progress.totalUnitCount = download->GetTotalBytes();
226 progress.completedUnitCount = download->GetReceivedBytes();
227
228 FilePath download_path = download->GetFullPath();
229 if (progress_data->target() != download_path) {
230 progress_data->setTarget(download_path);
231 NSURL* download_url = [NSURL fileURLWithPath:
232 base::mac::FilePathToNSString(download_path)];
233 [progress setUserInfoObject:download_url
234 forKey:ProgressString(kNSProgressFileURLKey)];
235 }
236 }
237
238 void DownloadStatusUpdater::UpdateDownloadProgressForItemCompleted(
239 content::DownloadItem* download) {
240 // Bounce the dock icon.
241 NSString* download_path =
242 base::mac::FilePathToNSString(download->GetFullPath());
243 [[NSDistributedNotificationCenter defaultCenter]
244 postNotificationName:@"com.apple.DownloadFileFinished"
245 object:download_path];
246
247 // Notify the Finder.
248 NSString* parent_path = [download_path stringByDeletingLastPathComponent];
249 FNNotifyByPath(
250 reinterpret_cast<const UInt8*>([parent_path fileSystemRepresentation]),
251 kFNDirectoryModifiedMessage,
252 kNilOptions);
253
254 // Clean up 10.8 NSProgress stuff.
255 if (!NSProgressSupported())
256 return;
257
258 CrNSProgressUserData* progress_data = static_cast<CrNSProgressUserData*>(
259 download->GetUserData(&kCrNSProgressUserDataKey));
260 if (!progress_data)
261 return;
262
263 NSProgress* progress = progress_data->progress();
264 [progress unpublish];
265
266 download->RemoveUserData(&kCrNSProgressUserDataKey);
267 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698