OLD | NEW |
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "ios/chrome/browser/ui/open_in_controller.h" | 5 #import "ios/chrome/browser/ui/open_in_controller.h" |
6 | 6 |
7 #include "base/files/file_path.h" | 7 #include "base/files/file_path.h" |
8 #include "base/ios/weak_nsobject.h" | |
9 #include "base/location.h" | 8 #include "base/location.h" |
10 #include "base/logging.h" | 9 #include "base/logging.h" |
11 #import "base/mac/bind_objc_block.h" | 10 #import "base/mac/bind_objc_block.h" |
12 #include "base/mac/objc_property_releaser.h" | 11 |
13 #include "base/sequenced_task_runner.h" | 12 #include "base/sequenced_task_runner.h" |
14 #include "base/strings/sys_string_conversions.h" | 13 #include "base/strings/sys_string_conversions.h" |
15 #include "base/threading/sequenced_worker_pool.h" | 14 #include "base/threading/sequenced_worker_pool.h" |
16 #include "base/threading/thread_restrictions.h" | 15 #include "base/threading/thread_restrictions.h" |
17 #include "components/strings/grit/components_strings.h" | 16 #include "components/strings/grit/components_strings.h" |
18 #import "ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h" | 17 #import "ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h" |
19 #import "ios/chrome/browser/ui/open_in_controller_testing.h" | 18 #import "ios/chrome/browser/ui/open_in_controller_testing.h" |
20 #include "ios/chrome/browser/ui/ui_util.h" | 19 #include "ios/chrome/browser/ui/ui_util.h" |
21 #import "ios/chrome/browser/ui/uikit_ui_util.h" | 20 #import "ios/chrome/browser/ui/uikit_ui_util.h" |
22 #include "ios/chrome/grit/ios_strings.h" | 21 #include "ios/chrome/grit/ios_strings.h" |
23 #include "ios/web/public/web_thread.h" | 22 #include "ios/web/public/web_thread.h" |
24 #import "ios/web/web_state/ui/crw_web_controller.h" | 23 #import "ios/web/web_state/ui/crw_web_controller.h" |
25 #include "net/base/load_flags.h" | 24 #include "net/base/load_flags.h" |
26 #include "net/url_request/url_fetcher.h" | 25 #include "net/url_request/url_fetcher.h" |
27 #include "net/url_request/url_fetcher_delegate.h" | 26 #include "net/url_request/url_fetcher_delegate.h" |
28 #include "net/url_request/url_request_context_getter.h" | 27 #include "net/url_request/url_request_context_getter.h" |
29 #include "ui/base/l10n/l10n_util_mac.h" | 28 #include "ui/base/l10n/l10n_util_mac.h" |
30 #import "ui/gfx/ios/NSString+CrStringDrawing.h" | 29 #import "ui/gfx/ios/NSString+CrStringDrawing.h" |
31 #include "url/gurl.h" | 30 #include "url/gurl.h" |
32 | 31 |
| 32 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 33 #error "This file requires ARC support." |
| 34 #endif |
| 35 |
33 namespace { | 36 namespace { |
34 // The path in the temp directory containing documents that are to be opened in | 37 // The path in the temp directory containing documents that are to be opened in |
35 // other applications. | 38 // other applications. |
36 static NSString* const kDocumentsTempPath = @"OpenIn"; | 39 static NSString* const kDocumentsTempPath = @"OpenIn"; |
37 | 40 |
38 static const int kHTTPResponseCodeSucceeded = 200; | 41 static const int kHTTPResponseCodeSucceeded = 200; |
39 | 42 |
40 // Duration of the show/hide animation for the |openInToolbar_|. | 43 // Duration of the show/hide animation for the |openInToolbar_|. |
41 const NSTimeInterval kOpenInToolbarAnimationDuration = 0.2; | 44 const NSTimeInterval kOpenInToolbarAnimationDuration = 0.2; |
42 | 45 |
(...skipping 14 matching lines...) Expand all Loading... |
57 const CGFloat kOverlayedViewLabelWidthPercentage = 0.7; | 60 const CGFloat kOverlayedViewLabelWidthPercentage = 0.7; |
58 | 61 |
59 // Bottom margin for the label displayed on the |overlayedView_|. | 62 // Bottom margin for the label displayed on the |overlayedView_|. |
60 const CGFloat kOverlayedViewLabelBottomMargin = 60; | 63 const CGFloat kOverlayedViewLabelBottomMargin = 60; |
61 | 64 |
62 } // anonymous namespace | 65 } // anonymous namespace |
63 | 66 |
64 @interface OpenInController () { | 67 @interface OpenInController () { |
65 // AlertCoordinator for showing an alert if no applications were found to open | 68 // AlertCoordinator for showing an alert if no applications were found to open |
66 // the current document. | 69 // the current document. |
67 base::scoped_nsobject<AlertCoordinator> _alertCoordinator; | 70 AlertCoordinator* _alertCoordinator; |
68 } | 71 } |
69 | 72 |
70 // URLFetcher delegate method called when |fetcher_| completes a request. | 73 // URLFetcher delegate method called when |fetcher_| completes a request. |
71 - (void)urlFetchDidComplete:(const net::URLFetcher*)source; | 74 - (void)urlFetchDidComplete:(const net::URLFetcher*)source; |
72 // Ensures the destination directory is created and any contained obsolete files | 75 // Ensures the destination directory is created and any contained obsolete files |
73 // are deleted. Returns YES if the directory is created successfully. | 76 // are deleted. Returns YES if the directory is created successfully. |
74 + (BOOL)createDestinationDirectoryAndRemoveObsoleteFiles; | 77 + (BOOL)createDestinationDirectoryAndRemoveObsoleteFiles; |
75 // Starts downloading the file at path |kDocumentsTempPath| with the name | 78 // Starts downloading the file at path |kDocumentsTempPath| with the name |
76 // |suggestedFilename_|. | 79 // |suggestedFilename_|. |
77 - (void)startDownload; | 80 - (void)startDownload; |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
142 // |OpenInController| destroys the fetcher and cancels the callback. This is | 145 // |OpenInController| destroys the fetcher and cancels the callback. This is |
143 // why |OnURLFetchComplete| will neved be called after |owner_| is disabled. | 146 // why |OnURLFetchComplete| will neved be called after |owner_| is disabled. |
144 owner_ = nil; | 147 owner_ = nil; |
145 } | 148 } |
146 | 149 |
147 protected: | 150 protected: |
148 friend base::RefCountedThreadSafe<OpenInControllerBridge>; | 151 friend base::RefCountedThreadSafe<OpenInControllerBridge>; |
149 ~OpenInControllerBridge() override {} | 152 ~OpenInControllerBridge() override {} |
150 | 153 |
151 private: | 154 private: |
152 OpenInController* owner_; // weak | 155 __weak OpenInController* owner_; |
153 }; | 156 }; |
154 | 157 |
155 @implementation OpenInController { | 158 @implementation OpenInController { |
156 // Bridge from C++ to Obj-C class. | 159 // Bridge from C++ to Obj-C class. |
157 scoped_refptr<OpenInControllerBridge> bridge_; | 160 scoped_refptr<OpenInControllerBridge> bridge_; |
158 | 161 |
159 // URL of the document. | 162 // URL of the document. |
160 GURL documentURL_; | 163 GURL documentURL_; |
161 | 164 |
162 // Controller for opening documents in other applications. | 165 // Controller for opening documents in other applications. |
163 base::scoped_nsobject<UIDocumentInteractionController> documentController_; | 166 UIDocumentInteractionController* documentController_; |
164 | 167 |
165 // Toolbar overlay to be displayed on tap. | 168 // Toolbar overlay to be displayed on tap. |
166 base::scoped_nsobject<OpenInToolbar> openInToolbar_; | 169 OpenInToolbar* openInToolbar_; |
167 | 170 |
168 // Timer used to automatically hide the |openInToolbar_| after a period. | 171 // Timer used to automatically hide the |openInToolbar_| after a period. |
169 base::scoped_nsobject<NSTimer> openInTimer_; | 172 NSTimer* openInTimer_; |
170 | 173 |
171 // Gesture recognizer to catch taps on the document. | 174 // Gesture recognizer to catch taps on the document. |
172 base::scoped_nsobject<UITapGestureRecognizer> tapRecognizer_; | 175 UITapGestureRecognizer* tapRecognizer_; |
173 | 176 |
174 // Suggested filename for the document. | 177 // Suggested filename for the document. |
175 base::scoped_nsobject<NSString> suggestedFilename_; | 178 NSString* suggestedFilename_; |
176 | 179 |
177 // Fetcher used to redownload the document and save it in the sandbox. | 180 // Fetcher used to redownload the document and save it in the sandbox. |
178 std::unique_ptr<net::URLFetcher> fetcher_; | 181 std::unique_ptr<net::URLFetcher> fetcher_; |
179 | 182 |
180 // CRWWebController used to check if the tap is not on a link and the | 183 // CRWWebController used to check if the tap is not on a link and the |
181 // |openInToolbar_| should be displayed. | 184 // |openInToolbar_| should be displayed. |
182 base::scoped_nsobject<CRWWebController> webController_; | 185 CRWWebController* webController_; |
183 | 186 |
184 // URLRequestContextGetter needed for the URLFetcher. | 187 // URLRequestContextGetter needed for the URLFetcher. |
185 scoped_refptr<net::URLRequestContextGetter> requestContext_; | 188 scoped_refptr<net::URLRequestContextGetter> requestContext_; |
186 | 189 |
187 // Spinner view displayed while the file is downloading. | 190 // Spinner view displayed while the file is downloading. |
188 base::scoped_nsobject<UIView> overlayedView_; | 191 UIView* overlayedView_; |
189 | 192 |
190 // The location where the "Open in..." menu is anchored. | 193 // The location where the "Open in..." menu is anchored. |
191 CGRect anchorLocation_; | 194 CGRect anchorLocation_; |
192 | 195 |
193 // YES if the file download was canceled. | 196 // YES if the file download was canceled. |
194 BOOL downloadCanceled_; | 197 BOOL downloadCanceled_; |
195 | 198 |
196 // YES if the OpenIn menu is displayed. | 199 // YES if the OpenIn menu is displayed. |
197 BOOL isOpenInMenuDisplayed_; | 200 BOOL isOpenInMenuDisplayed_; |
198 | 201 |
199 // YES if the toolbar is displayed. | 202 // YES if the toolbar is displayed. |
200 BOOL isOpenInToolbarDisplayed_; | 203 BOOL isOpenInToolbarDisplayed_; |
201 | 204 |
202 // Task runner on which file operations should happen. | 205 // Task runner on which file operations should happen. |
203 scoped_refptr<base::SequencedTaskRunner> sequencedTaskRunner_; | 206 scoped_refptr<base::SequencedTaskRunner> sequencedTaskRunner_; |
204 | |
205 base::mac::ObjCPropertyReleaser propertyReleaser_OpenInController_; | |
206 } | 207 } |
207 | 208 |
208 - (id)initWithRequestContext:(net::URLRequestContextGetter*)requestContext | 209 - (id)initWithRequestContext:(net::URLRequestContextGetter*)requestContext |
209 webController:(CRWWebController*)webController { | 210 webController:(CRWWebController*)webController { |
210 self = [super init]; | 211 self = [super init]; |
211 if (self) { | 212 if (self) { |
212 requestContext_ = requestContext; | 213 requestContext_ = requestContext; |
213 webController_.reset([webController retain]); | 214 webController_ = webController; |
214 tapRecognizer_.reset([[UITapGestureRecognizer alloc] | 215 tapRecognizer_ = [[UITapGestureRecognizer alloc] |
215 initWithTarget:self | 216 initWithTarget:self |
216 action:@selector(handleTapFrom:)]); | 217 action:@selector(handleTapFrom:)]; |
217 [tapRecognizer_ setDelegate:self]; | 218 [tapRecognizer_ setDelegate:self]; |
218 base::SequencedWorkerPool* pool = web::WebThread::GetBlockingPool(); | 219 base::SequencedWorkerPool* pool = web::WebThread::GetBlockingPool(); |
219 sequencedTaskRunner_ = | 220 sequencedTaskRunner_ = |
220 pool->GetSequencedTaskRunner(pool->GetSequenceToken()); | 221 pool->GetSequencedTaskRunner(pool->GetSequenceToken()); |
221 isOpenInMenuDisplayed_ = NO; | 222 isOpenInMenuDisplayed_ = NO; |
222 propertyReleaser_OpenInController_.Init(self, [OpenInController class]); | |
223 } | 223 } |
224 return self; | 224 return self; |
225 } | 225 } |
226 | 226 |
227 - (void)enableWithDocumentURL:(const GURL&)documentURL | 227 - (void)enableWithDocumentURL:(const GURL&)documentURL |
228 suggestedFilename:(NSString*)suggestedFilename { | 228 suggestedFilename:(NSString*)suggestedFilename { |
229 documentURL_ = GURL(documentURL); | 229 documentURL_ = GURL(documentURL); |
230 suggestedFilename_.reset([suggestedFilename retain]); | 230 suggestedFilename_ = suggestedFilename; |
231 [webController_ addGestureRecognizerToWebView:tapRecognizer_]; | 231 [webController_ addGestureRecognizerToWebView:tapRecognizer_]; |
232 [self openInToolbar].alpha = 0.0f; | 232 [self openInToolbar].alpha = 0.0f; |
233 [webController_ addToolbarViewToWebView:[self openInToolbar]]; | 233 [webController_ addToolbarViewToWebView:[self openInToolbar]]; |
234 [self showOpenInToolbar]; | 234 [self showOpenInToolbar]; |
235 } | 235 } |
236 | 236 |
237 - (void)disable { | 237 - (void)disable { |
238 [self openInToolbar].alpha = 0.0f; | 238 [self openInToolbar].alpha = 0.0f; |
239 [openInTimer_ invalidate]; | 239 [openInTimer_ invalidate]; |
240 if (bridge_.get()) | 240 if (bridge_.get()) |
241 bridge_->OnOwnerDisabled(); | 241 bridge_->OnOwnerDisabled(); |
242 bridge_ = nil; | 242 bridge_ = nil; |
243 [webController_ removeGestureRecognizerFromWebView:tapRecognizer_]; | 243 [webController_ removeGestureRecognizerFromWebView:tapRecognizer_]; |
244 [webController_ removeToolbarViewFromWebView:[self openInToolbar]]; | 244 [webController_ removeToolbarViewFromWebView:[self openInToolbar]]; |
245 [documentController_ dismissMenuAnimated:NO]; | 245 [documentController_ dismissMenuAnimated:NO]; |
246 [documentController_ setDelegate:nil]; | 246 [documentController_ setDelegate:nil]; |
247 documentURL_ = GURL(); | 247 documentURL_ = GURL(); |
248 suggestedFilename_.reset(); | 248 suggestedFilename_ = nil; |
249 fetcher_.reset(); | 249 fetcher_.reset(); |
250 } | 250 } |
251 | 251 |
252 - (void)detachFromWebController { | 252 - (void)detachFromWebController { |
253 [self disable]; | 253 [self disable]; |
254 // Animation blocks may be keeping this object alive; don't extend the | 254 // Animation blocks may be keeping this object alive; don't extend the |
255 // lifetime of CRWWebController. | 255 // lifetime of CRWWebController. |
256 webController_.reset(); | 256 webController_ = nil; |
257 } | 257 } |
258 | 258 |
259 - (void)dealloc { | 259 - (void)dealloc { |
260 [self disable]; | 260 [self disable]; |
261 [super dealloc]; | |
262 } | 261 } |
263 | 262 |
264 - (void)handleTapFrom:(UIGestureRecognizer*)gestureRecognizer { | 263 - (void)handleTapFrom:(UIGestureRecognizer*)gestureRecognizer { |
265 if ([gestureRecognizer state] == UIGestureRecognizerStateEnded) { | 264 if ([gestureRecognizer state] == UIGestureRecognizerStateEnded) { |
266 if (isOpenInToolbarDisplayed_) { | 265 if (isOpenInToolbarDisplayed_) { |
267 [self hideOpenInToolbar]; | 266 [self hideOpenInToolbar]; |
268 } else { | 267 } else { |
269 [self showOpenInToolbar]; | 268 [self showOpenInToolbar]; |
270 } | 269 } |
271 } | 270 } |
272 } | 271 } |
273 | 272 |
274 - (void)showOpenInToolbar { | 273 - (void)showOpenInToolbar { |
275 if ([openInTimer_ isValid]) { | 274 if ([openInTimer_ isValid]) { |
276 [openInTimer_ setFireDate:([NSDate dateWithTimeIntervalSinceNow: | 275 [openInTimer_ setFireDate:([NSDate dateWithTimeIntervalSinceNow: |
277 kOpenInToolbarDisplayDuration])]; | 276 kOpenInToolbarDisplayDuration])]; |
278 } else { | 277 } else { |
279 openInTimer_.reset( | 278 openInTimer_ = |
280 [[NSTimer scheduledTimerWithTimeInterval:kOpenInToolbarDisplayDuration | 279 [NSTimer scheduledTimerWithTimeInterval:kOpenInToolbarDisplayDuration |
281 target:self | 280 target:self |
282 selector:@selector(hideOpenInToolbar) | 281 selector:@selector(hideOpenInToolbar) |
283 userInfo:nil | 282 userInfo:nil |
284 repeats:NO] retain]); | 283 repeats:NO]; |
285 UIView* openInToolbar = [self openInToolbar]; | 284 UIView* openInToolbar = [self openInToolbar]; |
286 [UIView animateWithDuration:kOpenInToolbarAnimationDuration | 285 [UIView animateWithDuration:kOpenInToolbarAnimationDuration |
287 animations:^{ | 286 animations:^{ |
288 [openInToolbar setAlpha:1.0]; | 287 [openInToolbar setAlpha:1.0]; |
289 }]; | 288 }]; |
290 } | 289 } |
291 isOpenInToolbarDisplayed_ = YES; | 290 isOpenInToolbarDisplayed_ = YES; |
292 } | 291 } |
293 | 292 |
294 - (void)hideOpenInToolbar { | 293 - (void)hideOpenInToolbar { |
(...skipping 30 matching lines...) Expand all Loading... |
325 base::Callback<void(BOOL)> reply = base::Bind( | 324 base::Callback<void(BOOL)> reply = base::Bind( |
326 &OpenInControllerBridge::OnDestinationDirectoryCreated, bridge_); | 325 &OpenInControllerBridge::OnDestinationDirectoryCreated, bridge_); |
327 base::PostTaskAndReplyWithResult(sequencedTaskRunner_.get(), FROM_HERE, task, | 326 base::PostTaskAndReplyWithResult(sequencedTaskRunner_.get(), FROM_HERE, task, |
328 reply); | 327 reply); |
329 } | 328 } |
330 | 329 |
331 - (void)startDownload { | 330 - (void)startDownload { |
332 NSString* tempDirPath = [NSTemporaryDirectory() | 331 NSString* tempDirPath = [NSTemporaryDirectory() |
333 stringByAppendingPathComponent:kDocumentsTempPath]; | 332 stringByAppendingPathComponent:kDocumentsTempPath]; |
334 NSString* filePath = | 333 NSString* filePath = |
335 [tempDirPath stringByAppendingPathComponent:suggestedFilename_.get()]; | 334 [tempDirPath stringByAppendingPathComponent:suggestedFilename_]; |
336 | 335 |
337 // In iPad the toolbar has to be displayed to anchor the "Open in" menu. | 336 // In iPad the toolbar has to be displayed to anchor the "Open in" menu. |
338 if (!IsIPadIdiom()) | 337 if (!IsIPadIdiom()) |
339 [self hideOpenInToolbar]; | 338 [self hideOpenInToolbar]; |
340 | 339 |
341 // Show an overlayed view to indicate a download is in progress. On tap this | 340 // Show an overlayed view to indicate a download is in progress. On tap this |
342 // view can be dismissed and the download canceled. | 341 // view can be dismissed and the download canceled. |
343 [self showDownloadOverlayView]; | 342 [self showDownloadOverlayView]; |
344 downloadCanceled_ = NO; | 343 downloadCanceled_ = NO; |
345 | 344 |
(...skipping 18 matching lines...) Expand all Loading... |
364 [self removeOverlayedView]; | 363 [self removeOverlayedView]; |
365 if (IsIPadIdiom()) | 364 if (IsIPadIdiom()) |
366 [self hideOpenInToolbar]; | 365 [self hideOpenInToolbar]; |
367 downloadCanceled_ = YES; | 366 downloadCanceled_ = YES; |
368 } | 367 } |
369 | 368 |
370 - (void)removeOverlayedView { | 369 - (void)removeOverlayedView { |
371 if (!overlayedView_) | 370 if (!overlayedView_) |
372 return; | 371 return; |
373 | 372 |
374 UIView* overlayedView = overlayedView_.get(); | 373 UIView* overlayedView = overlayedView_; |
375 [UIView animateWithDuration:kOverlayViewAnimationDuration | 374 [UIView animateWithDuration:kOverlayViewAnimationDuration |
376 animations:^{ | 375 animations:^{ |
377 [overlayedView setAlpha:0.0]; | 376 [overlayedView setAlpha:0.0]; |
378 } | 377 } |
379 completion:^(BOOL finished) { | 378 completion:^(BOOL finished) { |
380 [overlayedView removeFromSuperview]; | 379 [overlayedView removeFromSuperview]; |
381 }]; | 380 }]; |
382 overlayedView_.reset(); | 381 overlayedView_ = nil; |
383 } | 382 } |
384 | 383 |
385 - (void)showErrorWithMessage:(NSString*)message { | 384 - (void)showErrorWithMessage:(NSString*)message { |
386 UIViewController* topViewController = | 385 UIViewController* topViewController = |
387 [[[UIApplication sharedApplication] keyWindow] rootViewController]; | 386 [[[UIApplication sharedApplication] keyWindow] rootViewController]; |
388 | 387 |
389 _alertCoordinator.reset([[AlertCoordinator alloc] | 388 _alertCoordinator = |
390 initWithBaseViewController:topViewController | 389 [[AlertCoordinator alloc] initWithBaseViewController:topViewController |
391 title:nil | 390 title:nil |
392 message:message]); | 391 message:message]; |
393 | 392 |
394 [_alertCoordinator addItemWithTitle:l10n_util::GetNSString(IDS_OK) | 393 [_alertCoordinator addItemWithTitle:l10n_util::GetNSString(IDS_OK) |
395 action:nil | 394 action:nil |
396 style:UIAlertActionStyleDefault]; | 395 style:UIAlertActionStyleDefault]; |
397 | 396 |
398 [_alertCoordinator start]; | 397 [_alertCoordinator start]; |
399 } | 398 } |
400 | 399 |
401 - (void)presentOpenInMenuForFileAtURL:(NSURL*)fileURL { | 400 - (void)presentOpenInMenuForFileAtURL:(NSURL*)fileURL { |
402 if (!webController_) | 401 if (!webController_) |
403 return; | 402 return; |
404 | 403 |
405 if (requestContext_.get()) { | 404 if (requestContext_.get()) { |
406 // |requestContext_| is nil only if this is called from a unit test, in | 405 // |requestContext_| is nil only if this is called from a unit test, in |
407 // which case the |documentController_| was set already. | 406 // which case the |documentController_| was set already. |
408 documentController_.reset([[UIDocumentInteractionController | 407 documentController_ = |
409 interactionControllerWithURL:fileURL] retain]); | 408 [UIDocumentInteractionController interactionControllerWithURL:fileURL]; |
410 } | 409 } |
411 | 410 |
412 // TODO(cgrigoruta): The UTI is hardcoded for now, change this when we add | 411 // TODO(cgrigoruta): The UTI is hardcoded for now, change this when we add |
413 // support for other file types as well. | 412 // support for other file types as well. |
414 [documentController_ setUTI:@"com.adobe.pdf"]; | 413 [documentController_ setUTI:@"com.adobe.pdf"]; |
415 [documentController_ setDelegate:self]; | 414 [documentController_ setDelegate:self]; |
416 BOOL success = | 415 BOOL success = |
417 [documentController_ presentOpenInMenuFromRect:anchorLocation_ | 416 [documentController_ presentOpenInMenuFromRect:anchorLocation_ |
418 inView:[webController_ view] | 417 inView:[webController_ view] |
419 animated:YES]; | 418 animated:YES]; |
420 if (requestContext_.get()) { | 419 if (requestContext_.get()) { |
421 [self removeOverlayedView]; | 420 [self removeOverlayedView]; |
422 if (!success) { | 421 if (!success) { |
423 if (IsIPadIdiom()) | 422 if (IsIPadIdiom()) |
424 [self hideOpenInToolbar]; | 423 [self hideOpenInToolbar]; |
425 NSString* errorMessage = | 424 NSString* errorMessage = |
426 l10n_util::GetNSStringWithFixup(IDS_IOS_OPEN_IN_NO_APPS_REGISTERED); | 425 l10n_util::GetNSStringWithFixup(IDS_IOS_OPEN_IN_NO_APPS_REGISTERED); |
427 [self showErrorWithMessage:errorMessage]; | 426 [self showErrorWithMessage:errorMessage]; |
428 } else { | 427 } else { |
429 isOpenInMenuDisplayed_ = YES; | 428 isOpenInMenuDisplayed_ = YES; |
430 } | 429 } |
431 } | 430 } |
432 } | 431 } |
433 | 432 |
434 - (void)showDownloadOverlayView { | 433 - (void)showDownloadOverlayView { |
435 UIViewController* topViewController = | 434 UIViewController* topViewController = |
436 [[[UIApplication sharedApplication] keyWindow] rootViewController]; | 435 [[[UIApplication sharedApplication] keyWindow] rootViewController]; |
437 UIView* topView = topViewController.view; | 436 UIView* topView = topViewController.view; |
438 overlayedView_.reset([[UIView alloc] initWithFrame:[topView bounds]]); | 437 overlayedView_ = [[UIView alloc] initWithFrame:[topView bounds]]; |
439 [overlayedView_ setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | | 438 [overlayedView_ setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | |
440 UIViewAutoresizingFlexibleHeight)]; | 439 UIViewAutoresizingFlexibleHeight)]; |
441 base::scoped_nsobject<UIView> grayBackgroundView( | 440 UIView* grayBackgroundView = |
442 [[UIView alloc] initWithFrame:[overlayedView_ frame]]); | 441 [[UIView alloc] initWithFrame:[overlayedView_ frame]]; |
443 [grayBackgroundView setBackgroundColor:[UIColor darkGrayColor]]; | 442 [grayBackgroundView setBackgroundColor:[UIColor darkGrayColor]]; |
444 [grayBackgroundView setAlpha:kOverlayedViewBackgroundAlpha]; | 443 [grayBackgroundView setAlpha:kOverlayedViewBackgroundAlpha]; |
445 [grayBackgroundView setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | | 444 [grayBackgroundView setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | |
446 UIViewAutoresizingFlexibleHeight)]; | 445 UIViewAutoresizingFlexibleHeight)]; |
447 [overlayedView_ addSubview:grayBackgroundView]; | 446 [overlayedView_ addSubview:grayBackgroundView]; |
448 | 447 |
449 base::scoped_nsobject<UIActivityIndicatorView> spinner([ | 448 UIActivityIndicatorView* spinner = [[UIActivityIndicatorView alloc] |
450 [UIActivityIndicatorView alloc] | 449 initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; |
451 initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]); | |
452 [spinner setFrame:[overlayedView_ frame]]; | 450 [spinner setFrame:[overlayedView_ frame]]; |
453 [spinner setHidesWhenStopped:YES]; | 451 [spinner setHidesWhenStopped:YES]; |
454 [spinner setUserInteractionEnabled:NO]; | 452 [spinner setUserInteractionEnabled:NO]; |
455 [spinner startAnimating]; | 453 [spinner startAnimating]; |
456 [spinner setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | | 454 [spinner setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | |
457 UIViewAutoresizingFlexibleHeight)]; | 455 UIViewAutoresizingFlexibleHeight)]; |
458 [overlayedView_ addSubview:spinner]; | 456 [overlayedView_ addSubview:spinner]; |
459 | 457 |
460 base::scoped_nsobject<UILabel> label([[UILabel alloc] init]); | 458 UILabel* label = [[UILabel alloc] init]; |
461 [label setTextColor:[UIColor whiteColor]]; | 459 [label setTextColor:[UIColor whiteColor]]; |
462 [label setFont:GetUIFont(FONT_HELVETICA, true, kLabelTextSize)]; | 460 [label setFont:GetUIFont(FONT_HELVETICA, true, kLabelTextSize)]; |
463 [label setNumberOfLines:0]; | 461 [label setNumberOfLines:0]; |
464 [label setShadowColor:[UIColor blackColor]]; | 462 [label setShadowColor:[UIColor blackColor]]; |
465 [label setShadowOffset:CGSizeMake(0.0, 1.0)]; | 463 [label setShadowOffset:CGSizeMake(0.0, 1.0)]; |
466 [label setBackgroundColor:[UIColor clearColor]]; | 464 [label setBackgroundColor:[UIColor clearColor]]; |
467 [label setText:l10n_util::GetNSString(IDS_IOS_OPEN_IN_FILE_DOWNLOAD_CANCEL)]; | 465 [label setText:l10n_util::GetNSString(IDS_IOS_OPEN_IN_FILE_DOWNLOAD_CANCEL)]; |
468 [label setLineBreakMode:NSLineBreakByWordWrapping]; | 466 [label setLineBreakMode:NSLineBreakByWordWrapping]; |
469 [label setTextAlignment:NSTextAlignmentCenter]; | 467 [label setTextAlignment:NSTextAlignmentCenter]; |
470 CGFloat labelWidth = | 468 CGFloat labelWidth = |
471 [overlayedView_ frame].size.width * kOverlayedViewLabelWidthPercentage; | 469 [overlayedView_ frame].size.width * kOverlayedViewLabelWidthPercentage; |
472 CGFloat originX = ([overlayedView_ frame].size.width - labelWidth) / 2; | 470 CGFloat originX = ([overlayedView_ frame].size.width - labelWidth) / 2; |
473 | 471 |
474 CGFloat labelHeight = | 472 CGFloat labelHeight = |
475 [[label text] cr_boundingSizeWithSize:CGSizeMake(labelWidth, CGFLOAT_MAX) | 473 [[label text] cr_boundingSizeWithSize:CGSizeMake(labelWidth, CGFLOAT_MAX) |
476 font:[label font]] | 474 font:[label font]] |
477 .height; | 475 .height; |
478 CGFloat originY = | 476 CGFloat originY = |
479 [overlayedView_ center].y - labelHeight - kOverlayedViewLabelBottomMargin; | 477 [overlayedView_ center].y - labelHeight - kOverlayedViewLabelBottomMargin; |
480 [label setFrame:CGRectMake(originX, originY, labelWidth, labelHeight)]; | 478 [label setFrame:CGRectMake(originX, originY, labelWidth, labelHeight)]; |
481 [overlayedView_ addSubview:label]; | 479 [overlayedView_ addSubview:label]; |
482 | 480 |
483 base::scoped_nsobject<UITapGestureRecognizer> tapRecognizer( | 481 UITapGestureRecognizer* tapRecognizer = [[UITapGestureRecognizer alloc] |
484 [[UITapGestureRecognizer alloc] | 482 initWithTarget:self |
485 initWithTarget:self | 483 action:@selector(handleTapOnOverlayedView:)]; |
486 action:@selector(handleTapOnOverlayedView:)]); | |
487 [tapRecognizer setDelegate:self]; | 484 [tapRecognizer setDelegate:self]; |
488 [overlayedView_ addGestureRecognizer:tapRecognizer]; | 485 [overlayedView_ addGestureRecognizer:tapRecognizer]; |
489 | 486 |
490 [overlayedView_ setAlpha:0.0]; | 487 [overlayedView_ setAlpha:0.0]; |
491 [topView addSubview:overlayedView_]; | 488 [topView addSubview:overlayedView_]; |
492 UIView* overlayedView = overlayedView_.get(); | 489 UIView* overlayedView = overlayedView_; |
493 [UIView animateWithDuration:kOverlayViewAnimationDuration | 490 [UIView animateWithDuration:kOverlayViewAnimationDuration |
494 animations:^{ | 491 animations:^{ |
495 [overlayedView setAlpha:1.0]; | 492 [overlayedView setAlpha:1.0]; |
496 }]; | 493 }]; |
497 } | 494 } |
498 | 495 |
499 - (UIView*)openInToolbar { | 496 - (UIView*)openInToolbar { |
500 if (!openInToolbar_) { | 497 if (!openInToolbar_) { |
501 openInToolbar_.reset([[OpenInToolbar alloc] | 498 openInToolbar_ = [[OpenInToolbar alloc] |
502 initWithTarget:self | 499 initWithTarget:self |
503 action:@selector(exportFileWithOpenInMenuAnchoredAt:)]); | 500 action:@selector(exportFileWithOpenInMenuAnchoredAt:)]; |
504 } | 501 } |
505 return openInToolbar_.get(); | 502 return openInToolbar_; |
506 } | 503 } |
507 | 504 |
508 #pragma mark - | 505 #pragma mark - |
509 #pragma mark File management | 506 #pragma mark File management |
510 | 507 |
511 - (void)removeDocumentAtPath:(NSString*)path { | 508 - (void)removeDocumentAtPath:(NSString*)path { |
512 base::ThreadRestrictions::AssertIOAllowed(); | 509 base::ThreadRestrictions::AssertIOAllowed(); |
513 NSFileManager* fileManager = [NSFileManager defaultManager]; | 510 NSFileManager* fileManager = [NSFileManager defaultManager]; |
514 NSError* error = nil; | 511 NSError* error = nil; |
515 if (![fileManager removeItemAtPath:path error:&error]) { | 512 if (![fileManager removeItemAtPath:path error:&error]) { |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
575 - (void)urlFetchDidComplete:(const net::URLFetcher*)fetcher { | 572 - (void)urlFetchDidComplete:(const net::URLFetcher*)fetcher { |
576 DCHECK(fetcher); | 573 DCHECK(fetcher); |
577 if (requestContext_.get()) | 574 if (requestContext_.get()) |
578 DCHECK_CURRENTLY_ON(web::WebThread::UI); | 575 DCHECK_CURRENTLY_ON(web::WebThread::UI); |
579 base::FilePath filePath; | 576 base::FilePath filePath; |
580 if (fetcher->GetResponseCode() == kHTTPResponseCodeSucceeded && | 577 if (fetcher->GetResponseCode() == kHTTPResponseCodeSucceeded && |
581 fetcher->GetResponseAsFilePath(true, &filePath)) { | 578 fetcher->GetResponseAsFilePath(true, &filePath)) { |
582 NSURL* fileURL = | 579 NSURL* fileURL = |
583 [NSURL fileURLWithPath:base::SysUTF8ToNSString(filePath.value())]; | 580 [NSURL fileURLWithPath:base::SysUTF8ToNSString(filePath.value())]; |
584 if (downloadCanceled_) { | 581 if (downloadCanceled_) { |
585 sequencedTaskRunner_->PostTask(FROM_HERE, base::BindBlock(^{ | 582 sequencedTaskRunner_->PostTask(FROM_HERE, base::BindBlockArc(^{ |
586 [self | 583 [self |
587 removeDocumentAtPath:[fileURL path]]; | 584 removeDocumentAtPath:[fileURL path]]; |
588 })); | 585 })); |
589 } else { | 586 } else { |
590 [self presentOpenInMenuForFileAtURL:fileURL]; | 587 [self presentOpenInMenuForFileAtURL:fileURL]; |
591 } | 588 } |
592 } else if (!downloadCanceled_) { | 589 } else if (!downloadCanceled_) { |
593 if (IsIPadIdiom()) | 590 if (IsIPadIdiom()) |
594 [self hideOpenInToolbar]; | 591 [self hideOpenInToolbar]; |
595 [self removeOverlayedView]; | 592 [self removeOverlayedView]; |
596 [self showErrorWithMessage:l10n_util::GetNSStringWithFixup( | 593 [self showErrorWithMessage:l10n_util::GetNSStringWithFixup( |
597 IDS_IOS_OPEN_IN_FILE_DOWNLOAD_FAILED)]; | 594 IDS_IOS_OPEN_IN_FILE_DOWNLOAD_FAILED)]; |
598 } | 595 } |
599 } | 596 } |
600 | 597 |
601 #pragma mark - | 598 #pragma mark - |
602 #pragma mark UIDocumentInteractionControllerDelegate Methods | 599 #pragma mark UIDocumentInteractionControllerDelegate Methods |
603 | 600 |
604 - (void)documentInteractionController:(UIDocumentInteractionController*)contr | 601 - (void)documentInteractionController:(UIDocumentInteractionController*)contr |
605 didEndSendingToApplication:(NSString*)application { | 602 didEndSendingToApplication:(NSString*)application { |
606 sequencedTaskRunner_->PostTask(FROM_HERE, base::BindBlock(^{ | 603 sequencedTaskRunner_->PostTask(FROM_HERE, base::BindBlockArc(^{ |
607 [self | 604 [self |
608 removeDocumentAtPath:[[contr URL] path]]; | 605 removeDocumentAtPath:[[contr URL] path]]; |
609 })); | 606 })); |
610 if (IsIPadIdiom()) { | 607 if (IsIPadIdiom()) { |
611 // Call the |documentInteractionControllerDidDismissOpenInMenu:| method | 608 // Call the |documentInteractionControllerDidDismissOpenInMenu:| method |
612 // as this is not called on the iPad after the document has been opened | 609 // as this is not called on the iPad after the document has been opened |
613 // in another application. | 610 // in another application. |
614 [self documentInteractionControllerDidDismissOpenInMenu:contr]; | 611 [self documentInteractionControllerDidDismissOpenInMenu:contr]; |
615 } | 612 } |
616 } | 613 } |
617 | 614 |
618 - (void)documentInteractionControllerDidDismissOpenInMenu: | 615 - (void)documentInteractionControllerDidDismissOpenInMenu: |
619 (UIDocumentInteractionController*)controller { | 616 (UIDocumentInteractionController*)controller { |
620 if (!IsIPadIdiom()) { | 617 if (!IsIPadIdiom()) { |
621 isOpenInMenuDisplayed_ = NO; | 618 isOpenInMenuDisplayed_ = NO; |
622 // On the iPhone the |openInToolber_| is hidden already. | 619 // On the iPhone the |openInToolber_| is hidden already. |
623 return; | 620 return; |
624 } | 621 } |
625 | 622 |
626 // On iPad this method is called whenever the device changes orientation, | 623 // On iPad this method is called whenever the device changes orientation, |
627 // even thought the OpenIn menu is not displayed. To distinguish the cases | 624 // even thought the OpenIn menu is not displayed. To distinguish the cases |
628 // when this method is called after the OpenIn menu is dismissed, we | 625 // when this method is called after the OpenIn menu is dismissed, we |
629 // check the BOOL |isOpenInMenuDisplayed|. | 626 // check the BOOL |isOpenInMenuDisplayed|. |
630 if (isOpenInMenuDisplayed_) { | 627 if (isOpenInMenuDisplayed_) { |
631 openInTimer_.reset( | 628 openInTimer_ = |
632 [[NSTimer scheduledTimerWithTimeInterval:kOpenInToolbarDisplayDuration | 629 [NSTimer scheduledTimerWithTimeInterval:kOpenInToolbarDisplayDuration |
633 target:self | 630 target:self |
634 selector:@selector(hideOpenInToolbar) | 631 selector:@selector(hideOpenInToolbar) |
635 userInfo:nil | 632 userInfo:nil |
636 repeats:NO] retain]); | 633 repeats:NO]; |
637 } | 634 } |
638 isOpenInMenuDisplayed_ = NO; | 635 isOpenInMenuDisplayed_ = NO; |
639 } | 636 } |
640 | 637 |
641 #pragma mark - | 638 #pragma mark - |
642 #pragma mark UIGestureRecognizerDelegate Methods | 639 #pragma mark UIGestureRecognizerDelegate Methods |
643 | 640 |
644 - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer*)gestureRecognizer { | 641 - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer*)gestureRecognizer { |
645 if ([gestureRecognizer.view isEqual:overlayedView_]) | 642 if ([gestureRecognizer.view isEqual:overlayedView_]) |
646 return YES; | 643 return YES; |
647 | 644 |
648 CGPoint location = [gestureRecognizer locationInView:[self openInToolbar]]; | 645 CGPoint location = [gestureRecognizer locationInView:[self openInToolbar]]; |
649 return ![[self openInToolbar] pointInside:location withEvent:nil]; | 646 return ![[self openInToolbar] pointInside:location withEvent:nil]; |
650 } | 647 } |
651 | 648 |
652 #pragma mark - TestingAditions | 649 #pragma mark - TestingAditions |
653 | 650 |
654 - (void)setDocumentInteractionController: | 651 - (void)setDocumentInteractionController: |
655 (UIDocumentInteractionController*)controller { | 652 (UIDocumentInteractionController*)controller { |
656 documentController_.reset([controller retain]); | 653 documentController_ = controller; |
657 } | 654 } |
658 | 655 |
659 - (NSString*)suggestedFilename { | 656 - (NSString*)suggestedFilename { |
660 return suggestedFilename_.get(); | 657 return suggestedFilename_; |
661 } | 658 } |
662 | 659 |
663 @end | 660 @end |
OLD | NEW |