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

Side by Side Diff: ios/chrome/browser/web/external_app_launcher.mm

Issue 2580333003: Upstream Chrome on iOS source code [10/11]. (Closed)
Patch Set: Created 4 years 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
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #import "ios/chrome/browser/web/external_app_launcher.h"
6
7 #include "base/ios/weak_nsobject.h"
8 #include "base/logging.h"
9 #include "base/metrics/histogram.h"
10 #include "base/strings/sys_string_conversions.h"
11 #include "components/strings/grit/components_strings.h"
12 #include "ios/chrome/browser/experimental_flags.h"
13 #import "ios/chrome/browser/open_url_util.h"
14 #include "ios/chrome/grit/ios_strings.h"
15 #import "net/base/mac/url_conversions.h"
16 #include "ui/base/l10n/l10n_util.h"
17 #include "url/gurl.h"
18
19 namespace {
20
21 typedef void (^AlertHandler)(UIAlertAction* action);
22
23 // Returns a set of NSStrings that are URL schemes for iTunes Stores.
24 NSSet<NSString*>* ITMSSchemes() {
25 static NSSet<NSString*>* schemes;
26 static dispatch_once_t once;
27 dispatch_once(&once, ^{
28 schemes =
29 [[NSSet setWithObjects:@"itms", @"itmss", @"itms-apps", @"itms-appss",
30 // There's no evidence that itms-bookss is
31 // actually supported, but over-inclusion
32 // costs less than under-inclusion.
33 @"itms-books", @"itms-bookss", nil] retain];
34 });
35 return schemes;
36 }
37
38 bool UrlHasAppStoreScheme(const GURL& gURL) {
39 std::string scheme = gURL.scheme();
40 return [ITMSSchemes() containsObject:base::SysUTF8ToNSString(scheme)];
41 }
42
43 // Logs an entry for |Tab.ExternalApplicationOpened|. If the user decided to
44 // open in an external app, pass true. Otherwise, if the user cancelled the
45 // opening, pass false.
46 void RecordExternalApplicationOpened(bool opened) {
47 UMA_HISTOGRAM_BOOLEAN("Tab.ExternalApplicationOpened", opened);
48 }
49
50 } // namespace
51
52 @interface ExternalAppLauncher ()
53 // Returns the Phone/FaceTime call argument from |URL|.
54 + (NSString*)formatCallArgument:(NSURL*)URL;
55 // Ask user for confirmation before dialing FaceTime destination.
56 - (void)openFaceTimePromptForURL:(NSURL*)telURL;
57 // Ask user for confirmation before moving to external app.
58 - (void)openExternalAppWithPromptForURL:(NSURL*)URL;
59 // Presents a configured alert controller on the root view controller.
60 - (void)presentAlertControllerWithMessage:(NSString*)message
61 openTitle:(NSString*)openTitle
62 openHandler:(AlertHandler)openHandler
63 cancelHandler:(AlertHandler)cancelHandler;
64 @end
65
66 @implementation ExternalAppLauncher
67
68 + (NSString*)formatCallArgument:(NSURL*)URL {
69 NSCharacterSet* charSet =
70 [NSCharacterSet characterSetWithCharactersInString:@"/"];
71 NSString* scheme = [NSString stringWithFormat:@"%@:", [URL scheme]];
72 NSString* URLString = [URL absoluteString];
73 if ([URLString length] <= [scheme length])
74 return URLString;
75 NSString* prompt = [[[[URL absoluteString] substringFromIndex:[scheme length]]
76 stringByTrimmingCharactersInSet:charSet] stringByRemovingPercentEncoding];
77 // Returns original URL string if there's nothing interesting to display
78 // other than the scheme itself.
79 if (![prompt length])
80 return URLString;
81 return prompt;
82 }
83
84 - (void)openExternalAppWithPromptForURL:(NSURL*)URL {
85 NSString* message = l10n_util::GetNSString(IDS_IOS_OPEN_IN_ANOTHER_APP);
86 NSString* openTitle =
87 l10n_util::GetNSString(IDS_IOS_APP_LAUNCHER_OPEN_APP_BUTTON_LABEL);
88 [self presentAlertControllerWithMessage:message
89 openTitle:openTitle
90 openHandler:^(UIAlertAction* action) {
91 RecordExternalApplicationOpened(true);
92 OpenUrlWithCompletionHandler(URL, nil);
93 }
94 cancelHandler:^(UIAlertAction* action) {
95 RecordExternalApplicationOpened(false);
96 }];
97 }
98
99 - (void)openFaceTimePromptForURL:(NSURL*)URL {
100 NSString* openTitle = l10n_util::GetNSString(IDS_IOS_FACETIME_BUTTON);
101 [self presentAlertControllerWithMessage:[[self class] formatCallArgument:URL]
102 openTitle:openTitle
103 openHandler:^(UIAlertAction* action) {
104 OpenUrlWithCompletionHandler(URL, nil);
105 }
106 cancelHandler:nil];
107 }
108
109 - (void)presentAlertControllerWithMessage:(NSString*)message
110 openTitle:(NSString*)openTitle
111 openHandler:(AlertHandler)openHandler
112 cancelHandler:(AlertHandler)cancelHandler {
113 UIAlertController* alertController =
114 [UIAlertController alertControllerWithTitle:nil
115 message:message
116 preferredStyle:UIAlertControllerStyleAlert];
117 UIAlertAction* openAction =
118 [UIAlertAction actionWithTitle:openTitle
119 style:UIAlertActionStyleDefault
120 handler:openHandler];
121 UIAlertAction* cancelAction =
122 [UIAlertAction actionWithTitle:l10n_util::GetNSString(IDS_CANCEL)
123 style:UIAlertActionStyleCancel
124 handler:cancelHandler];
125 [alertController addAction:cancelAction];
126 [alertController addAction:openAction];
127
128 [[[[UIApplication sharedApplication] keyWindow] rootViewController]
129 presentViewController:alertController
130 animated:YES
131 completion:nil];
132 }
133
134 - (BOOL)openURL:(const GURL&)gURL linkClicked:(BOOL)linkClicked {
135 if (!gURL.is_valid() || !gURL.has_scheme())
136 return NO;
137 NSURL* URL = net::NSURLWithGURL(gURL);
138
139 if (gURL.SchemeIs("facetime") || gURL.SchemeIs("facetime-audio")) {
140 // Showing an alert view immediately has a side-effect where focus is
141 // taken from the UIWebView so quickly that mouseup events are lost and
142 // buttons get 'stuck' in the on position. The solution is to defer
143 // showing the view.
144 [self performSelector:@selector(openFaceTimePromptForURL:)
145 withObject:URL
146 afterDelay:0.0];
147 return YES;
148 }
149
150 // Use telprompt instead of tel because telprompt returns user back to
151 // Chrome after phone call is completed/aborted.
152 if (gURL.SchemeIs("tel")) {
153 GURL::Replacements replacements;
154 replacements.SetSchemeStr("telprompt");
155 URL = net::NSURLWithGURL(gURL.ReplaceComponents(replacements));
156 DCHECK([[URL scheme] isEqualToString:@"telprompt"]);
157 }
158
159 // Don't open external application if chrome is not active.
160 if ([[UIApplication sharedApplication] applicationState] !=
161 UIApplicationStateActive)
162 return NO;
163
164 if (experimental_flags::IsExternalApplicationPromptEnabled()) {
165 // Prompt user to open itunes when opening it is not a result of a link
166 // click.
167 if (!linkClicked && UrlHasAppStoreScheme(gURL)) {
168 [self performSelector:@selector(openExternalAppWithPromptForURL:)
169 withObject:URL
170 afterDelay:0.0];
171 return YES;
172 }
173 }
174
175 // If the following call returns YES, an external application is about to be
176 // launched and Chrome will go into the background now.
177 // TODO(crbug.com/622735): This call still needs to be updated.
178 // It's heavily nested so some refactoring is needed.
179 return [[UIApplication sharedApplication] openURL:URL];
180 }
181
182 @end
OLDNEW
« no previous file with comments | « ios/chrome/browser/web/external_app_launcher.h ('k') | ios/chrome/browser/web/external_app_launcher_disabler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698