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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: ios/chrome/app/chrome_app_startup_parameters.mm
diff --git a/ios/chrome/app/chrome_app_startup_parameters.mm b/ios/chrome/app/chrome_app_startup_parameters.mm
new file mode 100644
index 0000000000000000000000000000000000000000..b00dc5ca2f13bc550cad7c2453e737cc4e8aecc5
--- /dev/null
+++ b/ios/chrome/app/chrome_app_startup_parameters.mm
@@ -0,0 +1,339 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/app/chrome_app_startup_parameters.h"
+
+#include "base/logging.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/user_metrics_action.h"
+#include "base/strings/sys_string_conversions.h"
+#include "ios/chrome/browser/chrome_url_constants.h"
+#include "ios/chrome/browser/xcallback_parameters.h"
+#include "ios/chrome/common/app_group/app_group_constants.h"
+#include "ios/chrome/common/x_callback_url.h"
+#import "net/base/mac/url_conversions.h"
+#include "url/gurl.h"
+
+namespace {
+
+// Key of the UMA Startup.MobileSessionStartAction histogram.
+const char kUMAMobileSessionStartActionHistogram[] =
+ "Startup.MobileSessionStartAction";
+
+const char kApplicationGroupCommandDelay[] =
+ "Startup.ApplicationGroupCommandDelay";
+
+// URL Query String parameter to indicate that this openURL: request arrived
+// here due to a Smart App Banner presentation on a Google.com page.
+NSString* const kSmartAppBannerKey = @"safarisab";
+
+const CGFloat kAppGroupTriggersVoiceSearchTimeout = 15.0;
+
+// Values of the UMA Startup.MobileSessionStartAction histogram.
+enum MobileSessionStartAction {
+ START_ACTION_OPEN_HTTP = 0,
+ START_ACTION_OPEN_HTTPS,
+ START_ACTION_OPEN_FILE,
+ START_ACTION_XCALLBACK_OPEN,
+ START_ACTION_XCALLBACK_OTHER,
+ START_ACTION_OTHER,
+ START_ACTION_XCALLBACK_APPGROUP_COMMAND,
+ MOBILE_SESSION_START_ACTION_COUNT,
+};
+
+} // namespace
+
+@implementation ChromeAppStartupParameters {
+ base::scoped_nsobject<NSString> _secureSourceApp;
+ base::scoped_nsobject<NSString> _declaredSourceApp;
+ base::scoped_nsobject<NSURL> _completeURL;
+}
+
+- (instancetype)initWithExternalURL:(const GURL&)externalURL
+ xCallbackParameters:(XCallbackParameters*)xCallbackParameters {
+ NOTREACHED();
+ return nil;
+}
+
+- (instancetype)initWithExternalURL:(const GURL&)externalURL
+ xCallbackParameters:(XCallbackParameters*)xCallbackParameters
+ declaredSourceApp:(NSString*)declaredSourceApp
+ secureSourceApp:(NSString*)secureSourceApp
+ completeURL:(NSURL*)completeURL {
+ self = [super initWithExternalURL:externalURL
+ xCallbackParameters:xCallbackParameters];
+ if (self) {
+ _declaredSourceApp.reset([declaredSourceApp copy]);
+ _secureSourceApp.reset([secureSourceApp copy]);
+ _completeURL.reset([completeURL retain]);
+ }
+ return self;
+}
+
++ (instancetype)newChromeAppStartupParametersWithURL:(NSURL*)completeURL
+ fromSourceApplication:(NSString*)appId {
+ GURL gurl = net::GURLWithNSURL(completeURL);
+
+ if (!gurl.is_valid() || gurl.scheme().length() == 0)
+ return nil;
+
+ // TODO(ios): Temporary fix for b/7174478
+ if (IsXCallbackURL(gurl)) {
+ NSString* action = [completeURL path];
+ // Currently only "open" and "extension-command" are supported.
+ // Other actions are being considered (see b/6914153).
+ if ([action
+ isEqualToString:
+ [NSString
+ stringWithFormat:
+ @"/%s", app_group::kChromeAppGroupXCallbackCommand]]) {
+ UMA_HISTOGRAM_ENUMERATION(kUMAMobileSessionStartActionHistogram,
+ START_ACTION_XCALLBACK_APPGROUP_COMMAND,
+ MOBILE_SESSION_START_ACTION_COUNT);
+ return [ChromeAppStartupParameters
+ newExtensionCommandAppStartupParametersFromWithURL:completeURL
+ fromSourceApplication:appId];
+ }
+
+ if (![action isEqualToString:@"/open"]) {
+ UMA_HISTOGRAM_ENUMERATION(kUMAMobileSessionStartActionHistogram,
+ START_ACTION_XCALLBACK_OTHER,
+ MOBILE_SESSION_START_ACTION_COUNT);
+ return nil;
+ }
+
+ UMA_HISTOGRAM_ENUMERATION(kUMAMobileSessionStartActionHistogram,
+ START_ACTION_XCALLBACK_OPEN,
+ MOBILE_SESSION_START_ACTION_COUNT);
+
+ std::map<std::string, std::string> parameters =
+ ExtractQueryParametersFromXCallbackURL(gurl);
+ GURL url = GURL(parameters["url"]);
+ if (!url.is_valid() ||
+ (!url.SchemeIs(url::kHttpScheme) && !url.SchemeIs(url::kHttpsScheme))) {
+ return nil;
+ }
+
+ base::scoped_nsobject<XCallbackParameters> xcallbackParameters(
+ [[XCallbackParameters alloc] initWithSourceAppId:appId]);
+
+ return [[ChromeAppStartupParameters alloc]
+ initWithExternalURL:url
+ xCallbackParameters:xcallbackParameters
+ declaredSourceApp:appId
+ secureSourceApp:nil
+ completeURL:completeURL];
+
+ } else if (gurl.SchemeIsFile()) {
+ UMA_HISTOGRAM_ENUMERATION(kUMAMobileSessionStartActionHistogram,
+ START_ACTION_OPEN_FILE,
+ MOBILE_SESSION_START_ACTION_COUNT);
+ // |url| is the path to a file received from another application.
+ GURL::Replacements replacements;
+ const std::string host(kChromeUIExternalFileHost);
+ std::string filename = gurl.ExtractFileName();
+ replacements.SetPathStr(filename);
+ replacements.SetSchemeStr(kChromeUIScheme);
+ replacements.SetHostStr(host);
+ GURL externalURL = gurl.ReplaceComponents(replacements);
+ if (!externalURL.is_valid())
+ return nil;
+ return [[ChromeAppStartupParameters alloc] initWithExternalURL:externalURL
+ xCallbackParameters:nil
+ declaredSourceApp:appId
+ secureSourceApp:nil
+ completeURL:completeURL];
+ } else {
+ // Replace the scheme with https or http depending on whether the input
+ // |url| scheme ends with an 's'.
+ BOOL useHttps = gurl.scheme()[gurl.scheme().length() - 1] == 's';
+ MobileSessionStartAction action =
+ useHttps ? START_ACTION_OPEN_HTTPS : START_ACTION_OPEN_HTTP;
+ UMA_HISTOGRAM_ENUMERATION(kUMAMobileSessionStartActionHistogram, action,
+ MOBILE_SESSION_START_ACTION_COUNT);
+ GURL::Replacements replace_scheme;
+ if (useHttps)
+ replace_scheme.SetSchemeStr(url::kHttpsScheme);
+ else
+ replace_scheme.SetSchemeStr(url::kHttpScheme);
+ GURL externalURL = gurl.ReplaceComponents(replace_scheme);
+ if (!externalURL.is_valid())
+ return nil;
+ return [[ChromeAppStartupParameters alloc] initWithExternalURL:externalURL
+ xCallbackParameters:nil
+ declaredSourceApp:appId
+ secureSourceApp:nil
+ completeURL:completeURL];
+ }
+}
+
++ (instancetype)newExtensionCommandAppStartupParametersFromWithURL:(NSURL*)url
+ fromSourceApplication:
+ (NSString*)appId {
+ NSString* appGroup = app_group::ApplicationGroup();
+ base::scoped_nsobject<NSUserDefaults> sharedDefaults(
+ [[NSUserDefaults alloc] initWithSuiteName:appGroup]);
+
+ NSString* commandDictionaryPreference =
+ base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandPreference);
+ NSDictionary* commandDictionary = base::mac::ObjCCast<NSDictionary>(
+ [sharedDefaults objectForKey:commandDictionaryPreference]);
+
+ [sharedDefaults removeObjectForKey:commandDictionaryPreference];
+
+ // |sharedDefaults| is used for communication between apps. Synchronize to
+ // avoid synchronization issues (like removing the next order).
+ [sharedDefaults synchronize];
+
+ if (!commandDictionary) {
+ return nil;
+ }
+
+ NSString* commandCallerPreference =
+ base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandAppPreference);
+ NSString* commandCaller = base::mac::ObjCCast<NSString>(
+ [commandDictionary objectForKey:commandCallerPreference]);
+
+ NSString* commandPreference = base::SysUTF8ToNSString(
+ app_group::kChromeAppGroupCommandCommandPreference);
+ NSString* command = base::mac::ObjCCast<NSString>(
+ [commandDictionary objectForKey:commandPreference]);
+
+ NSString* commandTimePreference =
+ base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandTimePreference);
+ id commandTime = base::mac::ObjCCast<NSDate>(
+ [commandDictionary objectForKey:commandTimePreference]);
+
+ NSString* commandParameterPreference = base::SysUTF8ToNSString(
+ app_group::kChromeAppGroupCommandParameterPreference);
+ NSString* commandParameter = base::mac::ObjCCast<NSString>(
+ [commandDictionary objectForKey:commandParameterPreference]);
+
+ if (!commandCaller || !command || !commandTimePreference) {
+ return nil;
+ }
+
+ // Check the time of the last request to avoid app from intercepting old
+ // open url request and replay it later.
+ NSTimeInterval delay = [[NSDate date] timeIntervalSinceDate:commandTime];
+ UMA_HISTOGRAM_COUNTS_100(kApplicationGroupCommandDelay, delay);
+ if (delay > kAppGroupTriggersVoiceSearchTimeout)
+ return nil;
+ return [ChromeAppStartupParameters
+ newAppStartupParametersForCommand:command
+ withParameter:commandParameter
+ withURL:url
+ fromSourceApplication:appId
+ fromSecureSourceApplication:commandCaller];
+}
+
++ (instancetype)newAppStartupParametersForCommand:(NSString*)command
+ withParameter:(id)parameter
+ withURL:(NSURL*)url
+ fromSourceApplication:(NSString*)appId
+ fromSecureSourceApplication:(NSString*)secureSourceApp {
+ if ([command
+ isEqualToString:base::SysUTF8ToNSString(
+ app_group::kChromeAppGroupVoiceSearchCommand)]) {
+ ChromeAppStartupParameters* params = [[ChromeAppStartupParameters alloc]
+ initWithExternalURL:GURL(kChromeUINewTabURL)
+ xCallbackParameters:nil
+ declaredSourceApp:appId
+ secureSourceApp:secureSourceApp
+ completeURL:url];
+ [params setLaunchVoiceSearch:YES];
+ return params;
+ }
+
+ if ([command isEqualToString:base::SysUTF8ToNSString(
+ app_group::kChromeAppGroupNewTabCommand)]) {
+ return [[ChromeAppStartupParameters alloc]
+ initWithExternalURL:GURL(kChromeUINewTabURL)
+ xCallbackParameters:nil
+ declaredSourceApp:appId
+ secureSourceApp:secureSourceApp
+ completeURL:url];
+ }
+ if ([command isEqualToString:base::SysUTF8ToNSString(
+ app_group::kChromeAppGroupOpenURLCommand)]) {
+ if (!parameter || ![parameter isKindOfClass:[NSString class]])
+ return nil;
+ GURL externalURL(base::SysNSStringToUTF8(parameter));
+ if (!externalURL.is_valid() || !externalURL.SchemeIsHTTPOrHTTPS())
+ return nil;
+ return
+ [[ChromeAppStartupParameters alloc] initWithExternalURL:externalURL
+ xCallbackParameters:nil
+ declaredSourceApp:appId
+ secureSourceApp:secureSourceApp
+ completeURL:url];
+ }
+
+ return nil;
+}
+
+- (MobileSessionCallerApp)callerApp {
+ if ([_secureSourceApp isEqualToString:@"TodayExtension"])
+ return CALLER_APP_GOOGLE_CHROME_TODAY_EXTENSION;
+
+ if (![_declaredSourceApp length])
+ return CALLER_APP_NOT_AVAILABLE;
+ if ([_declaredSourceApp isEqualToString:@"com.google.GoogleMobile"])
+ return CALLER_APP_GOOGLE_SEARCH;
+ if ([_declaredSourceApp isEqualToString:@"com.google.Gmail"])
+ return CALLER_APP_GOOGLE_GMAIL;
+ if ([_declaredSourceApp isEqualToString:@"com.google.GooglePlus"])
+ return CALLER_APP_GOOGLE_PLUS;
+ if ([_declaredSourceApp isEqualToString:@"com.google.Drive"])
+ return CALLER_APP_GOOGLE_DRIVE;
+ if ([_declaredSourceApp isEqualToString:@"com.google.b612"])
+ return CALLER_APP_GOOGLE_EARTH;
+ if ([_declaredSourceApp isEqualToString:@"com.google.ios.youtube"])
+ return CALLER_APP_GOOGLE_YOUTUBE;
+ if ([_declaredSourceApp isEqualToString:@"com.google.Maps"])
+ return CALLER_APP_GOOGLE_MAPS;
+ if ([_declaredSourceApp hasPrefix:@"com.google."])
+ return CALLER_APP_GOOGLE_OTHER;
+ if ([_declaredSourceApp isEqualToString:@"com.apple.mobilesafari"])
+ return CALLER_APP_APPLE_MOBILESAFARI;
+ if ([_declaredSourceApp hasPrefix:@"com.apple."])
+ return CALLER_APP_APPLE_OTHER;
+
+ return CALLER_APP_OTHER;
+}
+
+- (first_run::ExternalLaunch)launchSource {
+ if ([self callerApp] != CALLER_APP_APPLE_MOBILESAFARI) {
+ return first_run::LAUNCH_BY_OTHERS;
+ }
+
+ NSString* query = [_completeURL query];
+ // Takes care of degenerated case of no QUERY_STRING.
+ if (![query length])
+ return first_run::LAUNCH_BY_MOBILESAFARI;
+ // Look for |kSmartAppBannerKey| anywhere within the query string.
+ NSRange found = [query rangeOfString:kSmartAppBannerKey];
+ if (found.location == NSNotFound)
+ return first_run::LAUNCH_BY_MOBILESAFARI;
+ // |kSmartAppBannerKey| can be at the beginning or end of the query
+ // string and may also be optionally followed by a equal sign and a value.
+ // For now, just look for the presence of the key and ignore the value.
+ if (found.location + found.length < [query length]) {
+ // There are characters following the found location.
+ unichar charAfter =
+ [query characterAtIndex:(found.location + found.length)];
+ if (charAfter != '&' && charAfter != '=')
+ return first_run::LAUNCH_BY_MOBILESAFARI;
+ }
+ if (found.location > 0) {
+ unichar charBefore = [query characterAtIndex:(found.location - 1)];
+ if (charBefore != '&')
+ return first_run::LAUNCH_BY_MOBILESAFARI;
+ }
+ return first_run::LAUNCH_BY_SMARTAPPBANNER;
+}
+
+@end
« 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