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

Side by Side Diff: ios/chrome/app/chrome_app_startup_parameters.mm

Issue 2580363002: Upstream Chrome on iOS source code [1/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 2015 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/app/chrome_app_startup_parameters.h"
6
7 #include "base/logging.h"
8 #include "base/mac/foundation_util.h"
9 #include "base/mac/scoped_nsobject.h"
10 #include "base/metrics/histogram.h"
11 #include "base/metrics/user_metrics_action.h"
12 #include "base/strings/sys_string_conversions.h"
13 #include "ios/chrome/browser/chrome_url_constants.h"
14 #include "ios/chrome/browser/xcallback_parameters.h"
15 #include "ios/chrome/common/app_group/app_group_constants.h"
16 #include "ios/chrome/common/x_callback_url.h"
17 #import "net/base/mac/url_conversions.h"
18 #include "url/gurl.h"
19
20 namespace {
21
22 // Key of the UMA Startup.MobileSessionStartAction histogram.
23 const char kUMAMobileSessionStartActionHistogram[] =
24 "Startup.MobileSessionStartAction";
25
26 const char kApplicationGroupCommandDelay[] =
27 "Startup.ApplicationGroupCommandDelay";
28
29 // URL Query String parameter to indicate that this openURL: request arrived
30 // here due to a Smart App Banner presentation on a Google.com page.
31 NSString* const kSmartAppBannerKey = @"safarisab";
32
33 const CGFloat kAppGroupTriggersVoiceSearchTimeout = 15.0;
34
35 // Values of the UMA Startup.MobileSessionStartAction histogram.
36 enum MobileSessionStartAction {
37 START_ACTION_OPEN_HTTP = 0,
38 START_ACTION_OPEN_HTTPS,
39 START_ACTION_OPEN_FILE,
40 START_ACTION_XCALLBACK_OPEN,
41 START_ACTION_XCALLBACK_OTHER,
42 START_ACTION_OTHER,
43 START_ACTION_XCALLBACK_APPGROUP_COMMAND,
44 MOBILE_SESSION_START_ACTION_COUNT,
45 };
46
47 } // namespace
48
49 @implementation ChromeAppStartupParameters {
50 base::scoped_nsobject<NSString> _secureSourceApp;
51 base::scoped_nsobject<NSString> _declaredSourceApp;
52 base::scoped_nsobject<NSURL> _completeURL;
53 }
54
55 - (instancetype)initWithExternalURL:(const GURL&)externalURL
56 xCallbackParameters:(XCallbackParameters*)xCallbackParameters {
57 NOTREACHED();
58 return nil;
59 }
60
61 - (instancetype)initWithExternalURL:(const GURL&)externalURL
62 xCallbackParameters:(XCallbackParameters*)xCallbackParameters
63 declaredSourceApp:(NSString*)declaredSourceApp
64 secureSourceApp:(NSString*)secureSourceApp
65 completeURL:(NSURL*)completeURL {
66 self = [super initWithExternalURL:externalURL
67 xCallbackParameters:xCallbackParameters];
68 if (self) {
69 _declaredSourceApp.reset([declaredSourceApp copy]);
70 _secureSourceApp.reset([secureSourceApp copy]);
71 _completeURL.reset([completeURL retain]);
72 }
73 return self;
74 }
75
76 + (instancetype)newChromeAppStartupParametersWithURL:(NSURL*)completeURL
77 fromSourceApplication:(NSString*)appId {
78 GURL gurl = net::GURLWithNSURL(completeURL);
79
80 if (!gurl.is_valid() || gurl.scheme().length() == 0)
81 return nil;
82
83 // TODO(ios): Temporary fix for b/7174478
84 if (IsXCallbackURL(gurl)) {
85 NSString* action = [completeURL path];
86 // Currently only "open" and "extension-command" are supported.
87 // Other actions are being considered (see b/6914153).
88 if ([action
89 isEqualToString:
90 [NSString
91 stringWithFormat:
92 @"/%s", app_group::kChromeAppGroupXCallbackCommand]]) {
93 UMA_HISTOGRAM_ENUMERATION(kUMAMobileSessionStartActionHistogram,
94 START_ACTION_XCALLBACK_APPGROUP_COMMAND,
95 MOBILE_SESSION_START_ACTION_COUNT);
96 return [ChromeAppStartupParameters
97 newExtensionCommandAppStartupParametersFromWithURL:completeURL
98 fromSourceApplication:appId];
99 }
100
101 if (![action isEqualToString:@"/open"]) {
102 UMA_HISTOGRAM_ENUMERATION(kUMAMobileSessionStartActionHistogram,
103 START_ACTION_XCALLBACK_OTHER,
104 MOBILE_SESSION_START_ACTION_COUNT);
105 return nil;
106 }
107
108 UMA_HISTOGRAM_ENUMERATION(kUMAMobileSessionStartActionHistogram,
109 START_ACTION_XCALLBACK_OPEN,
110 MOBILE_SESSION_START_ACTION_COUNT);
111
112 std::map<std::string, std::string> parameters =
113 ExtractQueryParametersFromXCallbackURL(gurl);
114 GURL url = GURL(parameters["url"]);
115 if (!url.is_valid() ||
116 (!url.SchemeIs(url::kHttpScheme) && !url.SchemeIs(url::kHttpsScheme))) {
117 return nil;
118 }
119
120 base::scoped_nsobject<XCallbackParameters> xcallbackParameters(
121 [[XCallbackParameters alloc] initWithSourceAppId:appId]);
122
123 return [[ChromeAppStartupParameters alloc]
124 initWithExternalURL:url
125 xCallbackParameters:xcallbackParameters
126 declaredSourceApp:appId
127 secureSourceApp:nil
128 completeURL:completeURL];
129
130 } else if (gurl.SchemeIsFile()) {
131 UMA_HISTOGRAM_ENUMERATION(kUMAMobileSessionStartActionHistogram,
132 START_ACTION_OPEN_FILE,
133 MOBILE_SESSION_START_ACTION_COUNT);
134 // |url| is the path to a file received from another application.
135 GURL::Replacements replacements;
136 const std::string host(kChromeUIExternalFileHost);
137 std::string filename = gurl.ExtractFileName();
138 replacements.SetPathStr(filename);
139 replacements.SetSchemeStr(kChromeUIScheme);
140 replacements.SetHostStr(host);
141 GURL externalURL = gurl.ReplaceComponents(replacements);
142 if (!externalURL.is_valid())
143 return nil;
144 return [[ChromeAppStartupParameters alloc] initWithExternalURL:externalURL
145 xCallbackParameters:nil
146 declaredSourceApp:appId
147 secureSourceApp:nil
148 completeURL:completeURL];
149 } else {
150 // Replace the scheme with https or http depending on whether the input
151 // |url| scheme ends with an 's'.
152 BOOL useHttps = gurl.scheme()[gurl.scheme().length() - 1] == 's';
153 MobileSessionStartAction action =
154 useHttps ? START_ACTION_OPEN_HTTPS : START_ACTION_OPEN_HTTP;
155 UMA_HISTOGRAM_ENUMERATION(kUMAMobileSessionStartActionHistogram, action,
156 MOBILE_SESSION_START_ACTION_COUNT);
157 GURL::Replacements replace_scheme;
158 if (useHttps)
159 replace_scheme.SetSchemeStr(url::kHttpsScheme);
160 else
161 replace_scheme.SetSchemeStr(url::kHttpScheme);
162 GURL externalURL = gurl.ReplaceComponents(replace_scheme);
163 if (!externalURL.is_valid())
164 return nil;
165 return [[ChromeAppStartupParameters alloc] initWithExternalURL:externalURL
166 xCallbackParameters:nil
167 declaredSourceApp:appId
168 secureSourceApp:nil
169 completeURL:completeURL];
170 }
171 }
172
173 + (instancetype)newExtensionCommandAppStartupParametersFromWithURL:(NSURL*)url
174 fromSourceApplication:
175 (NSString*)appId {
176 NSString* appGroup = app_group::ApplicationGroup();
177 base::scoped_nsobject<NSUserDefaults> sharedDefaults(
178 [[NSUserDefaults alloc] initWithSuiteName:appGroup]);
179
180 NSString* commandDictionaryPreference =
181 base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandPreference);
182 NSDictionary* commandDictionary = base::mac::ObjCCast<NSDictionary>(
183 [sharedDefaults objectForKey:commandDictionaryPreference]);
184
185 [sharedDefaults removeObjectForKey:commandDictionaryPreference];
186
187 // |sharedDefaults| is used for communication between apps. Synchronize to
188 // avoid synchronization issues (like removing the next order).
189 [sharedDefaults synchronize];
190
191 if (!commandDictionary) {
192 return nil;
193 }
194
195 NSString* commandCallerPreference =
196 base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandAppPreference);
197 NSString* commandCaller = base::mac::ObjCCast<NSString>(
198 [commandDictionary objectForKey:commandCallerPreference]);
199
200 NSString* commandPreference = base::SysUTF8ToNSString(
201 app_group::kChromeAppGroupCommandCommandPreference);
202 NSString* command = base::mac::ObjCCast<NSString>(
203 [commandDictionary objectForKey:commandPreference]);
204
205 NSString* commandTimePreference =
206 base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandTimePreference);
207 id commandTime = base::mac::ObjCCast<NSDate>(
208 [commandDictionary objectForKey:commandTimePreference]);
209
210 NSString* commandParameterPreference = base::SysUTF8ToNSString(
211 app_group::kChromeAppGroupCommandParameterPreference);
212 NSString* commandParameter = base::mac::ObjCCast<NSString>(
213 [commandDictionary objectForKey:commandParameterPreference]);
214
215 if (!commandCaller || !command || !commandTimePreference) {
216 return nil;
217 }
218
219 // Check the time of the last request to avoid app from intercepting old
220 // open url request and replay it later.
221 NSTimeInterval delay = [[NSDate date] timeIntervalSinceDate:commandTime];
222 UMA_HISTOGRAM_COUNTS_100(kApplicationGroupCommandDelay, delay);
223 if (delay > kAppGroupTriggersVoiceSearchTimeout)
224 return nil;
225 return [ChromeAppStartupParameters
226 newAppStartupParametersForCommand:command
227 withParameter:commandParameter
228 withURL:url
229 fromSourceApplication:appId
230 fromSecureSourceApplication:commandCaller];
231 }
232
233 + (instancetype)newAppStartupParametersForCommand:(NSString*)command
234 withParameter:(id)parameter
235 withURL:(NSURL*)url
236 fromSourceApplication:(NSString*)appId
237 fromSecureSourceApplication:(NSString*)secureSourceApp {
238 if ([command
239 isEqualToString:base::SysUTF8ToNSString(
240 app_group::kChromeAppGroupVoiceSearchCommand)]) {
241 ChromeAppStartupParameters* params = [[ChromeAppStartupParameters alloc]
242 initWithExternalURL:GURL(kChromeUINewTabURL)
243 xCallbackParameters:nil
244 declaredSourceApp:appId
245 secureSourceApp:secureSourceApp
246 completeURL:url];
247 [params setLaunchVoiceSearch:YES];
248 return params;
249 }
250
251 if ([command isEqualToString:base::SysUTF8ToNSString(
252 app_group::kChromeAppGroupNewTabCommand)]) {
253 return [[ChromeAppStartupParameters alloc]
254 initWithExternalURL:GURL(kChromeUINewTabURL)
255 xCallbackParameters:nil
256 declaredSourceApp:appId
257 secureSourceApp:secureSourceApp
258 completeURL:url];
259 }
260 if ([command isEqualToString:base::SysUTF8ToNSString(
261 app_group::kChromeAppGroupOpenURLCommand)]) {
262 if (!parameter || ![parameter isKindOfClass:[NSString class]])
263 return nil;
264 GURL externalURL(base::SysNSStringToUTF8(parameter));
265 if (!externalURL.is_valid() || !externalURL.SchemeIsHTTPOrHTTPS())
266 return nil;
267 return
268 [[ChromeAppStartupParameters alloc] initWithExternalURL:externalURL
269 xCallbackParameters:nil
270 declaredSourceApp:appId
271 secureSourceApp:secureSourceApp
272 completeURL:url];
273 }
274
275 return nil;
276 }
277
278 - (MobileSessionCallerApp)callerApp {
279 if ([_secureSourceApp isEqualToString:@"TodayExtension"])
280 return CALLER_APP_GOOGLE_CHROME_TODAY_EXTENSION;
281
282 if (![_declaredSourceApp length])
283 return CALLER_APP_NOT_AVAILABLE;
284 if ([_declaredSourceApp isEqualToString:@"com.google.GoogleMobile"])
285 return CALLER_APP_GOOGLE_SEARCH;
286 if ([_declaredSourceApp isEqualToString:@"com.google.Gmail"])
287 return CALLER_APP_GOOGLE_GMAIL;
288 if ([_declaredSourceApp isEqualToString:@"com.google.GooglePlus"])
289 return CALLER_APP_GOOGLE_PLUS;
290 if ([_declaredSourceApp isEqualToString:@"com.google.Drive"])
291 return CALLER_APP_GOOGLE_DRIVE;
292 if ([_declaredSourceApp isEqualToString:@"com.google.b612"])
293 return CALLER_APP_GOOGLE_EARTH;
294 if ([_declaredSourceApp isEqualToString:@"com.google.ios.youtube"])
295 return CALLER_APP_GOOGLE_YOUTUBE;
296 if ([_declaredSourceApp isEqualToString:@"com.google.Maps"])
297 return CALLER_APP_GOOGLE_MAPS;
298 if ([_declaredSourceApp hasPrefix:@"com.google."])
299 return CALLER_APP_GOOGLE_OTHER;
300 if ([_declaredSourceApp isEqualToString:@"com.apple.mobilesafari"])
301 return CALLER_APP_APPLE_MOBILESAFARI;
302 if ([_declaredSourceApp hasPrefix:@"com.apple."])
303 return CALLER_APP_APPLE_OTHER;
304
305 return CALLER_APP_OTHER;
306 }
307
308 - (first_run::ExternalLaunch)launchSource {
309 if ([self callerApp] != CALLER_APP_APPLE_MOBILESAFARI) {
310 return first_run::LAUNCH_BY_OTHERS;
311 }
312
313 NSString* query = [_completeURL query];
314 // Takes care of degenerated case of no QUERY_STRING.
315 if (![query length])
316 return first_run::LAUNCH_BY_MOBILESAFARI;
317 // Look for |kSmartAppBannerKey| anywhere within the query string.
318 NSRange found = [query rangeOfString:kSmartAppBannerKey];
319 if (found.location == NSNotFound)
320 return first_run::LAUNCH_BY_MOBILESAFARI;
321 // |kSmartAppBannerKey| can be at the beginning or end of the query
322 // string and may also be optionally followed by a equal sign and a value.
323 // For now, just look for the presence of the key and ignore the value.
324 if (found.location + found.length < [query length]) {
325 // There are characters following the found location.
326 unichar charAfter =
327 [query characterAtIndex:(found.location + found.length)];
328 if (charAfter != '&' && charAfter != '=')
329 return first_run::LAUNCH_BY_MOBILESAFARI;
330 }
331 if (found.location > 0) {
332 unichar charBefore = [query characterAtIndex:(found.location - 1)];
333 if (charBefore != '&')
334 return first_run::LAUNCH_BY_MOBILESAFARI;
335 }
336 return first_run::LAUNCH_BY_SMARTAPPBANNER;
337 }
338
339 @end
OLDNEW
« no previous file with comments | « ios/chrome/app/chrome_app_startup_parameters.h ('k') | ios/chrome/app/chrome_app_startup_parameters_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698