Chromium Code Reviews| 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..ad737e091043d7a8d7e893220ac3b2e926011fa8 |
| --- /dev/null |
| +++ b/ios/chrome/browser/web/mailto_url_rewriter.mm |
| @@ -0,0 +1,198 @@ |
| +// 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)resetDefaultHandlerID; |
| + |
| +// 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; |
| + |
| +@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)resetDefaultHandlerID { |
|
rohitrao (ping after 24h)
2017/05/10 00:09:18
What code will call this function and reset the ha
pkl (ping after 24h if needed)
2017/05/10 01:04:14
No. This is only used by unit tests. I renamed it
|
| + [[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]; |
| +} |
| + |
| +// |
| +// 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), migrate to use system-provided Mail app. |
| + [defaults removeObjectForKey:kMailtoDefaultHandlerKey]; |
| + break; |
| + default: |
| + NOTREACHED(); |
| + break; |
| + } |
| + [defaults removeObjectForKey:kLegacyShouldAutoOpenKey]; |
| + return; |
| + } |
| + |
| + // If a default handler for mailto: has already been registered, this means |
|
rohitrao (ping after 24h)
2017/05/10 00:09:18
The rest of this function after this line isn't re
pkl (ping after 24h if needed)
2017/05/10 01:04:14
Done.
|
| + // that user had made a choice and no further migration should be done. |
| + if ([defaults objectForKey:kMailtoDefaultHandlerKey]) |
| + return; |
| + |
| + // For users who have not made an explict choice (kMailtoDefaultHandlerKey |
|
rohitrao (ping after 24h)
2017/05/09 23:52:20
Typo: explicit.
rohitrao (ping after 24h)
2017/05/09 23:52:21
The absence of kMailtoDefaultHandlerKey could happ
pkl (ping after 24h if needed)
2017/05/10 00:02:19
From Settings UI, user can set Mail app as the han
pkl (ping after 24h if needed)
2017/05/10 00:02:19
Yes, will fix that.
|
| + // not set), if Gmail is detected, make an explicit choice for the user to |
|
rohitrao (ping after 24h)
2017/05/09 23:52:20
If I choose to use system mail, then later install
pkl (ping after 24h if needed)
2017/05/10 00:02:19
If user has made a choice, this migration code wil
|
| + // use Gmail app as the default mailto: handler. |
| + MailtoHandler* gmailHandler = _handlers[kGmailAppStoreID]; |
| + if ([gmailHandler isAvailable]) |
| + [defaults setObject:kGmailAppStoreID forKey:kMailtoDefaultHandlerKey]; |
| +} |
| + |
| +@end |