Commit ad85698a authored by Eugene But's avatar Eugene But Committed by Commit Bot

Gracefully handle failure to present Open In... menu from New Download Manager.

On iOS 10, where Files app does not exist it is possible for
UIDocumentInteractionController to not present Open In... menu.
In this case Download Manager should show the prompt to install Google
Drive app.

Bug: 823702
Cq-Include-Trybots: master.tryserver.chromium.mac:ios-simulator-cronet;master.tryserver.chromium.mac:ios-simulator-full-configs
Change-Id: I393c8724186deaefd3dc192a61759c24799dd1d5
Reviewed-on: https://chromium-review.googlesource.com/974748
Commit-Queue: Eugene But <eugenebut@chromium.org>
Reviewed-by: default avatarSylvain Defresne <sdefresne@chromium.org>
Cr-Commit-Position: refs/heads/master@{#545098}
parent 37cb5af3
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#import "ios/chrome/browser/download/google_drive_app_util.h" #import "ios/chrome/browser/download/google_drive_app_util.h"
#import "ios/chrome/browser/installation_notifier.h" #import "ios/chrome/browser/installation_notifier.h"
#import "ios/chrome/browser/store_kit/store_kit_coordinator.h" #import "ios/chrome/browser/store_kit/store_kit_coordinator.h"
#import "ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h"
#import "ios/chrome/browser/ui/download/download_manager_mediator.h" #import "ios/chrome/browser/ui/download/download_manager_mediator.h"
#import "ios/chrome/browser/ui/download/download_manager_view_controller.h" #import "ios/chrome/browser/ui/download/download_manager_view_controller.h"
#import "ios/chrome/browser/ui/presenters/contained_presenter.h" #import "ios/chrome/browser/ui/presenters/contained_presenter.h"
...@@ -81,6 +82,10 @@ class UnopenedDownloadsTracker : public web::DownloadTaskObserver { ...@@ -81,6 +82,10 @@ class UnopenedDownloadsTracker : public web::DownloadTaskObserver {
UIDocumentInteractionController* _openInController; UIDocumentInteractionController* _openInController;
DownloadManagerMediator _mediator; DownloadManagerMediator _mediator;
StoreKitCoordinator* _storeKitCoordinator; StoreKitCoordinator* _storeKitCoordinator;
// Coordinator for displaying the alert informing the user that no application
// on the device can open the file. The alert offers the user to install
// Google Drive app.
AlertCoordinator* _installDriveAlertCoordinator;
UnopenedDownloadsTracker _unopenedDownloads; UnopenedDownloadsTracker _unopenedDownloads;
} }
@end @end
...@@ -124,6 +129,8 @@ class UnopenedDownloadsTracker : public web::DownloadTaskObserver { ...@@ -124,6 +129,8 @@ class UnopenedDownloadsTracker : public web::DownloadTaskObserver {
[_storeKitCoordinator stop]; [_storeKitCoordinator stop];
_storeKitCoordinator = nil; _storeKitCoordinator = nil;
[_installDriveAlertCoordinator stop];
_installDriveAlertCoordinator = nil;
} }
- (UIViewController*)viewController { - (UIViewController*)viewController {
...@@ -233,19 +240,7 @@ class UnopenedDownloadsTracker : public web::DownloadTaskObserver { ...@@ -233,19 +240,7 @@ class UnopenedDownloadsTracker : public web::DownloadTaskObserver {
- (void)installDriveForDownloadManagerViewController: - (void)installDriveForDownloadManagerViewController:
(DownloadManagerViewController*)controller { (DownloadManagerViewController*)controller {
if (!_storeKitCoordinator) { [self presentStoreKitForGoogleDriveApp];
_storeKitCoordinator = [[StoreKitCoordinator alloc]
initWithBaseViewController:self.baseViewController];
_storeKitCoordinator.iTunesItemIdentifier =
kGoogleDriveITunesItemIdentifier;
}
[_storeKitCoordinator start];
[controller setInstallDriveButtonVisible:NO animated:YES];
[[InstallationNotifier sharedInstance]
registerForInstallationNotifications:self
withSelector:@selector(didInstallGoogleDriveApp)
forScheme:kGoogleDriveAppURLScheme];
} }
- (void)downloadManagerViewControllerDidStartDownload: - (void)downloadManagerViewControllerDidStartDownload:
...@@ -269,7 +264,12 @@ class UnopenedDownloadsTracker : public web::DownloadTaskObserver { ...@@ -269,7 +264,12 @@ class UnopenedDownloadsTracker : public web::DownloadTaskObserver {
[_openInController presentOpenInMenuFromRect:layoutGuide.layoutFrame [_openInController presentOpenInMenuFromRect:layoutGuide.layoutFrame
inView:layoutGuide.owningView inView:layoutGuide.owningView
animated:YES]; animated:YES];
DCHECK(menuShown);
// No application on this device can open the file. Typically happens on
// iOS 10, where Files app does not exist.
if (!menuShown) {
[self didFailOpenInMenuPresentation];
}
} }
#pragma mark - Private #pragma mark - Private
...@@ -321,4 +321,52 @@ class UnopenedDownloadsTracker : public web::DownloadTaskObserver { ...@@ -321,4 +321,52 @@ class UnopenedDownloadsTracker : public web::DownloadTaskObserver {
base::UserMetricsAction(kDownloadManagerGoogleDriveInstalled)); base::UserMetricsAction(kDownloadManagerGoogleDriveInstalled));
} }
// Called when Open In... menu was not presented. This method shows the alert
// which offers the user to install Google Drive app.
- (void)didFailOpenInMenuPresentation {
NSString* title =
l10n_util::GetNSString(IDS_IOS_DOWNLOAD_MANAGER_UNABLE_TO_OPEN_FILE);
NSString* message =
l10n_util::GetNSString(IDS_IOS_DOWNLOAD_MANAGER_NO_APP_MESSAGE);
_installDriveAlertCoordinator = [[AlertCoordinator alloc]
initWithBaseViewController:self.baseViewController
title:title
message:message];
NSString* googleDriveButtonTitle =
l10n_util::GetNSString(IDS_IOS_DOWNLOAD_MANAGER_UPLOAD_TO_GOOGLE_DRIVE);
__weak DownloadManagerCoordinator* weakSelf = self;
[_installDriveAlertCoordinator
addItemWithTitle:googleDriveButtonTitle
action:^{
[weakSelf presentStoreKitForGoogleDriveApp];
}
style:UIAlertActionStyleDefault];
[_installDriveAlertCoordinator
addItemWithTitle:l10n_util::GetNSString(IDS_CANCEL)
action:nil
style:UIAlertActionStyleCancel];
[_installDriveAlertCoordinator start];
}
// Presents StoreKit dialog for Google Drive application.
- (void)presentStoreKitForGoogleDriveApp {
if (!_storeKitCoordinator) {
_storeKitCoordinator = [[StoreKitCoordinator alloc]
initWithBaseViewController:self.baseViewController];
_storeKitCoordinator.iTunesItemIdentifier =
kGoogleDriveITunesItemIdentifier;
}
[_storeKitCoordinator start];
[_viewController setInstallDriveButtonVisible:NO animated:YES];
[[InstallationNotifier sharedInstance]
registerForInstallationNotifications:self
withSelector:@selector(didInstallGoogleDriveApp)
forScheme:kGoogleDriveAppURLScheme];
}
@end @end
...@@ -537,6 +537,52 @@ TEST_F(DownloadManagerCoordinatorTest, OpenInOtherApp) { ...@@ -537,6 +537,52 @@ TEST_F(DownloadManagerCoordinatorTest, OpenInOtherApp) {
1); 1);
} }
// Tests the failure to present Open In... menu. Typically happens on iOS 10
// where Files app is not installed.
TEST_F(DownloadManagerCoordinatorTest, OpenInFailure) {
web::FakeDownloadTask task(GURL(kTestUrl), kTestMimeType);
task.SetSuggestedFilename(base::SysNSStringToUTF16(kTestSuggestedFileName));
coordinator_.downloadTask = &task;
[coordinator_ start];
EXPECT_EQ(1U, base_view_controller_.childViewControllers.count);
DownloadManagerViewController* viewController =
base_view_controller_.childViewControllers.firstObject;
ASSERT_EQ([DownloadManagerViewController class], [viewController class]);
// Start and complete the download.
base::FilePath path;
ASSERT_TRUE(base::GetTempDir(&path));
task.Start(std::make_unique<net::URLFetcherFileWriter>(
base::ThreadTaskRunnerHandle::Get(), path));
// Stub UIDocumentInteractionController.
id document_interaction_controller =
[[FakeDocumentInteractionController alloc] init];
[document_interaction_controller setPresentsOpenInMenu:NO];
OCMStub([document_interaction_controller_class_
interactionControllerWithURL:[OCMArg any]])
.andReturn(document_interaction_controller);
// Attempt to present Open In... menu.
ASSERT_FALSE([document_interaction_controller presentedOpenInMenu]);
@autoreleasepool {
// This call will retain coordinator, which should outlive thread bundle.
[viewController.delegate downloadManagerViewController:viewController
presentOpenInMenuWithLayoutGuide:nil];
}
ASSERT_FALSE([document_interaction_controller presentedOpenInMenu]);
// Verify that UIAlert is presented.
ASSERT_TRUE([base_view_controller_.presentedViewController
isKindOfClass:[UIAlertController class]]);
UIAlertController* alert = base::mac::ObjCCast<UIAlertController>(
base_view_controller_.presentedViewController);
EXPECT_NSEQ(@"Unable to Open File", alert.title);
EXPECT_NSEQ(@"No application on this device can open the file.",
alert.message);
}
// Tests closing view controller while the download is in progress. Coordinator // Tests closing view controller while the download is in progress. Coordinator
// should present the confirmation dialog. // should present the confirmation dialog.
TEST_F(DownloadManagerCoordinatorTest, CloseInProgressDownload) { TEST_F(DownloadManagerCoordinatorTest, CloseInProgressDownload) {
......
...@@ -21,6 +21,9 @@ ...@@ -21,6 +21,9 @@
@property(nonatomic, weak) id<UIDocumentInteractionControllerDelegate> delegate; @property(nonatomic, weak) id<UIDocumentInteractionControllerDelegate> delegate;
// Whether or not this controller can present Open In... menu. Defaults to YES.
@property(nonatomic) BOOL presentsOpenInMenu;
// Menu that is currently being presented. // Menu that is currently being presented.
@property(nonatomic, readonly) OpenInMenu* presentedOpenInMenu; @property(nonatomic, readonly) OpenInMenu* presentedOpenInMenu;
......
...@@ -23,10 +23,23 @@ ...@@ -23,10 +23,23 @@
@implementation FakeDocumentInteractionController @implementation FakeDocumentInteractionController
@synthesize delegate = _delegate; @synthesize delegate = _delegate;
@synthesize presentsOpenInMenu = _presentsOpenInMenu;
@synthesize presentedOpenInMenu = _presentedOpenInMenu; @synthesize presentedOpenInMenu = _presentedOpenInMenu;
- (instancetype)init {
self = [super init];
if (self) {
_presentsOpenInMenu = YES;
}
return self;
}
- (BOOL)presentOpenInMenuFromRect:(CGRect)rect - (BOOL)presentOpenInMenuFromRect:(CGRect)rect
inView:(UIView*)view inView:(UIView*)view
animated:(BOOL)animated { animated:(BOOL)animated {
if (!_presentsOpenInMenu)
return NO;
_presentedOpenInMenu = [[OpenInMenu alloc] init]; _presentedOpenInMenu = [[OpenInMenu alloc] init];
_presentedOpenInMenu.rect = rect; _presentedOpenInMenu.rect = rect;
_presentedOpenInMenu.view = view; _presentedOpenInMenu.view = view;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment