Index: ios/chrome/browser/ui/promos/signin_promo_view_controller.mm |
diff --git a/ios/chrome/browser/ui/promos/signin_promo_view_controller.mm b/ios/chrome/browser/ui/promos/signin_promo_view_controller.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..a9c154ceb534a086a5af5c44bb17013adc21ea67 |
--- /dev/null |
+++ b/ios/chrome/browser/ui/promos/signin_promo_view_controller.mm |
@@ -0,0 +1,226 @@ |
+// Copyright 2013 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/ui/promos/signin_promo_view_controller.h" |
+ |
+#include "base/mac/scoped_nsobject.h" |
+#include "base/metrics/histogram.h" |
+#include "base/metrics/user_metrics.h" |
+#include "base/strings/sys_string_conversions.h" |
+#include "base/version.h" |
+#include "components/signin/core/browser/signin_metrics.h" |
+#include "components/version_info/version_info.h" |
+#include "ios/chrome/app/tests_hook.h" |
+#import "ios/chrome/browser/browser_state/chrome_browser_state.h" |
+#include "ios/chrome/browser/signin/authentication_service.h" |
+#include "ios/chrome/browser/signin/authentication_service_factory.h" |
+#import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h" |
+#include "ios/public/provider/chrome/browser/chrome_browser_provider.h" |
+#import "ios/public/provider/chrome/browser/signin/chrome_identity_service.h" |
+#include "net/base/network_change_notifier.h" |
+ |
+// Key in the UserDefaults to record the version of the application when the |
+// SSO Recall promo has been displayed. |
+NSString* kDisplayedSSORecallForMajorVersionKey = |
+ @"DisplayedSSORecallForMajorVersionKey"; |
+ |
+namespace { |
+ |
+// Key in the UserDefaults to track how many times the SSO Recall promo has been |
+// displayed. |
+NSString* kDisplayedSSORecallPromoCountKey = @"DisplayedSSORecallPromoCount"; |
+ |
+// Name of the UMA SSO Recall histogram. |
+const char* const kUMASSORecallPromoAction = "SSORecallPromo.PromoAction"; |
+ |
+// Name of the histogram recording how many accounts were avilable on the device |
+// when the promo was shown. |
+const char* const kUMASSORecallAccountsAvailable = |
+ "SSORecallPromo.AccountsAvailable"; |
+ |
+// Name of the histogram recording how many times the promo has been shown. |
+const char* const kUMASSORecallPromoSeenCount = "SSORecallPromo.PromoSeenCount"; |
+ |
+// Values of the UMA SSORecallPromo.PromoAction histogram. |
+enum PromoAction { |
+ ACTION_DISMISSED, |
+ ACTION_ENABLED_SSO_ACCOUNT, |
+ ACTION_ADDED_ANOTHER_ACCOUNT, |
+ PROMO_ACTION_COUNT |
+}; |
+ |
+} // namespace |
+ |
+@interface SigninPromoViewController ()<ChromeSigninViewControllerDelegate> |
+@end |
+ |
+@implementation SigninPromoViewController { |
+ BOOL _addAccountOperation; |
+} |
+ |
+- (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState { |
+ self = [super initWithBrowserState:browserState |
+ isPresentedOnSettings:NO |
+ signInAccessPoint:signin_metrics::AccessPoint:: |
+ ACCESS_POINT_SIGNIN_PROMO |
+ signInIdentity:nil]; |
+ if (self) { |
+ super.delegate = self; |
+ } |
+ return self; |
+} |
+ |
+- (void)viewDidAppear:(BOOL)animated { |
+ [super viewDidAppear:animated]; |
+ |
+ if ([self isBeingPresented] || [self isMovingToParentViewController]) { |
+ base::RecordAction( |
+ base::UserMetricsAction("Signin_Signin_FromSigninPromo")); |
+ signin_metrics::LogSigninAccessPointStarted( |
+ signin_metrics::AccessPoint::ACCESS_POINT_SIGNIN_PROMO); |
+ } |
+ |
+ [self recordPromoDisplayed]; |
+} |
+ |
+- (void)dismissWithSignedIn:(BOOL)signedIn |
+ executeCommand:(GenericChromeCommand*)command { |
+ DCHECK(self.presentingViewController); |
+ UIViewController* presentingViewController = self.presentingViewController; |
+ [presentingViewController |
+ dismissViewControllerAnimated:YES |
+ completion:^{ |
+ if (command) { |
+ [presentingViewController |
+ chromeExecuteCommand:command]; |
+ } |
+ }]; |
+} |
+ |
+// Records in user defaults that the promo has been shown as well as the number |
+// of times it's been displayed. |
+- (void)recordPromoDisplayed { |
+ [[self class] recordVersionSeen]; |
+ NSUserDefaults* standardDefaults = [NSUserDefaults standardUserDefaults]; |
+ int promoSeenCount = |
+ [standardDefaults integerForKey:kDisplayedSSORecallPromoCountKey]; |
+ promoSeenCount++; |
+ [standardDefaults setInteger:promoSeenCount |
+ forKey:kDisplayedSSORecallPromoCountKey]; |
+ |
+ NSArray* identities = ios::GetChromeBrowserProvider() |
+ ->GetChromeIdentityService() |
+ ->GetAllIdentitiesSortedForDisplay(); |
+ UMA_HISTOGRAM_COUNTS_100(kUMASSORecallAccountsAvailable, [identities count]); |
+ UMA_HISTOGRAM_COUNTS_100(kUMASSORecallPromoSeenCount, promoSeenCount); |
+} |
+ |
+// Called to obtain the current version of the application to compare against |
+// the version the last time the promo was seen. |
+// Separated out into a discrete function to allow overriding when testing. |
++ (void)recordVersionSeen { |
+ base::Version currentVersion = [self currentVersion]; |
+ NSUserDefaults* standardDefaults = [NSUserDefaults standardUserDefaults]; |
+ [standardDefaults |
+ setObject:base::SysUTF8ToNSString(currentVersion.GetString()) |
+ forKey:kDisplayedSSORecallForMajorVersionKey]; |
+} |
+ |
++ (base::Version)currentVersion { |
+ base::Version currentVersion(version_info::GetVersionNumber()); |
+ DCHECK(currentVersion.IsValid()); |
+ return currentVersion; |
+} |
+ |
+#pragma mark - PromoViewController |
+ |
++ (BOOL)shouldBePresentedForBrowserState: |
+ (ios::ChromeBrowserState*)browserState { |
+ if (tests_hook::DisableSigninRecallPromo()) |
+ return NO; |
+ |
+ if (browserState->IsOffTheRecord()) |
+ return NO; |
+ |
+ // There will be an error shown if the user chooses to sign in or select |
+ // another account while offline. |
+ if (net::NetworkChangeNotifier::IsOffline()) |
+ return NO; |
+ |
+ AuthenticationService* authService = |
+ AuthenticationServiceFactory::GetForBrowserState(browserState); |
+ // Do not show the SSO promo if the user is already logged in. |
+ if (authService->GetAuthenticatedUserEmail()) |
+ return NO; |
+ |
+ // Show the promo at most every two major versions. |
+ NSUserDefaults* standardDefaults = [NSUserDefaults standardUserDefaults]; |
+ NSString* versionShown = |
+ [standardDefaults stringForKey:kDisplayedSSORecallForMajorVersionKey]; |
+ if (versionShown) { |
+ base::Version seenVersion(base::SysNSStringToUTF8(versionShown)); |
+ base::Version currentVersion = [[self class] currentVersion]; |
+ if (currentVersion.components()[0] - seenVersion.components()[0] < 2) |
+ return NO; |
+ } |
+ |
+ NSArray* identities = ios::GetChromeBrowserProvider() |
+ ->GetChromeIdentityService() |
+ ->GetAllIdentitiesSortedForDisplay(); |
+ return [identities count] > 0; |
+} |
+ |
++ (UIViewController*)controllerToPresentForBrowserState: |
+ (ios::ChromeBrowserState*)browserState { |
+ base::scoped_nsobject<UIViewController> controller( |
+ [[SigninPromoViewController alloc] initWithBrowserState:browserState]); |
+ return controller.autorelease(); |
+} |
+ |
+#pragma mark - ChromeSigninViewControllerDelegate |
+ |
+- (void)willStartSignIn:(ChromeSigninViewController*)controller { |
+ DCHECK_EQ(self, controller); |
+ _addAccountOperation = NO; |
+} |
+ |
+- (void)willStartAddAccount:(ChromeSigninViewController*)controller { |
+ DCHECK_EQ(self, controller); |
+ _addAccountOperation = YES; |
+} |
+ |
+- (void)didSkipSignIn:(ChromeSigninViewController*)controller { |
+ DCHECK_EQ(self, controller); |
+ UMA_HISTOGRAM_ENUMERATION(kUMASSORecallPromoAction, ACTION_DISMISSED, |
+ PROMO_ACTION_COUNT); |
+ [self dismissWithSignedIn:NO executeCommand:nil]; |
+} |
+ |
+- (void)didFailSignIn:(ChromeSigninViewController*)controller { |
+ DCHECK_EQ(self, controller); |
+ [self dismissWithSignedIn:NO executeCommand:nil]; |
+} |
+ |
+- (void)didSignIn:(ChromeSigninViewController*)controller { |
+ DCHECK_EQ(self, controller); |
+} |
+ |
+- (void)didUndoSignIn:(ChromeSigninViewController*)controller |
+ identity:(ChromeIdentity*)identity { |
+ DCHECK_EQ(self, controller); |
+ // No accounts case is impossible in SigninPromoViewController, nothing to do. |
+} |
+ |
+- (void)didAcceptSignIn:(ChromeSigninViewController*)controller |
+ executeCommand:(GenericChromeCommand*)command { |
+ DCHECK_EQ(self, controller); |
+ PromoAction promoAction = _addAccountOperation ? ACTION_ADDED_ANOTHER_ACCOUNT |
+ : ACTION_ENABLED_SSO_ACCOUNT; |
+ UMA_HISTOGRAM_ENUMERATION(kUMASSORecallPromoAction, promoAction, |
+ PROMO_ACTION_COUNT); |
+ |
+ [self dismissWithSignedIn:YES executeCommand:command]; |
+} |
+ |
+@end |