Index: ios/chrome/browser/web/mailto_url_rewriter.mm |
diff --git a/ios/chrome/browser/web/mailto_url_rewriter.mm b/ios/chrome/browser/web/mailto_url_rewriter.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f6c00c5cff1bcac1421298cf6d8a5f574e003e73 |
--- /dev/null |
+++ b/ios/chrome/browser/web/mailto_url_rewriter.mm |
@@ -0,0 +1,206 @@ |
+// Copyright 2017 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/browser/web/mailto_url_rewriter.h" |
+ |
+#import "base/logging.h" |
+#import "ios/chrome/browser/web/mailto_handler.h" |
+#import "ios/chrome/browser/web/mailto_handler_gmail.h" |
+#import "ios/chrome/browser/web/mailto_handler_system_mail.h" |
+ |
+#import <UIKit/UIKit.h> |
+ |
+#if !defined(__has_feature) || !__has_feature(objc_arc) |
+#error "This file requires ARC support." |
+#endif |
+ |
+namespace { |
+// The key for NSUserDefaults to store the Mail client selected to handle |
+// mailto: URL scheme. If this key is not set, user has not made an explicit |
+// choice for default mailto: handler and system-provided Mail client app will |
+// be used. |
+NSString* const kMailtoDefaultHandlerKey = @"MailtoHandlerDefault"; |
+} // namespace |
+ |
+@interface MailtoURLRewriter () |
+ |
+// Dictionary keyed by the App Store ID of the Mail client and the value is |
+// the MailtoHandler object that can rewrite a mailto: URL. |
+@property(nonatomic, strong) |
+ NSMutableDictionary<NSString*, MailtoHandler*>* handlers; |
+ |
+// Private method for testing to clear the default state. |
++ (void)resetDefaultHandlerIDForTesting; |
+ |
+// Private method to add one or more |handlerApp| objects to the list of known |
+// Mail client apps. |
+- (void)addMailtoApps:(NSArray<MailtoHandler*>*)handlerApps; |
+ |
+// Custom logic to handle the migration from Google Native App Launcher options |
+// to this simplified mailto: URL only system. This must be called after |
+// -addMailtoApp: has been called to add all the known Mail client apps. |
+// TODO(crbug.com/718601): At some point in the future when almost all users |
+// have upgraded, this method can be removed. |
+- (void)migrateLegacyOptions; |
+ |
+// For users who have not made an explicit choice (kMailtoDefaultHandlerKey |
+// not set), if Gmail is detected, make an explicit choice for the user to |
+// use Gmail app as the default mailto: handler. |
+- (void)autoDefaultToGmailIfInstalled; |
+ |
+@end |
+ |
+@implementation MailtoURLRewriter |
+@synthesize handlers = _handlers; |
+ |
++ (NSString*)systemMailApp { |
+ // This is the App Store ID for Apple Mail app. |
+ // See https://itunes.apple.com/us/app/mail/id1108187098?mt=8 |
+ return @"1108187098"; |
+} |
+ |
+- (instancetype)init { |
+ self = [super init]; |
+ if (self) { |
+ _handlers = [NSMutableDictionary dictionary]; |
+ } |
+ return self; |
+} |
+ |
+- (instancetype)initWithStandardHandlers { |
+ self = [self init]; |
+ if (self) { |
+ [self addMailtoApps:@[ |
+ [[MailtoHandlerSystemMail alloc] init], [[MailtoHandlerGmail alloc] init] |
+ ]]; |
+ } |
+ return self; |
+} |
+ |
+- (NSArray<MailtoHandler*>*)defaultHandlers { |
+ return [_handlers allValues]; |
+} |
+ |
+- (NSString*)defaultHandlerID { |
+ NSString* value = [[NSUserDefaults standardUserDefaults] |
+ stringForKey:kMailtoDefaultHandlerKey]; |
+ return value ? value : [[self class] systemMailApp]; |
+} |
+ |
+- (void)setDefaultHandlerID:(NSString*)appStoreID { |
+ DCHECK([appStoreID length]); |
+ [[NSUserDefaults standardUserDefaults] setObject:appStoreID |
+ forKey:kMailtoDefaultHandlerKey]; |
+} |
+ |
+- (NSString*)rewriteMailtoURL:(const GURL&)gURL { |
+ NSString* value = [self defaultHandlerID]; |
+ if ([value length]) { |
+ MailtoHandler* handler = _handlers[value]; |
+ if (handler) { |
+ return [handler rewriteMailtoURL:gURL]; |
+ } |
+ } |
+ return nil; |
+} |
+ |
+#pragma mark - Private |
+ |
++ (void)resetDefaultHandlerIDForTesting { |
+ [[NSUserDefaults standardUserDefaults] |
+ removeObjectForKey:kMailtoDefaultHandlerKey]; |
+} |
+ |
+- (void)addMailtoApps:(NSArray<MailtoHandler*>*)handlerApps { |
+ for (MailtoHandler* app in handlerApps) { |
+ if ([app isAvailable]) |
+ [_handlers setObject:app forKey:[app appStoreID]]; |
+ } |
+ [self migrateLegacyOptions]; |
+ [self autoDefaultToGmailIfInstalled]; |
+} |
+ |
+// |
+// Implements the migration logic for users of previous versions of Google |
+// Chrome which supports Google Native App Launcher. The goal is to preserve |
+// the previous behavior and support user choice of non-system provided Mail |
+// client apps. System-provided Mail client app will be referred to as |
+// "System Mail". The migration goals are: |
+// - If a user has not made a choice for preferred mailto: handler in the past, |
+// the behavior after upgrading to this version should not change. |
+// - If a user had disabled Gmail app as the preferred mailto: handler in the |
+// past, System Mail should be selected as the default mailto: handler. |
+// - If a user installs Gmail app after the installation of Chrome, Gmail app |
+// will be chosen as the default mailto: handler, preserving the previous |
+// behavior. |
+// - If a user installs another 3rd party mail client app, assuming that the |
+// 3rd party mail client app is explicitly supported in Chrome, the new 3rd |
+// party mail client app can be set as the default mailto: handler through |
+// Tools > Settings > Content Settings. |
+// |
+// Two NSUserDefaults keys are interpreted with the following meanings: |
+// - kLegacyShouldAutoOpenKey: The existence of this key implies that the user |
+// has used Chrome in the past and had Gmail app installed. Gmail app may or |
+// may not be installed currently. |
+// - kMailtoDefaultHandlerKey: If this key is not set, System Mail app is used |
+// to handle mailto: URLs. If this key is set, the value is a string that is |
+// the key to |_handlers| which maps to a MailtoHandler object. |
+// |
+- (void)migrateLegacyOptions { |
+ NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; |
+ |
+ // User previously had a selection made for opening mailto: links with Gmail, |
+ // upgrade will set Gmail app to be the default mailto: handler. If user had |
+ // opted out to using Gmail app (even when it was installed), migrate user |
+ // to use system-provided Mail client. |
+ // The key used in NSUserDefaults is from legacy code when Native App |
+ // Launcher was still in use. The general format is a string prefix, |
+ // underscore, then followed by the App Store ID of the application. |
+ NSString* const kGmailAppStoreID = @"422689480"; |
+ NSString* const kLegacyShouldAutoOpenKey = |
+ [NSString stringWithFormat:@"ShouldAutoOpenLinks_%@", kGmailAppStoreID]; |
+ NSNumber* legacyValue = [defaults objectForKey:kLegacyShouldAutoOpenKey]; |
+ if (legacyValue) { |
+ switch ([legacyValue intValue]) { |
+ case 0: |
+ case 2: { |
+ // If legacy user was using default (kAutoOpenLinksNotSet) or had |
+ // explicitly chosen to use Gmail (kAutoOpenLinksYes), migrate to use |
+ // Gmail app. |
+ MailtoHandler* gmailHandler = _handlers[kGmailAppStoreID]; |
+ if ([gmailHandler isAvailable]) |
+ [defaults setObject:kGmailAppStoreID forKey:kMailtoDefaultHandlerKey]; |
+ else |
+ [defaults removeObjectForKey:kMailtoDefaultHandlerKey]; |
+ break; |
+ } |
+ case 1: |
+ // If legacy user was not using Gmail to handle mailto: links |
+ // (kAutoOpenLinksNo), consider this an explicit user choice and |
+ // migrate to use system-provided Mail app. |
+ [defaults setObject:[[self class] systemMailApp] |
+ forKey:kMailtoDefaultHandlerKey]; |
+ break; |
+ default: |
+ NOTREACHED(); |
+ break; |
+ } |
+ [defaults removeObjectForKey:kLegacyShouldAutoOpenKey]; |
+ } |
+} |
+ |
+- (void)autoDefaultToGmailIfInstalled { |
+ NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; |
+ // If a default handler for mailto: has already been set, user had made an |
+ // explicit choice and no further changes should be done. |
+ if ([defaults objectForKey:kMailtoDefaultHandlerKey]) |
+ return; |
+ |
+ NSString* const kGmailAppStoreID = @"422689480"; |
+ MailtoHandler* gmailHandler = _handlers[kGmailAppStoreID]; |
+ if ([gmailHandler isAvailable]) |
+ [defaults setObject:kGmailAppStoreID forKey:kMailtoDefaultHandlerKey]; |
+} |
+ |
+@end |