OLD | NEW |
(Empty) | |
| 1 // Copyright 2013 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/browser/ui/promos/signin_promo_view_controller.h" |
| 6 |
| 7 #include "base/mac/scoped_nsobject.h" |
| 8 #include "base/metrics/histogram.h" |
| 9 #include "base/metrics/user_metrics.h" |
| 10 #include "base/strings/sys_string_conversions.h" |
| 11 #include "base/version.h" |
| 12 #include "components/signin/core/browser/signin_metrics.h" |
| 13 #include "components/version_info/version_info.h" |
| 14 #include "ios/chrome/app/tests_hook.h" |
| 15 #import "ios/chrome/browser/browser_state/chrome_browser_state.h" |
| 16 #include "ios/chrome/browser/signin/authentication_service.h" |
| 17 #include "ios/chrome/browser/signin/authentication_service_factory.h" |
| 18 #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h" |
| 19 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h" |
| 20 #import "ios/public/provider/chrome/browser/signin/chrome_identity_service.h" |
| 21 #include "net/base/network_change_notifier.h" |
| 22 |
| 23 // Key in the UserDefaults to record the version of the application when the |
| 24 // SSO Recall promo has been displayed. |
| 25 NSString* kDisplayedSSORecallForMajorVersionKey = |
| 26 @"DisplayedSSORecallForMajorVersionKey"; |
| 27 |
| 28 namespace { |
| 29 |
| 30 // Key in the UserDefaults to track how many times the SSO Recall promo has been |
| 31 // displayed. |
| 32 NSString* kDisplayedSSORecallPromoCountKey = @"DisplayedSSORecallPromoCount"; |
| 33 |
| 34 // Name of the UMA SSO Recall histogram. |
| 35 const char* const kUMASSORecallPromoAction = "SSORecallPromo.PromoAction"; |
| 36 |
| 37 // Name of the histogram recording how many accounts were avilable on the device |
| 38 // when the promo was shown. |
| 39 const char* const kUMASSORecallAccountsAvailable = |
| 40 "SSORecallPromo.AccountsAvailable"; |
| 41 |
| 42 // Name of the histogram recording how many times the promo has been shown. |
| 43 const char* const kUMASSORecallPromoSeenCount = "SSORecallPromo.PromoSeenCount"; |
| 44 |
| 45 // Values of the UMA SSORecallPromo.PromoAction histogram. |
| 46 enum PromoAction { |
| 47 ACTION_DISMISSED, |
| 48 ACTION_ENABLED_SSO_ACCOUNT, |
| 49 ACTION_ADDED_ANOTHER_ACCOUNT, |
| 50 PROMO_ACTION_COUNT |
| 51 }; |
| 52 |
| 53 } // namespace |
| 54 |
| 55 @interface SigninPromoViewController ()<ChromeSigninViewControllerDelegate> |
| 56 @end |
| 57 |
| 58 @implementation SigninPromoViewController { |
| 59 BOOL _addAccountOperation; |
| 60 } |
| 61 |
| 62 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState { |
| 63 self = [super initWithBrowserState:browserState |
| 64 isPresentedOnSettings:NO |
| 65 signInAccessPoint:signin_metrics::AccessPoint:: |
| 66 ACCESS_POINT_SIGNIN_PROMO |
| 67 signInIdentity:nil]; |
| 68 if (self) { |
| 69 super.delegate = self; |
| 70 } |
| 71 return self; |
| 72 } |
| 73 |
| 74 - (void)viewDidAppear:(BOOL)animated { |
| 75 [super viewDidAppear:animated]; |
| 76 |
| 77 if ([self isBeingPresented] || [self isMovingToParentViewController]) { |
| 78 base::RecordAction( |
| 79 base::UserMetricsAction("Signin_Signin_FromSigninPromo")); |
| 80 signin_metrics::LogSigninAccessPointStarted( |
| 81 signin_metrics::AccessPoint::ACCESS_POINT_SIGNIN_PROMO); |
| 82 } |
| 83 |
| 84 [self recordPromoDisplayed]; |
| 85 } |
| 86 |
| 87 - (void)dismissWithSignedIn:(BOOL)signedIn |
| 88 executeCommand:(GenericChromeCommand*)command { |
| 89 DCHECK(self.presentingViewController); |
| 90 UIViewController* presentingViewController = self.presentingViewController; |
| 91 [presentingViewController |
| 92 dismissViewControllerAnimated:YES |
| 93 completion:^{ |
| 94 if (command) { |
| 95 [presentingViewController |
| 96 chromeExecuteCommand:command]; |
| 97 } |
| 98 }]; |
| 99 } |
| 100 |
| 101 // Records in user defaults that the promo has been shown as well as the number |
| 102 // of times it's been displayed. |
| 103 - (void)recordPromoDisplayed { |
| 104 [[self class] recordVersionSeen]; |
| 105 NSUserDefaults* standardDefaults = [NSUserDefaults standardUserDefaults]; |
| 106 int promoSeenCount = |
| 107 [standardDefaults integerForKey:kDisplayedSSORecallPromoCountKey]; |
| 108 promoSeenCount++; |
| 109 [standardDefaults setInteger:promoSeenCount |
| 110 forKey:kDisplayedSSORecallPromoCountKey]; |
| 111 |
| 112 NSArray* identities = ios::GetChromeBrowserProvider() |
| 113 ->GetChromeIdentityService() |
| 114 ->GetAllIdentitiesSortedForDisplay(); |
| 115 UMA_HISTOGRAM_COUNTS_100(kUMASSORecallAccountsAvailable, [identities count]); |
| 116 UMA_HISTOGRAM_COUNTS_100(kUMASSORecallPromoSeenCount, promoSeenCount); |
| 117 } |
| 118 |
| 119 // Called to obtain the current version of the application to compare against |
| 120 // the version the last time the promo was seen. |
| 121 // Separated out into a discrete function to allow overriding when testing. |
| 122 + (void)recordVersionSeen { |
| 123 base::Version currentVersion = [self currentVersion]; |
| 124 NSUserDefaults* standardDefaults = [NSUserDefaults standardUserDefaults]; |
| 125 [standardDefaults |
| 126 setObject:base::SysUTF8ToNSString(currentVersion.GetString()) |
| 127 forKey:kDisplayedSSORecallForMajorVersionKey]; |
| 128 } |
| 129 |
| 130 + (base::Version)currentVersion { |
| 131 base::Version currentVersion(version_info::GetVersionNumber()); |
| 132 DCHECK(currentVersion.IsValid()); |
| 133 return currentVersion; |
| 134 } |
| 135 |
| 136 #pragma mark - PromoViewController |
| 137 |
| 138 + (BOOL)shouldBePresentedForBrowserState: |
| 139 (ios::ChromeBrowserState*)browserState { |
| 140 if (tests_hook::DisableSigninRecallPromo()) |
| 141 return NO; |
| 142 |
| 143 if (browserState->IsOffTheRecord()) |
| 144 return NO; |
| 145 |
| 146 // There will be an error shown if the user chooses to sign in or select |
| 147 // another account while offline. |
| 148 if (net::NetworkChangeNotifier::IsOffline()) |
| 149 return NO; |
| 150 |
| 151 AuthenticationService* authService = |
| 152 AuthenticationServiceFactory::GetForBrowserState(browserState); |
| 153 // Do not show the SSO promo if the user is already logged in. |
| 154 if (authService->GetAuthenticatedUserEmail()) |
| 155 return NO; |
| 156 |
| 157 // Show the promo at most every two major versions. |
| 158 NSUserDefaults* standardDefaults = [NSUserDefaults standardUserDefaults]; |
| 159 NSString* versionShown = |
| 160 [standardDefaults stringForKey:kDisplayedSSORecallForMajorVersionKey]; |
| 161 if (versionShown) { |
| 162 base::Version seenVersion(base::SysNSStringToUTF8(versionShown)); |
| 163 base::Version currentVersion = [[self class] currentVersion]; |
| 164 if (currentVersion.components()[0] - seenVersion.components()[0] < 2) |
| 165 return NO; |
| 166 } |
| 167 |
| 168 NSArray* identities = ios::GetChromeBrowserProvider() |
| 169 ->GetChromeIdentityService() |
| 170 ->GetAllIdentitiesSortedForDisplay(); |
| 171 return [identities count] > 0; |
| 172 } |
| 173 |
| 174 + (UIViewController*)controllerToPresentForBrowserState: |
| 175 (ios::ChromeBrowserState*)browserState { |
| 176 base::scoped_nsobject<UIViewController> controller( |
| 177 [[SigninPromoViewController alloc] initWithBrowserState:browserState]); |
| 178 return controller.autorelease(); |
| 179 } |
| 180 |
| 181 #pragma mark - ChromeSigninViewControllerDelegate |
| 182 |
| 183 - (void)willStartSignIn:(ChromeSigninViewController*)controller { |
| 184 DCHECK_EQ(self, controller); |
| 185 _addAccountOperation = NO; |
| 186 } |
| 187 |
| 188 - (void)willStartAddAccount:(ChromeSigninViewController*)controller { |
| 189 DCHECK_EQ(self, controller); |
| 190 _addAccountOperation = YES; |
| 191 } |
| 192 |
| 193 - (void)didSkipSignIn:(ChromeSigninViewController*)controller { |
| 194 DCHECK_EQ(self, controller); |
| 195 UMA_HISTOGRAM_ENUMERATION(kUMASSORecallPromoAction, ACTION_DISMISSED, |
| 196 PROMO_ACTION_COUNT); |
| 197 [self dismissWithSignedIn:NO executeCommand:nil]; |
| 198 } |
| 199 |
| 200 - (void)didFailSignIn:(ChromeSigninViewController*)controller { |
| 201 DCHECK_EQ(self, controller); |
| 202 [self dismissWithSignedIn:NO executeCommand:nil]; |
| 203 } |
| 204 |
| 205 - (void)didSignIn:(ChromeSigninViewController*)controller { |
| 206 DCHECK_EQ(self, controller); |
| 207 } |
| 208 |
| 209 - (void)didUndoSignIn:(ChromeSigninViewController*)controller |
| 210 identity:(ChromeIdentity*)identity { |
| 211 DCHECK_EQ(self, controller); |
| 212 // No accounts case is impossible in SigninPromoViewController, nothing to do. |
| 213 } |
| 214 |
| 215 - (void)didAcceptSignIn:(ChromeSigninViewController*)controller |
| 216 executeCommand:(GenericChromeCommand*)command { |
| 217 DCHECK_EQ(self, controller); |
| 218 PromoAction promoAction = _addAccountOperation ? ACTION_ADDED_ANOTHER_ACCOUNT |
| 219 : ACTION_ENABLED_SSO_ACCOUNT; |
| 220 UMA_HISTOGRAM_ENUMERATION(kUMASSORecallPromoAction, promoAction, |
| 221 PROMO_ACTION_COUNT); |
| 222 |
| 223 [self dismissWithSignedIn:YES executeCommand:command]; |
| 224 } |
| 225 |
| 226 @end |
OLD | NEW |